mirror of
https://github.com/microsoft/DirectXTex
synced 2024-11-08 14:00:05 +00:00
Add Auxiliary files for JPEG/PNG support on Linux (#407)
This commit is contained in:
parent
eb172c521a
commit
fae11ce578
421
Auxiliary/DirectXTexJPEG.cpp
Normal file
421
Auxiliary/DirectXTexJPEG.cpp
Normal file
@ -0,0 +1,421 @@
|
||||
//--------------------------------------------------------------------------------------
|
||||
// File: DirectXTexJPEG.cpp
|
||||
//
|
||||
// DirectXTex Auxilary functions for using the JPEG(https://www.ijg.org) library
|
||||
//
|
||||
// For the Windows platform, the strong recommendation is to make use of the WIC
|
||||
// functions rather than using the open source library. This module exists to support
|
||||
// Windows Subsystem on Linux.
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
#include "DirectXTexP.h"
|
||||
#include "DirectXTexJPEG.h"
|
||||
|
||||
#if __cplusplus < 201703L
|
||||
#error Requires C++17 (and /Zc:__cplusplus with MSVC)
|
||||
#endif
|
||||
|
||||
#ifndef _BASETSD_H_
|
||||
#define _BASETSD_H_
|
||||
#endif
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <exception>
|
||||
#include <filesystem>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
#include <vector>
|
||||
|
||||
#include <jpeglib.h>
|
||||
#include <jerror.h>
|
||||
|
||||
|
||||
using namespace DirectX;
|
||||
using std::filesystem::path;
|
||||
using ScopedFILE = std::unique_ptr<FILE, int(*)(FILE*)>;
|
||||
|
||||
namespace
|
||||
{
|
||||
#ifdef _WIN32
|
||||
ScopedFILE OpenFILE(const path& p) noexcept(false)
|
||||
{
|
||||
const std::wstring fpath = p.generic_wstring();
|
||||
FILE* fp = nullptr;
|
||||
if (auto ec = _wfopen_s(&fp, fpath.c_str(), L"rb"); ec)
|
||||
throw std::system_error{ static_cast<int>(_doserrno), std::system_category(), "_wfopen_s" };
|
||||
return { fp, &fclose };
|
||||
}
|
||||
ScopedFILE CreateFILE(const path& p) noexcept(false)
|
||||
{
|
||||
const std::wstring fpath = p.generic_wstring();
|
||||
FILE* fp = nullptr;
|
||||
if (auto ec = _wfopen_s(&fp, fpath.c_str(), L"w+b"); ec)
|
||||
throw std::system_error{ static_cast<int>(_doserrno), std::system_category(), "_wfopen_s" };
|
||||
return { fp, &fclose };
|
||||
}
|
||||
#else
|
||||
ScopedFILE OpenFILE(const path& p) noexcept(false)
|
||||
{
|
||||
const std::string fpath = p.generic_string();
|
||||
FILE* fp = fopen(fpath.c_str(), "rb");
|
||||
if (!fp)
|
||||
throw std::system_error{ errno, std::system_category(), "fopen" };
|
||||
return { fp, &fclose };
|
||||
}
|
||||
ScopedFILE CreateFILE(const path& p) noexcept(false)
|
||||
{
|
||||
const std::string fpath = p.generic_string();
|
||||
FILE* fp = fopen(fpath.c_str(), "w+b");
|
||||
if (!fp)
|
||||
throw std::system_error{ errno, std::system_category(), "fopen" };
|
||||
return { fp, &fclose };
|
||||
}
|
||||
#endif
|
||||
|
||||
[[noreturn]] void OnJPEGError(j_common_ptr ptr)
|
||||
{
|
||||
char msg[JMSG_LENGTH_MAX]{};
|
||||
// "0x89 0x50": PNG
|
||||
// "0x52 0x49": WEBP
|
||||
(*ptr->err->format_message)(ptr, msg);
|
||||
jpeg_destroy(ptr);
|
||||
throw std::runtime_error{ msg };
|
||||
}
|
||||
|
||||
class JPEGDecompress final
|
||||
{
|
||||
jpeg_error_mgr err;
|
||||
jpeg_decompress_struct dec;
|
||||
|
||||
public:
|
||||
JPEGDecompress() : err{}, dec{}
|
||||
{
|
||||
jpeg_std_error(&err);
|
||||
err.error_exit = &OnJPEGError;
|
||||
dec.err = &err;
|
||||
jpeg_create_decompress(&dec);
|
||||
}
|
||||
~JPEGDecompress() noexcept
|
||||
{
|
||||
jpeg_destroy_decompress(&dec);
|
||||
}
|
||||
|
||||
void UseInput(FILE* fin) noexcept
|
||||
{
|
||||
jpeg_stdio_src(&dec, fin);
|
||||
}
|
||||
|
||||
static DXGI_FORMAT TranslateColor(J_COLOR_SPACE colorspace) noexcept
|
||||
{
|
||||
switch (colorspace)
|
||||
{
|
||||
case JCS_GRAYSCALE: // 1 component
|
||||
return DXGI_FORMAT_R8_UNORM;
|
||||
case JCS_RGB: // 3 component, Standard RGB
|
||||
return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
case JCS_CMYK: // 4 component. WIC retuns this for CMYK
|
||||
return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
#ifdef LIBJPEG_TURBO_VERSION
|
||||
case JCS_EXT_RGBX: // 4 component
|
||||
case JCS_EXT_RGBA:
|
||||
return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
case JCS_RGB565:
|
||||
return DXGI_FORMAT_B5G6R5_UNORM;
|
||||
#endif
|
||||
case JCS_YCbCr: // 3 component, YCbCr
|
||||
default:
|
||||
return DXGI_FORMAT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
void GetMetadata(TexMetadata& metadata) noexcept(false)
|
||||
{
|
||||
metadata.width = dec.image_width;
|
||||
metadata.height = dec.image_height;
|
||||
metadata.depth = 1;
|
||||
metadata.arraySize = 1;
|
||||
metadata.mipLevels = 1;
|
||||
metadata.dimension = TEX_DIMENSION_TEXTURE2D;
|
||||
metadata.miscFlags2 |= TEX_ALPHA_MODE_OPAQUE;
|
||||
|
||||
metadata.format = TranslateColor(dec.out_color_space);
|
||||
if (metadata.format == DXGI_FORMAT_UNKNOWN)
|
||||
throw std::runtime_error{ "unexpected out_color_space in jpeg_decompress_struct" };
|
||||
}
|
||||
|
||||
HRESULT GetHeader(TexMetadata& metadata) noexcept(false)
|
||||
{
|
||||
metadata = {};
|
||||
switch (jpeg_read_header(&dec, false))
|
||||
{
|
||||
case JPEG_HEADER_TABLES_ONLY:
|
||||
[[fallthrough]];
|
||||
case JPEG_HEADER_OK:
|
||||
break;
|
||||
case JPEG_SUSPENDED:
|
||||
return E_FAIL;
|
||||
}
|
||||
GetMetadata(metadata);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#if !defined(LIBJPEG_TURBO_VERSION)
|
||||
// shift pixels with padding in reverse order (to make it work in-memory)
|
||||
void ShiftPixels(ScratchImage& image) noexcept
|
||||
{
|
||||
size_t num_pixels = dec.output_width * dec.output_height;
|
||||
uint8_t* dst = image.GetPixels();
|
||||
const uint8_t* src = dst;
|
||||
for (size_t i = num_pixels - 1; i > 0; i -= 1)
|
||||
{
|
||||
dst[4*i + 0] = src[3*i + 0];
|
||||
dst[4*i + 1] = src[3*i + 1];
|
||||
dst[4*i + 2] = src[3*i + 2];
|
||||
dst[4*i + 3] = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
HRESULT GetImage(TexMetadata& metadata, ScratchImage& image) noexcept(false)
|
||||
{
|
||||
metadata = {};
|
||||
switch (jpeg_read_header(&dec, true))
|
||||
{
|
||||
case JPEG_HEADER_TABLES_ONLY:
|
||||
GetMetadata(metadata);
|
||||
[[fallthrough]];
|
||||
case JPEG_SUSPENDED:
|
||||
return E_FAIL;
|
||||
case JPEG_HEADER_OK:
|
||||
break;
|
||||
}
|
||||
GetMetadata(metadata);
|
||||
// if the JPEG library doesn't have color space conversion, it should be ERROR_NOT_SUPPORTED
|
||||
if (dec.jpeg_color_space == JCS_YCCK)
|
||||
{
|
||||
// CMYK is the known case
|
||||
if (dec.out_color_space == JCS_CMYK)
|
||||
return HRESULT_E_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if (auto hr = image.Initialize2D(metadata.format, metadata.width, metadata.height, metadata.arraySize, metadata.mipLevels); FAILED(hr))
|
||||
return hr;
|
||||
|
||||
#ifdef LIBJPEG_TURBO_VERSION
|
||||
// grayscale is the only color space which uses 1 component
|
||||
if (dec.out_color_space != JCS_GRAYSCALE)
|
||||
// if there is no proper conversion to 4 component, E_FAIL...
|
||||
dec.out_color_space = JCS_EXT_RGBX;
|
||||
#endif
|
||||
if (jpeg_start_decompress(&dec) == false)
|
||||
return E_FAIL;
|
||||
|
||||
uint8_t* dest = image.GetPixels();
|
||||
const size_t stride = dec.output_width * static_cast<size_t>(dec.output_components);
|
||||
std::vector<JSAMPROW> rows(dec.output_height);
|
||||
for (size_t i = 0u; i < dec.output_height; ++i)
|
||||
rows[i] = dest + (stride * i);
|
||||
|
||||
JDIMENSION leftover = dec.output_height;
|
||||
while (leftover > 0)
|
||||
{
|
||||
JDIMENSION consumed = jpeg_read_scanlines(&dec, &rows[dec.output_scanline], leftover);
|
||||
leftover -= consumed;
|
||||
}
|
||||
if (jpeg_finish_decompress(&dec) == false)
|
||||
return E_FAIL;
|
||||
|
||||
#if !defined(LIBJPEG_TURBO_VERSION)
|
||||
// if NOT TurboJPEG, we need to make 3 component images to 4 component image
|
||||
if (dec.out_color_space != JCS_GRAYSCALE)
|
||||
ShiftPixels(image);
|
||||
#endif
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT GetImage(ScratchImage& image) noexcept(false)
|
||||
{
|
||||
TexMetadata metadata{};
|
||||
return GetImage(metadata, image);
|
||||
}
|
||||
};
|
||||
|
||||
class JPEGCompress final
|
||||
{
|
||||
jpeg_error_mgr err{};
|
||||
jpeg_compress_struct enc{};
|
||||
|
||||
public:
|
||||
JPEGCompress() : err{}, enc{}
|
||||
{
|
||||
jpeg_std_error(&err);
|
||||
err.error_exit = &OnJPEGError;
|
||||
enc.err = &err;
|
||||
jpeg_create_compress(&enc);
|
||||
}
|
||||
~JPEGCompress() noexcept
|
||||
{
|
||||
jpeg_destroy_compress(&enc);
|
||||
}
|
||||
|
||||
void UseOutput(FILE* fout)
|
||||
{
|
||||
jpeg_stdio_dest(&enc, fout);
|
||||
}
|
||||
|
||||
/// @todo More correct DXGI_FORMAT mapping
|
||||
HRESULT WriteImage(const Image& image) noexcept(false)
|
||||
{
|
||||
switch (image.format)
|
||||
{
|
||||
case DXGI_FORMAT_R8_UNORM:
|
||||
enc.input_components = 1;
|
||||
enc.in_color_space = JCS_GRAYSCALE;
|
||||
break;
|
||||
#ifdef LIBJPEG_TURBO_VERSION
|
||||
case DXGI_FORMAT_R8G8B8A8_UNORM:
|
||||
enc.input_components = 4;
|
||||
enc.in_color_space = JCS_EXT_RGBA;
|
||||
break;
|
||||
case DXGI_FORMAT_B8G8R8A8_UNORM:
|
||||
enc.input_components = 4;
|
||||
enc.in_color_space = JCS_EXT_BGRA;
|
||||
break;
|
||||
#else
|
||||
case DXGI_FORMAT_R8G8B8A8_UNORM:
|
||||
enc.input_components = 3;
|
||||
enc.in_color_space = JCS_RGB;
|
||||
#endif
|
||||
|
||||
default:
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
enc.image_width = static_cast<JDIMENSION>(image.width);
|
||||
enc.image_height = static_cast<JDIMENSION>(image.height);
|
||||
jpeg_set_defaults(&enc);
|
||||
jpeg_set_quality(&enc, 100, true);
|
||||
// we will write a row each time ...
|
||||
jpeg_start_compress(&enc, true);
|
||||
const size_t stride = enc.image_width * static_cast<size_t>(enc.input_components);
|
||||
while (enc.next_scanline < enc.image_height)
|
||||
{
|
||||
JSAMPROW rows[1]{ image.pixels + stride * enc.next_scanline };
|
||||
jpeg_write_scanlines(&enc, rows, 1);
|
||||
}
|
||||
jpeg_finish_compress(&enc);
|
||||
return S_OK;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_Use_decl_annotations_
|
||||
HRESULT DirectX::GetMetadataFromJPEGFile(
|
||||
const wchar_t* file,
|
||||
TexMetadata& metadata)
|
||||
{
|
||||
if (!file)
|
||||
return E_INVALIDARG;
|
||||
|
||||
try
|
||||
{
|
||||
auto fin = OpenFILE(file);
|
||||
JPEGDecompress decoder{};
|
||||
decoder.UseInput(fin.get());
|
||||
return decoder.GetHeader(metadata);
|
||||
}
|
||||
catch (const std::bad_alloc&)
|
||||
{
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
catch (const std::system_error& ec)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return HRESULT_FROM_WIN32(static_cast<unsigned long>(ec.code().value()));
|
||||
#else
|
||||
return (ec.code().value() == ENOENT) ? HRESULT_ERROR_FILE_NOT_FOUND : E_FAIL;
|
||||
#endif
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
_Use_decl_annotations_
|
||||
HRESULT DirectX::LoadFromJPEGFile(
|
||||
const wchar_t* file,
|
||||
TexMetadata* metadata,
|
||||
ScratchImage&image)
|
||||
{
|
||||
if (!file)
|
||||
return E_INVALIDARG;
|
||||
|
||||
image.Release();
|
||||
|
||||
try
|
||||
{
|
||||
auto fin = OpenFILE(file);
|
||||
JPEGDecompress decoder{};
|
||||
decoder.UseInput(fin.get());
|
||||
if (!metadata)
|
||||
return decoder.GetImage(image);
|
||||
return decoder.GetImage(*metadata, image);
|
||||
}
|
||||
catch (const std::bad_alloc&)
|
||||
{
|
||||
image.Release();
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
catch (const std::system_error& ec)
|
||||
{
|
||||
image.Release();
|
||||
#ifdef _WIN32
|
||||
return HRESULT_FROM_WIN32(static_cast<unsigned long>(ec.code().value()));
|
||||
#else
|
||||
return (ec.code().value() == ENOENT) ? HRESULT_ERROR_FILE_NOT_FOUND : E_FAIL;
|
||||
#endif
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
image.Release();
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
_Use_decl_annotations_
|
||||
HRESULT DirectX::SaveToJPEGFile(
|
||||
const Image& image,
|
||||
const wchar_t* file)
|
||||
{
|
||||
if (!file)
|
||||
return E_INVALIDARG;
|
||||
|
||||
try
|
||||
{
|
||||
auto fout = CreateFILE(file);
|
||||
JPEGCompress encoder{};
|
||||
encoder.UseOutput(fout.get());
|
||||
return encoder.WriteImage(image);
|
||||
}
|
||||
catch (const std::bad_alloc&)
|
||||
{
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
catch (const std::system_error& ec)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return HRESULT_FROM_WIN32(static_cast<unsigned long>(ec.code().value()));
|
||||
#else
|
||||
return (ec.code().value() == ENOENT) ? HRESULT_ERROR_FILE_NOT_FOUND : E_FAIL;
|
||||
#endif
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
33
Auxiliary/DirectXTexJPEG.h
Normal file
33
Auxiliary/DirectXTexJPEG.h
Normal file
@ -0,0 +1,33 @@
|
||||
//--------------------------------------------------------------------------------------
|
||||
// File: DirectXTexJPEG.h
|
||||
//
|
||||
// DirectXTex Auxilary functions for using the JPEG(https://www.ijg.org) library
|
||||
//
|
||||
// For the Windows platform, the strong recommendation is to make use of the WIC
|
||||
// functions rather than using the open source library. This module exists to support
|
||||
// Windows Subsystem on Linux.
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "DirectXTex.h"
|
||||
|
||||
|
||||
namespace DirectX
|
||||
{
|
||||
HRESULT __cdecl GetMetadataFromJPEGFile(
|
||||
_In_z_ const wchar_t* szFile,
|
||||
_Out_ TexMetadata& metadata);
|
||||
|
||||
HRESULT __cdecl LoadFromJPEGFile(
|
||||
_In_z_ const wchar_t* szFile,
|
||||
_Out_opt_ TexMetadata* metadata,
|
||||
_Out_ ScratchImage& image);
|
||||
|
||||
HRESULT __cdecl SaveToJPEGFile(
|
||||
_In_ const Image& image,
|
||||
_In_z_ const wchar_t* szFile);
|
||||
}
|
414
Auxiliary/DirectXTexPNG.cpp
Normal file
414
Auxiliary/DirectXTexPNG.cpp
Normal file
@ -0,0 +1,414 @@
|
||||
//--------------------------------------------------------------------------------------
|
||||
// File: DirectXTexPNG.cpp
|
||||
//
|
||||
// DirectXTex Auxilary functions for using the PNG(http://www.libpng.org/pub/png/libpng.html) library
|
||||
//
|
||||
// For the Windows platform, the strong recommendation is to make use of the WIC
|
||||
// functions rather than using the open source library. This module exists to support
|
||||
// Windows Subsystem on Linux.
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
#include "DirectXTexP.h"
|
||||
#include "DirectXTexPNG.h"
|
||||
|
||||
#if __cplusplus < 201703L
|
||||
#error Requires C++17 (and /Zc:__cplusplus with MSVC)
|
||||
#endif
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <exception>
|
||||
#include <filesystem>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
#include <vector>
|
||||
|
||||
#include <png.h>
|
||||
|
||||
|
||||
using namespace DirectX;
|
||||
using std::filesystem::path;
|
||||
using ScopedFILE = std::unique_ptr<FILE, int(*)(FILE*)>;
|
||||
|
||||
namespace
|
||||
{
|
||||
#ifdef _WIN32
|
||||
ScopedFILE OpenFILE(const path& p) noexcept(false)
|
||||
{
|
||||
const std::wstring fpath = p.generic_wstring();
|
||||
FILE* fp = nullptr;
|
||||
if (auto ec = _wfopen_s(&fp, fpath.c_str(), L"rb"); ec)
|
||||
throw std::system_error{ static_cast<int>(_doserrno), std::system_category(), "_wfopen_s" };
|
||||
return { fp, &fclose };
|
||||
}
|
||||
ScopedFILE CreateFILE(const path& p) noexcept(false)
|
||||
{
|
||||
const std::wstring fpath = p.generic_wstring();
|
||||
FILE* fp = nullptr;
|
||||
if (auto ec = _wfopen_s(&fp, fpath.c_str(), L"w+b"); ec)
|
||||
throw std::system_error{ static_cast<int>(_doserrno), std::system_category(), "_wfopen_s" };
|
||||
return { fp, &fclose };
|
||||
}
|
||||
#else
|
||||
ScopedFILE OpenFILE(const path& p) noexcept(false)
|
||||
{
|
||||
const std::string fpath = p.generic_string();
|
||||
FILE* fp = fopen(fpath.c_str(), "rb");
|
||||
if (!fp)
|
||||
throw std::system_error{ errno, std::system_category(), "fopen" };
|
||||
return { fp, &fclose };
|
||||
}
|
||||
ScopedFILE CreateFILE(const path& p) noexcept(false)
|
||||
{
|
||||
const std::string fpath = p.generic_string();
|
||||
FILE* fp = fopen(fpath.c_str(), "w+b");
|
||||
if (!fp)
|
||||
throw std::system_error{ errno, std::system_category(), "fopen" };
|
||||
return { fp, &fclose };
|
||||
}
|
||||
#endif
|
||||
|
||||
[[noreturn]] void OnPNGError(png_structp, png_const_charp msg)
|
||||
{
|
||||
throw std::runtime_error{ msg };
|
||||
}
|
||||
|
||||
void OnPNGWarning(png_structp, png_const_charp)
|
||||
{
|
||||
// drain warning messages ...
|
||||
}
|
||||
|
||||
/// @note If the PNG contains some extra chunks like EXIF, this will be used
|
||||
void OnPNGRead(png_structp st, png_bytep ptr, size_t len)
|
||||
{
|
||||
FILE* fin = reinterpret_cast<FILE*>(png_get_io_ptr(st));
|
||||
fread(ptr, len, 1, fin);
|
||||
}
|
||||
|
||||
|
||||
/// @see http://www.libpng.org/pub/png/libpng.html
|
||||
/// @see http://www.libpng.org/pub/png/libpng-manual.txt
|
||||
class PNGDecompress final
|
||||
{
|
||||
png_structp st;
|
||||
png_infop info;
|
||||
|
||||
public:
|
||||
PNGDecompress() noexcept(false) : st{ nullptr }, info{ nullptr }
|
||||
{
|
||||
st = png_create_read_struct(PNG_LIBPNG_VER_STRING, this, &OnPNGError, &OnPNGWarning);
|
||||
if (!st)
|
||||
throw std::runtime_error{ "png_create_read_struct" };
|
||||
info = png_create_info_struct(st);
|
||||
if (!info)
|
||||
{
|
||||
png_destroy_read_struct(&st, nullptr, nullptr);
|
||||
throw std::runtime_error{ "png_create_info_struct" };
|
||||
}
|
||||
}
|
||||
|
||||
~PNGDecompress() noexcept
|
||||
{
|
||||
png_destroy_read_struct(&st, &info, nullptr);
|
||||
}
|
||||
|
||||
void UseInput(FILE* fin) noexcept
|
||||
{
|
||||
// we assume the signature is unread. if so, we have to use `png_set_sig_bytes`
|
||||
png_init_io(st, fin);
|
||||
png_set_read_fn(st, fin, &OnPNGRead);
|
||||
}
|
||||
|
||||
void Update() noexcept(false)
|
||||
{
|
||||
png_read_info(st, info);
|
||||
// color handling
|
||||
png_byte color_type = png_get_color_type(st, info);
|
||||
if (color_type == PNG_COLOR_TYPE_GRAY)
|
||||
{
|
||||
// bit_depth will be 8 or 16
|
||||
if (png_get_bit_depth(st, info) < 8)
|
||||
png_set_expand_gray_1_2_4_to_8(st);
|
||||
}
|
||||
else if (color_type == PNG_COLOR_TYPE_PALETTE)
|
||||
{
|
||||
// request RGB color
|
||||
png_set_palette_to_rgb(st);
|
||||
if (png_get_valid(st, info, PNG_INFO_tRNS))
|
||||
png_set_tRNS_to_alpha(st);
|
||||
}
|
||||
// Here we don't know if the pixel data is in BGR/RGB order
|
||||
// png_set_bgr(st);
|
||||
png_set_alpha_mode(st, PNG_ALPHA_STANDARD, PNG_DEFAULT_sRGB);
|
||||
// make 4 component
|
||||
// using `png_set_add_alpha` here may confuse `TEX_ALPHA_MODE_OPAQUE` estimation
|
||||
if (png_get_channels(st, info) == 3)
|
||||
png_set_filler(st, 0, PNG_FILLER_AFTER);
|
||||
// prefer DXGI_FORMAT_R8G8B8A8_UNORM. strip in decode
|
||||
//if (png_get_bit_depth(st, info) > 8)
|
||||
// png_set_strip_16(st);
|
||||
png_read_update_info(st, info);
|
||||
}
|
||||
|
||||
/// @note must call `Update` before this
|
||||
/// @todo Proper detection of DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM_SRGB
|
||||
DXGI_FORMAT GuessFormat() const noexcept(false)
|
||||
{
|
||||
// 1 or 4. 1 is for gray
|
||||
auto c = png_get_channels(st, info);
|
||||
if (c == 1)
|
||||
{
|
||||
if (png_get_bit_depth(st, info) == 16)
|
||||
return DXGI_FORMAT_R16_UNORM;
|
||||
// with `png_set_expand_gray_1_2_4_to_8`, libpng will change to R8_UNORM
|
||||
return DXGI_FORMAT_R8_UNORM;
|
||||
}
|
||||
|
||||
// 8 or 16. expanded if 1, 2, 4
|
||||
auto d = png_get_bit_depth(st, info);
|
||||
if (d == 16)
|
||||
return DXGI_FORMAT_R16G16B16A16_UNORM;
|
||||
if (d != 8)
|
||||
throw std::runtime_error{ "unexpected info from libpng" };
|
||||
|
||||
int intent = 0;
|
||||
if (png_get_sRGB(st, info, &intent) == PNG_INFO_sRGB)
|
||||
return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
|
||||
|
||||
return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
}
|
||||
|
||||
/// @todo More correct DXGI_FORMAT mapping
|
||||
void GetHeader(TexMetadata& metadata) noexcept(false)
|
||||
{
|
||||
metadata.width = png_get_image_width(st, info);
|
||||
metadata.height = png_get_image_height(st, info);
|
||||
metadata.arraySize = 1;
|
||||
metadata.mipLevels = 1;
|
||||
metadata.depth = 1;
|
||||
metadata.dimension = TEX_DIMENSION_TEXTURE2D;
|
||||
metadata.format = GuessFormat();
|
||||
png_byte color_type = png_get_color_type(st, info);
|
||||
bool have_alpha = (color_type & PNG_COLOR_MASK_ALPHA);
|
||||
if (have_alpha == false)
|
||||
metadata.miscFlags2 |= TEX_ALPHA_MODE_OPAQUE;
|
||||
}
|
||||
|
||||
/// @todo More correct DXGI_FORMAT mapping
|
||||
HRESULT GetImage(TexMetadata& metadata, ScratchImage& image) noexcept(false)
|
||||
{
|
||||
metadata = {};
|
||||
GetHeader(metadata);
|
||||
|
||||
if (auto hr = image.Initialize2D(metadata.format, metadata.width, metadata.height, metadata.arraySize, metadata.mipLevels); FAILED(hr))
|
||||
return hr;
|
||||
auto* dest = image.GetPixels();
|
||||
const auto stride = metadata.width * png_get_channels(st, info);
|
||||
std::vector<png_byte*> rows(metadata.height);
|
||||
for (auto i = 0u; i < metadata.height; ++i)
|
||||
rows[i] = dest + (stride * i);
|
||||
|
||||
png_read_rows(st, rows.data(), nullptr, static_cast<uint32_t>(rows.size()));
|
||||
png_read_end(st, info);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT GetImage(ScratchImage& image) noexcept(false)
|
||||
{
|
||||
TexMetadata metadata{};
|
||||
return GetImage(metadata, image);
|
||||
}
|
||||
};
|
||||
|
||||
/// @see http://www.libpng.org/pub/png/libpng.html
|
||||
/// @see http://www.libpng.org/pub/png/libpng-manual.txt
|
||||
class PNGCompress final
|
||||
{
|
||||
png_structp st;
|
||||
png_infop info;
|
||||
|
||||
public:
|
||||
PNGCompress() noexcept(false) : st{ nullptr }, info{ nullptr }
|
||||
{
|
||||
st = png_create_write_struct(PNG_LIBPNG_VER_STRING, this, &OnPNGError, &OnPNGWarning);
|
||||
if (!st)
|
||||
throw std::runtime_error{ "png_create_write_struct" };
|
||||
info = png_create_info_struct(st);
|
||||
if (!info)
|
||||
{
|
||||
png_destroy_write_struct(&st, nullptr);
|
||||
throw std::runtime_error{ "png_create_info_struct" };
|
||||
}
|
||||
png_set_compression_level(st, 0);
|
||||
}
|
||||
|
||||
~PNGCompress() noexcept
|
||||
{
|
||||
png_destroy_write_struct(&st, &info);
|
||||
}
|
||||
|
||||
void UseOutput(FILE* fout) noexcept
|
||||
{
|
||||
png_init_io(st, fout);
|
||||
}
|
||||
|
||||
HRESULT WriteImage(const Image& image) noexcept(false)
|
||||
{
|
||||
int color_type = PNG_COLOR_TYPE_RGB;
|
||||
bool using_bgr = false;
|
||||
int channel = 4;
|
||||
int bit_depth = 8;
|
||||
switch (image.format)
|
||||
{
|
||||
case DXGI_FORMAT_R8_UNORM:
|
||||
color_type = PNG_COLOR_TYPE_GRAY;
|
||||
break;
|
||||
case DXGI_FORMAT_B8G8R8A8_UNORM:
|
||||
case DXGI_FORMAT_B8G8R8X8_UNORM:
|
||||
using_bgr = true;
|
||||
[[fallthrough]];
|
||||
case DXGI_FORMAT_R8G8B8A8_UNORM:
|
||||
color_type = PNG_COLOR_TYPE_RGBA;
|
||||
break;
|
||||
default:
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
png_set_IHDR(st, info,
|
||||
static_cast<uint32_t>(image.width),
|
||||
static_cast<uint32_t>(image.height),
|
||||
bit_depth,
|
||||
color_type,
|
||||
PNG_INTERLACE_NONE,
|
||||
PNG_COMPRESSION_TYPE_DEFAULT,
|
||||
PNG_FILTER_TYPE_DEFAULT);
|
||||
png_write_info(st, info);
|
||||
if (using_bgr)
|
||||
png_set_bgr(st);
|
||||
|
||||
const size_t stride = static_cast<size_t>(channel) * image.width;
|
||||
std::vector<png_bytep> rows(image.height);
|
||||
for (size_t i = 0u; i< image.height; ++i)
|
||||
rows[i] = image.pixels + stride * i;
|
||||
png_write_rows(st, rows.data(), static_cast<uint32_t>(rows.size()));
|
||||
|
||||
// actual write will be done here
|
||||
png_write_end(st, info);
|
||||
return S_OK;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_Use_decl_annotations_
|
||||
HRESULT DirectX::GetMetadataFromPNGFile(
|
||||
const wchar_t* file,
|
||||
TexMetadata& metadata)
|
||||
{
|
||||
if (!file)
|
||||
return E_INVALIDARG;
|
||||
|
||||
try
|
||||
{
|
||||
auto fin = OpenFILE(file);
|
||||
PNGDecompress decoder{};
|
||||
decoder.UseInput(fin.get());
|
||||
decoder.Update();
|
||||
decoder.GetHeader(metadata);
|
||||
return S_OK;
|
||||
}
|
||||
catch (const std::bad_alloc&)
|
||||
{
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
catch (const std::system_error& ec)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return HRESULT_FROM_WIN32(static_cast<unsigned long>(ec.code().value()));
|
||||
#else
|
||||
return (ec.code().value() == ENOENT) ? HRESULT_ERROR_FILE_NOT_FOUND : E_FAIL;
|
||||
#endif
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
_Use_decl_annotations_
|
||||
HRESULT DirectX::LoadFromPNGFile(
|
||||
const wchar_t* file,
|
||||
TexMetadata* metadata,
|
||||
ScratchImage& image)
|
||||
{
|
||||
if (!file)
|
||||
return E_INVALIDARG;
|
||||
|
||||
image.Release();
|
||||
|
||||
try
|
||||
{
|
||||
auto fin = OpenFILE(file);
|
||||
PNGDecompress decoder{};
|
||||
decoder.UseInput(fin.get());
|
||||
decoder.Update();
|
||||
if (metadata == nullptr)
|
||||
return decoder.GetImage(image);
|
||||
return decoder.GetImage(*metadata, image);
|
||||
}
|
||||
catch (const std::bad_alloc&)
|
||||
{
|
||||
image.Release();
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
catch (const std::system_error& ec)
|
||||
{
|
||||
image.Release();
|
||||
#ifdef _WIN32
|
||||
return HRESULT_FROM_WIN32(static_cast<unsigned long>(ec.code().value()));
|
||||
#else
|
||||
return (ec.code().value() == ENOENT) ? HRESULT_ERROR_FILE_NOT_FOUND : E_FAIL;
|
||||
#endif
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
image.Release();
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
_Use_decl_annotations_
|
||||
HRESULT DirectX::SaveToPNGFile(
|
||||
const Image& image,
|
||||
const wchar_t* file)
|
||||
{
|
||||
if (!file)
|
||||
return E_INVALIDARG;
|
||||
|
||||
try
|
||||
{
|
||||
auto fout = CreateFILE(file);
|
||||
PNGCompress encoder{};
|
||||
encoder.UseOutput(fout.get());
|
||||
return encoder.WriteImage(image);
|
||||
}
|
||||
catch (const std::bad_alloc&)
|
||||
{
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
catch (const std::system_error& ec)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return HRESULT_FROM_WIN32(static_cast<unsigned long>(ec.code().value()));
|
||||
#else
|
||||
return (ec.code().value() == ENOENT) ? HRESULT_ERROR_FILE_NOT_FOUND : E_FAIL;
|
||||
#endif
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
33
Auxiliary/DirectXTexPNG.h
Normal file
33
Auxiliary/DirectXTexPNG.h
Normal file
@ -0,0 +1,33 @@
|
||||
//--------------------------------------------------------------------------------------
|
||||
// File: DirectXTexPNG.h
|
||||
//
|
||||
// DirectXTex Auxilary functions for using the PNG(http://www.libpng.org/pub/png/libpng.html) library
|
||||
//
|
||||
// For the Windows platform, the strong recommendation is to make use of the WIC
|
||||
// functions rather than using the open source library. This module exists to support
|
||||
// Windows Subsystem on Linux.
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "DirectXTex.h"
|
||||
|
||||
|
||||
namespace DirectX
|
||||
{
|
||||
HRESULT __cdecl GetMetadataFromPNGFile(
|
||||
_In_z_ const wchar_t* szFile,
|
||||
_Out_ TexMetadata& metadata);
|
||||
|
||||
HRESULT __cdecl LoadFromPNGFile(
|
||||
_In_z_ const wchar_t* szFile,
|
||||
_Out_opt_ TexMetadata* metadata,
|
||||
_Out_ ScratchImage& image);
|
||||
|
||||
HRESULT __cdecl SaveToPNGFile(
|
||||
_In_ const Image& image,
|
||||
_In_z_ const wchar_t* szFile);
|
||||
}
|
@ -48,6 +48,12 @@ option(BUILD_FUZZING "Build for fuzz testing" OFF)
|
||||
# Includes the functions for loading/saving OpenEXR files at runtime
|
||||
option(ENABLE_OPENEXR_SUPPORT "Build with OpenEXR support" OFF)
|
||||
|
||||
# See https://www.ijg.org/
|
||||
option(ENABLE_LIBJPEG_SUPPORT "Build with libjpeg support" OFF)
|
||||
|
||||
# See http://www.libpng.org/pub/png/libpng.html
|
||||
option(ENABLE_LIBPNG_SUPPORT "Build with libpng support" OFF)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
@ -181,6 +187,22 @@ if(ENABLE_OPENEXR_SUPPORT)
|
||||
list(APPEND LIBRARY_SOURCES Auxiliary/DirectXTexEXR.cpp)
|
||||
endif()
|
||||
|
||||
if(ENABLE_LIBJPEG_SUPPORT)
|
||||
if(WIN32)
|
||||
message(STATUS "Use of the Windows Imaging Component (WIC) instead of libjpeg is recommended.")
|
||||
endif()
|
||||
list(APPEND LIBRARY_HEADERS Auxiliary/DirectXTexJPEG.h)
|
||||
list(APPEND LIBRARY_SOURCES Auxiliary/DirectXTexJPEG.cpp)
|
||||
endif()
|
||||
|
||||
if(ENABLE_LIBPNG_SUPPORT)
|
||||
if(WIN32)
|
||||
message(STATUS "Use of the Windows Imaging Component (WIC) instead of libpng is recommended.")
|
||||
endif()
|
||||
list(APPEND LIBRARY_HEADERS Auxiliary/DirectXTexPNG.h)
|
||||
list(APPEND LIBRARY_SOURCES Auxiliary/DirectXTexPNG.cpp)
|
||||
endif()
|
||||
|
||||
if(BUILD_DX11 AND WIN32)
|
||||
if(NOT COMPILED_SHADERS)
|
||||
if(USE_PREBUILT_SHADERS)
|
||||
@ -255,6 +277,16 @@ elseif(BUILD_XBOX_EXTS_XBOXONE AND WIN32)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_LIBJPEG_SUPPORT)
|
||||
find_package(JPEG REQUIRED)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC JPEG::JPEG)
|
||||
endif()
|
||||
|
||||
if(ENABLE_LIBPNG_SUPPORT)
|
||||
find_package(PNG REQUIRED)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC PNG::PNG)
|
||||
endif()
|
||||
|
||||
if(NOT MINGW)
|
||||
target_precompile_headers(${PROJECT_NAME} PRIVATE DirectXTex/DirectXTexP.h)
|
||||
endif()
|
||||
@ -364,6 +396,13 @@ endif()
|
||||
if(directx-headers_FOUND)
|
||||
list(APPEND DIRECTXTEX_DEP_L "DirectX-Headers")
|
||||
endif()
|
||||
if(ENABLE_LIBJPEG_SUPPORT AND JPEG_FOUND)
|
||||
list(APPEND DIRECTXTEX_DEP_L "libjpeg")
|
||||
endif()
|
||||
if(ENABLE_LIBPNG_SUPPORT AND PNG_FOUND)
|
||||
list(APPEND DIRECTXTEX_DEP_L "libpng")
|
||||
endif()
|
||||
|
||||
list(LENGTH DIRECTXTEX_DEP_L DEP_L)
|
||||
if(DEP_L)
|
||||
STRING(REPLACE ";" ", " DIRECTXTEX_DEP " ${DIRECTXTEX_DEP_L}")
|
||||
@ -425,6 +464,20 @@ if(BUILD_TOOLS AND WIN32)
|
||||
target_compile_definitions(${t} PRIVATE USE_OPENEXR)
|
||||
endforeach()
|
||||
endif()
|
||||
if(ENABLE_LIBJPEG_SUPPORT)
|
||||
foreach(t IN LISTS TOOL_EXES)
|
||||
target_include_directories(${t} PRIVATE Auxiliary)
|
||||
target_link_libraries(${t} PRIVATE JPEG::JPEG)
|
||||
target_compile_definitions(${t} PRIVATE USE_LIBJPEG)
|
||||
endforeach()
|
||||
endif()
|
||||
if(ENABLE_LIBPNG_SUPPORT)
|
||||
foreach(t IN LISTS TOOL_EXES)
|
||||
target_include_directories(${t} PRIVATE Auxiliary)
|
||||
target_link_libraries(${t} PRIVATE PNG::PNG)
|
||||
target_compile_definitions(${t} PRIVATE USE_LIBPNG)
|
||||
endforeach()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#--- DDSView sample
|
||||
|
@ -172,6 +172,14 @@
|
||||
},
|
||||
"hidden": true
|
||||
},
|
||||
{
|
||||
"name": "JPEG_PNG",
|
||||
"cacheVariables": {
|
||||
"ENABLE_LIBJPEG_SUPPORT": true,
|
||||
"ENABLE_LIBPNG_SUPPORT": true
|
||||
},
|
||||
"hidden": true
|
||||
},
|
||||
{
|
||||
"name": "MinGW32",
|
||||
"hidden": true,
|
||||
@ -241,6 +249,9 @@
|
||||
{ "name": "x64-Debug-EXR" , "description": "MSVC for x64 (Debug) using VCPKG/OpenEXR", "inherits": [ "base", "x64", "Debug", "MSVC", "VCPKG", "EXR" ] },
|
||||
{ "name": "x64-Release-EXR" , "description": "MSVC for x64 (Release) using VCPKG/OpenEXR", "inherits": [ "base", "x64", "Release", "MSVC", "VCPKG", "EXR" ] },
|
||||
|
||||
{ "name": "x64-Debug-JPEG-PNG" , "description": "MSVC for x64 (Debug) using VCPKG/PNG/JPEG", "inherits": [ "base", "x64", "Debug", "MSVC", "VCPKG", "JPEG_PNG" ] },
|
||||
{ "name": "x64-Release-JPEG-PNG", "description": "MSVC for x64 (Release) using VCPKG/PNG/JPEG", "inherits": [ "base", "x64", "Release", "MSVC", "VCPKG", "JPEG_PNG" ] },
|
||||
|
||||
{ "name": "x64-Debug-Clang" , "description": "Clang/LLVM for x64 (Debug) with DX12", "inherits": [ "base", "x64", "Debug", "Clang" ] },
|
||||
{ "name": "x64-Release-Clang" , "description": "Clang/LLVM for x64 (Release) with DX12", "inherits": [ "base", "x64", "Release", "Clang" ] },
|
||||
{ "name": "x86-Debug-Clang" , "description": "Clang/LLVM for x86 (Debug) with DX12", "inherits": [ "base", "x86", "Debug", "Clang" ], "environment": { "CXXFLAGS": "-m32" } },
|
||||
@ -260,6 +271,9 @@
|
||||
{ "name": "x86-Debug-Win7-Clang" , "description": "Clang/LLVM for x86 (Debug) for Windows 7", "inherits": [ "base", "x86", "Debug", "Clang", "Win7" ], "environment": { "CXXFLAGS": "-m32" } },
|
||||
{ "name": "x86-Release-Win7-Clang", "description": "Clang/LLVM for x86 (Release) for Windows 7", "inherits": [ "base", "x86", "Release", "Clang", "Win7" ], "environment": { "CXXFLAGS": "-m32" } },
|
||||
|
||||
{ "name": "x64-Debug-Clang-JPEG-PNG" , "description": "Clang/LLVM for x64 (Debug) with DX12", "inherits": [ "base", "x64", "Debug", "Clang", "VCPKG", "JPEG_PNG" ] },
|
||||
{ "name": "x64-Release-Clang-JPEG-PNG" , "description": "Clang/LLVM for x64 (Release) with DX12", "inherits": [ "base", "x64", "Release", "Clang", "VCPKG", "JPEG_PNG" ] },
|
||||
|
||||
{ "name": "x64-Debug-GDKX" , "description": "MSVC for x64 (Debug) Xbox One Extensions", "inherits": [ "base", "x64", "Debug", "GDKX", "MSVC" ] },
|
||||
{ "name": "x64-Release-GDKX" , "description": "MSVC for x64 (Release) Xbox One Extensions", "inherits": [ "base", "x64", "Release", "GDKX", "MSVC" ] },
|
||||
{ "name": "x64-Debug-GDKX-S" , "description": "MSVC for x64 (Debug) Xbox Series X|S Extensions", "inherits": [ "base", "x64", "Debug", "GDKXS", "MSVC" ] },
|
||||
@ -277,10 +291,15 @@
|
||||
{ "name": "x86-Debug-MinGW" , "description": "MinG-W32 (Debug)", "inherits": [ "base", "x86", "Debug", "GNUC", "VCPKG", "MinGW32" ] },
|
||||
{ "name": "x86-Release-MinGW", "description": "MinG-W32 (Release)", "inherits": [ "base", "x86", "Release", "GNUC", "VCPKG", "MinGW32" ] },
|
||||
|
||||
{ "name": "x64-Debug-Linux", "description": "WSL Linux x64 (Debug)", "inherits": [ "base", "x64", "Debug", "VCPKG" ] },
|
||||
{ "name": "x64-Release-Linux", "description": "WSL Linux x64 (Release)", "inherits": [ "base", "x64", "Release", "VCPKG" ] },
|
||||
{ "name": "arm64-Debug-Linux", "description": "WSL Linux ARM64 (Debug)", "inherits": [ "base", "ARM64", "Debug", "VCPKG" ] },
|
||||
{ "name": "arm64-Release-Linux", "description": "WSL Linux ARM64 (Release)", "inherits": [ "base", "ARM64", "Release", "VCPKG" ] },
|
||||
{ "name": "x64-Debug-MinGW-JPEG-PNG" , "description": "MinG-W64 (Debug)", "inherits": [ "base", "x64", "Debug", "GNUC", "VCPKG", "MinGW64", "JPEG_PNG" ] },
|
||||
{ "name": "x64-Release-MinGW-JPEG-PNG", "description": "MinG-W64 (Release)", "inherits": [ "base", "x64", "Release", "GNUC", "VCPKG", "MinGW64", "JPEG_PNG" ] },
|
||||
{ "name": "x86-Debug-MinGW-JPEG-PNG" , "description": "MinG-W32 (Debug)", "inherits": [ "base", "x86", "Debug", "GNUC", "VCPKG", "MinGW32", "JPEG_PNG" ] },
|
||||
{ "name": "x86-Release-MinGW-JPEG-PNG", "description": "MinG-W32 (Release)", "inherits": [ "base", "x86", "Release", "GNUC", "VCPKG", "MinGW32", "JPEG_PNG" ] },
|
||||
|
||||
{ "name": "x64-Debug-Linux", "description": "WSL Linux x64 (Debug)", "inherits": [ "base", "x64", "Debug", "VCPKG", "JPEG_PNG" ] },
|
||||
{ "name": "x64-Release-Linux", "description": "WSL Linux x64 (Release)", "inherits": [ "base", "x64", "Release", "VCPKG", "JPEG_PNG" ] },
|
||||
{ "name": "arm64-Debug-Linux", "description": "WSL Linux ARM64 (Debug)", "inherits": [ "base", "ARM64", "Debug", "VCPKG", "JPEG_PNG" ] },
|
||||
{ "name": "arm64-Release-Linux", "description": "WSL Linux ARM64 (Release)", "inherits": [ "base", "ARM64", "Release", "VCPKG", "JPEG_PNG" ] },
|
||||
|
||||
{ "name": "x64-Fuzzing" , "description": "MSVC for x64 (Release) with ASan", "inherits": [ "base", "x64", "Release", "MSVC", "Fuzzing" ] }
|
||||
],
|
||||
|
@ -198,6 +198,9 @@ using WICPixelFormatGUID = GUID;
|
||||
#define E_BOUNDS static_cast<HRESULT>(0x8000000BL)
|
||||
#endif
|
||||
|
||||
// HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)
|
||||
#define HRESULT_ERROR_FILE_NOT_FOUND static_cast<HRESULT>(0x80070002)
|
||||
|
||||
// HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW)
|
||||
#define HRESULT_E_ARITHMETIC_OVERFLOW static_cast<HRESULT>(0x80070216L)
|
||||
|
||||
|
@ -127,4 +127,6 @@ The DirectXTex library is the work of Chuck Walbourn, with contributions from Ma
|
||||
|
||||
Thanks to Paul Penson for his help with the implementation of ``MemoryStreamOnBlob``.
|
||||
|
||||
Thanks to Andrew Farrier and Scott Matloff for their on-going help with code reviews.
|
||||
Thanks to Andrew Farrier and Scott Matloff for their on-going help with code reviews.
|
||||
|
||||
Thanks to Park DongHa for their contribution of the JPEG/PNG auxiliary functions.
|
||||
|
@ -62,14 +62,19 @@
|
||||
|
||||
#include "DirectXTex.h"
|
||||
|
||||
//Uncomment to add support for OpenEXR (.exr)
|
||||
//#define USE_OPENEXR
|
||||
|
||||
#ifdef USE_OPENEXR
|
||||
// See <https://github.com/Microsoft/DirectXTex/wiki/Adding-OpenEXR> for details
|
||||
#include "DirectXTexEXR.h"
|
||||
#endif
|
||||
|
||||
// See <https://github.com/Microsoft/DirectXTex/wiki/Using-JPEG-PNG-OSS> for details
|
||||
#ifdef USE_LIBJPEG
|
||||
#include "DirectXTexJPEG.h"
|
||||
#endif
|
||||
#ifdef USE_LIBPNG
|
||||
#include "DirectXTexPNG.h"
|
||||
#endif
|
||||
|
||||
using namespace DirectX;
|
||||
using Microsoft::WRL::ComPtr;
|
||||
|
||||
@ -318,26 +323,41 @@ namespace
|
||||
|
||||
#ifdef USE_OPENEXR
|
||||
#define CODEC_EXR 0xFFFF0006
|
||||
#endif
|
||||
#ifdef USE_LIBJPEG
|
||||
#define CODEC_JPEG 0xFFFF0007
|
||||
#endif
|
||||
#ifdef USE_LIBPNG
|
||||
#define CODEC_PNG 0xFFFF0008
|
||||
#endif
|
||||
|
||||
const SValue g_pExtFileTypes[] =
|
||||
{
|
||||
{ L".BMP", WIC_CODEC_BMP },
|
||||
{ L".BMP", WIC_CODEC_BMP },
|
||||
#ifdef USE_LIBJPEG
|
||||
{ L".JPG", CODEC_JPEG },
|
||||
{ L".JPEG", CODEC_JPEG },
|
||||
#else
|
||||
{ L".JPG", WIC_CODEC_JPEG },
|
||||
{ L".JPEG", WIC_CODEC_JPEG },
|
||||
{ L".PNG", WIC_CODEC_PNG },
|
||||
{ L".DDS", CODEC_DDS },
|
||||
{ L".TGA", CODEC_TGA },
|
||||
{ L".HDR", CODEC_HDR },
|
||||
#endif
|
||||
#ifdef USE_LIBPNG
|
||||
{ L".PNG", CODEC_PNG },
|
||||
#else
|
||||
{ L".PNG", WIC_CODEC_PNG },
|
||||
#endif
|
||||
{ L".DDS", CODEC_DDS },
|
||||
{ L".TGA", CODEC_TGA },
|
||||
{ L".HDR", CODEC_HDR },
|
||||
{ L".TIF", WIC_CODEC_TIFF },
|
||||
{ L".TIFF", WIC_CODEC_TIFF },
|
||||
{ L".WDP", WIC_CODEC_WMP },
|
||||
{ L".HDP", WIC_CODEC_WMP },
|
||||
{ L".JXR", WIC_CODEC_WMP },
|
||||
#ifdef USE_OPENEXR
|
||||
{ L"EXR", CODEC_EXR },
|
||||
#endif
|
||||
{ nullptr, CODEC_DDS }
|
||||
{ L".WDP", WIC_CODEC_WMP },
|
||||
{ L".HDP", WIC_CODEC_WMP },
|
||||
{ L".JXR", WIC_CODEC_WMP },
|
||||
#ifdef USE_OPENEXR
|
||||
{ L".EXR", CODEC_EXR },
|
||||
#endif
|
||||
{ nullptr, CODEC_DDS }
|
||||
};
|
||||
|
||||
const SValue g_pFeatureLevels[] = // valid feature levels for -fl for maximimum size
|
||||
@ -833,10 +853,18 @@ namespace
|
||||
case CODEC_HDR:
|
||||
return SaveToHDRFile(img, szOutputFile);
|
||||
|
||||
#ifdef USE_OPENEXR
|
||||
#ifdef USE_OPENEXR
|
||||
case CODEC_EXR:
|
||||
return SaveToEXRFile(img, szOutputFile);
|
||||
#endif
|
||||
#endif
|
||||
#ifdef USE_LIBJPEG
|
||||
case CODEC_JPEG:
|
||||
return SaveToJPEGFile(img, szOutputFile);
|
||||
#endif
|
||||
#ifdef USE_LIBPNG
|
||||
case CODEC_PNG:
|
||||
return SaveToPNGFile(img, szOutputFile);
|
||||
#endif
|
||||
|
||||
default:
|
||||
{
|
||||
@ -1590,6 +1618,29 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_LIBJPEG
|
||||
else if (_wcsicmp(ext.c_str(), L".jpg") == 0 || _wcsicmp(ext.c_str(), L".jpeg") == 0)
|
||||
{
|
||||
hr = LoadFromJPEGFile(curpath.c_str(), &info, *image);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
wprintf(L" FAILED (%08X%ls)\n", static_cast<unsigned int>(hr), GetErrorDesc(hr));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_LIBPNG
|
||||
else if (_wcsicmp(ext.c_str(), L".png") == 0)
|
||||
{
|
||||
hr = LoadFromPNGFile(curpath.c_str(), &info, *image);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
wprintf(L" FAILED (%08X%ls)\n", static_cast<unsigned int>(hr), GetErrorDesc(hr));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
else
|
||||
{
|
||||
// WIC shares the same filter values for mode and dither
|
||||
|
@ -64,14 +64,19 @@
|
||||
|
||||
#include "DirectXPackedVector.h"
|
||||
|
||||
//Uncomment to add support for OpenEXR (.exr)
|
||||
//#define USE_OPENEXR
|
||||
|
||||
#ifdef USE_OPENEXR
|
||||
// See <https://github.com/Microsoft/DirectXTex/wiki/Adding-OpenEXR> for details
|
||||
#include "DirectXTexEXR.h"
|
||||
#endif
|
||||
|
||||
// See <https://github.com/Microsoft/DirectXTex/wiki/Using-JPEG-PNG-OSS> for details
|
||||
#ifdef USE_LIBJPEG
|
||||
#include "DirectXTexJPEG.h"
|
||||
#endif
|
||||
#ifdef USE_LIBPNG
|
||||
#include "DirectXTexPNG.h"
|
||||
#endif
|
||||
|
||||
using namespace DirectX;
|
||||
using namespace DirectX::PackedVector;
|
||||
using Microsoft::WRL::ComPtr;
|
||||
@ -456,14 +461,29 @@ namespace
|
||||
|
||||
#ifdef USE_OPENEXR
|
||||
#define CODEC_EXR 0xFFFF0008
|
||||
#endif
|
||||
#ifdef USE_LIBJPEG
|
||||
#define CODEC_JPEG 0xFFFF0009
|
||||
#endif
|
||||
#ifdef USE_LIBPNG
|
||||
#define CODEC_PNG 0xFFFF000A
|
||||
#endif
|
||||
|
||||
const SValue<uint32_t> g_pSaveFileTypes[] = // valid formats to write to
|
||||
{
|
||||
{ L"bmp", WIC_CODEC_BMP },
|
||||
#ifdef USE_LIBJPEG
|
||||
{ L"jpg", CODEC_JPEG },
|
||||
{ L"jpeg", CODEC_JPEG },
|
||||
#else
|
||||
{ L"jpg", WIC_CODEC_JPEG },
|
||||
{ L"jpeg", WIC_CODEC_JPEG },
|
||||
#endif
|
||||
#ifdef USE_LIBPNG
|
||||
{ L"png", CODEC_PNG },
|
||||
#else
|
||||
{ L"png", WIC_CODEC_PNG },
|
||||
#endif
|
||||
{ L"dds", CODEC_DDS },
|
||||
{ L"ddx", CODEC_DDS },
|
||||
{ L"tga", CODEC_TGA },
|
||||
@ -2212,6 +2232,30 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_LIBJPEG
|
||||
else if (_wcsicmp(ext.c_str(), L".jpg") == 0 || _wcsicmp(ext.c_str(), L".jpeg") == 0)
|
||||
{
|
||||
hr = LoadFromJPEGFile(curpath.c_str(), &info, *image);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
wprintf(L" FAILED (%08X%ls)\n", static_cast<unsigned int>(hr), GetErrorDesc(hr));
|
||||
retVal = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_LIBPNG
|
||||
else if (_wcsicmp(ext.c_str(), L".png") == 0)
|
||||
{
|
||||
hr = LoadFromPNGFile(curpath.c_str(), &info, *image);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
wprintf(L" FAILED (%08X%ls)\n", static_cast<unsigned int>(hr), GetErrorDesc(hr));
|
||||
retVal = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
@ -3803,6 +3847,16 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
|
||||
hr = SaveToEXRFile(img[0], destName.c_str());
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_LIBJPEG
|
||||
case CODEC_JPEG:
|
||||
hr = SaveToJPEGFile(img[0], destName.c_str());
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_LIBPNG
|
||||
case CODEC_PNG:
|
||||
hr = SaveToPNGFile(img[0], destName.c_str());
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
{
|
||||
|
@ -58,14 +58,19 @@
|
||||
|
||||
#include <DirectXPackedVector.h>
|
||||
|
||||
//Uncomment to add support for OpenEXR (.exr)
|
||||
//#define USE_OPENEXR
|
||||
|
||||
#ifdef USE_OPENEXR
|
||||
// See <https://github.com/Microsoft/DirectXTex/wiki/Adding-OpenEXR> for details
|
||||
#include "DirectXTexEXR.h"
|
||||
#endif
|
||||
|
||||
// See <https://github.com/Microsoft/DirectXTex/wiki/Using-JPEG-PNG-OSS> for details
|
||||
#ifdef USE_LIBJPEG
|
||||
#include "DirectXTexJPEG.h"
|
||||
#endif
|
||||
#ifdef USE_LIBPNG
|
||||
#include "DirectXTexPNG.h"
|
||||
#endif
|
||||
|
||||
using namespace DirectX;
|
||||
|
||||
enum COMMANDS : uint32_t
|
||||
@ -348,13 +353,28 @@ const SValue g_pFilters[] =
|
||||
#ifdef USE_OPENEXR
|
||||
#define CODEC_EXR 0xFFFF0006
|
||||
#endif
|
||||
#ifdef USE_LIBJPEG
|
||||
#define CODEC_JPEG 0xFFFF0007
|
||||
#endif
|
||||
#ifdef USE_LIBPNG
|
||||
#define CODEC_PNG 0xFFFF0008
|
||||
#endif
|
||||
|
||||
const SValue g_pDumpFileTypes[] =
|
||||
{
|
||||
{ L"bmp", WIC_CODEC_BMP },
|
||||
#ifdef USE_LIBJPEG
|
||||
{ L"jpg", CODEC_JPEG },
|
||||
{ L"jpeg", CODEC_JPEG },
|
||||
#else
|
||||
{ L"jpg", WIC_CODEC_JPEG },
|
||||
{ L"jpeg", WIC_CODEC_JPEG },
|
||||
#endif
|
||||
#ifdef USE_LIBPNG
|
||||
{ L"png", CODEC_PNG },
|
||||
#else
|
||||
{ L"png", WIC_CODEC_PNG },
|
||||
#endif
|
||||
{ L"tga", CODEC_TGA },
|
||||
{ L"hdr", CODEC_HDR },
|
||||
{ L"tif", WIC_CODEC_TIFF },
|
||||
@ -368,22 +388,31 @@ const SValue g_pDumpFileTypes[] =
|
||||
|
||||
const SValue g_pExtFileTypes[] =
|
||||
{
|
||||
{ L".bmp", WIC_CODEC_BMP },
|
||||
{ L".bmp", WIC_CODEC_BMP },
|
||||
#ifdef USE_LIBJPEG
|
||||
{ L".jpg", CODEC_JPEG },
|
||||
{ L".jpeg", CODEC_JPEG },
|
||||
#else
|
||||
{ L".jpg", WIC_CODEC_JPEG },
|
||||
{ L".jpeg", WIC_CODEC_JPEG },
|
||||
{ L".png", WIC_CODEC_PNG },
|
||||
{ L".dds", CODEC_DDS },
|
||||
{ L".tga", CODEC_TGA },
|
||||
{ L".hdr", CODEC_HDR },
|
||||
#endif
|
||||
#ifdef USE_LIBPNG
|
||||
{ L".png", CODEC_PNG },
|
||||
#else
|
||||
{ L".png", WIC_CODEC_PNG },
|
||||
#endif
|
||||
{ L".dds", CODEC_DDS },
|
||||
{ L".tga", CODEC_TGA },
|
||||
{ L".hdr", CODEC_HDR },
|
||||
{ L".tif", WIC_CODEC_TIFF },
|
||||
{ L".tiff", WIC_CODEC_TIFF },
|
||||
{ L".wdp", WIC_CODEC_WMP },
|
||||
{ L".hdp", WIC_CODEC_WMP },
|
||||
{ L".jxr", WIC_CODEC_WMP },
|
||||
{ L".wdp", WIC_CODEC_WMP },
|
||||
{ L".hdp", WIC_CODEC_WMP },
|
||||
{ L".jxr", WIC_CODEC_WMP },
|
||||
#ifdef USE_OPENEXR
|
||||
{ L"exr", CODEC_EXR },
|
||||
{ L"exr", CODEC_EXR },
|
||||
#endif
|
||||
{ nullptr, CODEC_DDS }
|
||||
{ nullptr, CODEC_DDS }
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
@ -813,6 +842,18 @@ namespace
|
||||
{
|
||||
return LoadFromEXRFile(fileName, &info, *image);
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_LIBJPEG
|
||||
else if (_wcsicmp(ext.c_str(), L".jpg") == 0 || _wcsicmp(ext.c_str(), L".jpeg") == 0)
|
||||
{
|
||||
return LoadFromJPEGFile(fileName, &info, *image);
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_LIBPNG
|
||||
else if (_wcsicmp(ext.c_str(), L".png") == 0)
|
||||
{
|
||||
return LoadFromPNGFile(fileName, &info, *image);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
@ -853,11 +894,18 @@ namespace
|
||||
case CODEC_HDR:
|
||||
return SaveToHDRFile(*image, fileName);
|
||||
|
||||
#ifdef USE_OPENEXR
|
||||
#ifdef USE_OPENEXR
|
||||
case CODEC_EXR:
|
||||
return SaveToEXRFile(*image, fileName);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#ifdef USE_LIBJPEG
|
||||
case CODEC_JPEG:
|
||||
return SaveToJPEGFile(*image, fileName);
|
||||
#endif
|
||||
#ifdef USE_LIBPNG
|
||||
case CODEC_PNG:
|
||||
return SaveToPNGFile(*image, fileName);
|
||||
#endif
|
||||
default:
|
||||
return SaveToWICFile(*image, WIC_FLAGS_NONE, GetWICCodec(static_cast<WICCodecs>(codec)), fileName);
|
||||
}
|
||||
|
@ -13,6 +13,16 @@ if(ENABLE_OPENEXR_SUPPORT)
|
||||
find_dependency(OpenEXR)
|
||||
endif()
|
||||
|
||||
set(ENABLE_LIBJPEG_SUPPORT @ENABLE_LIBJPEG_SUPPORT@)
|
||||
if(ENABLE_LIBJPEG_SUPPORT)
|
||||
find_dependency(JPEG)
|
||||
endif()
|
||||
|
||||
set(ENABLE_LIBPNG_SUPPORT @ENABLE_LIBPNG_SUPPORT@)
|
||||
if(ENABLE_LIBPNG_SUPPORT)
|
||||
find_dependency(PNG)
|
||||
endif()
|
||||
|
||||
if(MINGW OR (NOT WIN32))
|
||||
find_dependency(directx-headers)
|
||||
find_dependency(directxmath)
|
||||
|
Loading…
Reference in New Issue
Block a user