summaryrefslogtreecommitdiffstats
path: root/TextureLoader/src
diff options
context:
space:
mode:
authorassiduous <assiduous@diligentgraphics.com>2020-04-08 01:14:11 +0000
committerassiduous <assiduous@diligentgraphics.com>2020-04-08 01:14:11 +0000
commit0b7d07f841d8ed1f6da94a8f4a2900c2eff6355d (patch)
tree9102a5baca9316e363aa78fc7581d54dcfa9b821 /TextureLoader/src
parentMoved ImGuiScopedDisabler to ImGui namespace and renamed to ScopedDisabler (diff)
downloadDiligentTools-0b7d07f841d8ed1f6da94a8f4a2900c2eff6355d.tar.gz
DiligentTools-0b7d07f841d8ed1f6da94a8f4a2900c2eff6355d.zip
Reworked PNG and JPEG image decoding to fix incompatibility of setjmp with c++ destructors. Added JPEG and PNG encoding/decoding tests
Diffstat (limited to 'TextureLoader/src')
-rw-r--r--TextureLoader/src/Image.cpp465
-rw-r--r--TextureLoader/src/JPEGCodec.c278
-rw-r--r--TextureLoader/src/PNGCodec.c244
-rw-r--r--TextureLoader/src/TextureLoader.cpp62
-rw-r--r--TextureLoader/src/TextureUtilities.cpp6
-rw-r--r--TextureLoader/src/pch.cpp24
6 files changed, 629 insertions, 450 deletions
diff --git a/TextureLoader/src/Image.cpp b/TextureLoader/src/Image.cpp
index dff9eca..1f7331c 100644
--- a/TextureLoader/src/Image.cpp
+++ b/TextureLoader/src/Image.cpp
@@ -30,12 +30,13 @@
#include <algorithm>
#include <array>
-#include "Image.hpp"
+#include "Image.h"
#include "Errors.hpp"
#include "tiffio.h"
#include "png.h"
-#include "jpeglib.h"
+#include "PNGCodec.h"
+#include "JPEGCodec.h"
#include "DataBlobImpl.hpp"
#include "DebugUtilities.hpp"
@@ -217,273 +218,33 @@ void Image::LoadTiffFile(IDataBlob* pFileData, const ImageLoadInfo& LoadInfo)
}
-class PNGReadFnHelper
-{
-public:
- PNGReadFnHelper(IDataBlob* pData) :
- m_pData{pData},
- m_Offset{0}
- {
- }
-
- static void ReadData(png_structp pngPtr, png_bytep data, png_size_t length)
- {
- auto pThis = reinterpret_cast<PNGReadFnHelper*>(png_get_io_ptr(pngPtr));
- memcpy(data, reinterpret_cast<Uint8*>(pThis->m_pData->GetDataPtr()) + pThis->m_Offset, length);
- pThis->m_Offset += length;
- }
-
-private:
- RefCntAutoPtr<IDataBlob> m_pData;
- size_t m_Offset;
-};
-
-void Image::LoadPngFile(IDataBlob* pFileData, const ImageLoadInfo& LoadInfo)
-{
- // http://www.piko3d.net/tutorials/libpng-tutorial-loading-png-files-from-streams/
- // http://www.libpng.org/pub/png/book/chapter13.html#png.ch13.div.10
- // https://gist.github.com/niw/5963798
-
- PNGReadFnHelper ReadFnHelper(pFileData);
-
- const size_t PngSigSize = 8;
- png_const_bytep pngsig = reinterpret_cast<png_const_bytep>(pFileData->GetDataPtr());
- //Let LibPNG check the signature. If this function returns 0, everything is OK.
- if (png_sig_cmp(pngsig, 0, PngSigSize) != 0)
- {
- LOG_ERROR_AND_THROW("Invalid png signature");
- }
-
- png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
- VERIFY(png, "png_create_read_struct() failed");
-
- png_infop info = png_create_info_struct(png);
- VERIFY(info, "png_create_info_struct() failed");
-
- if (setjmp(png_jmpbuf(png)))
- {
- // When an error occurs during parsing, libPNG will jump to here
- png_destroy_read_struct(&png, &info, (png_infopp)0);
- LOG_ERROR_AND_THROW("Failed to read png file");
- }
-
- png_set_read_fn(png, (png_voidp)&ReadFnHelper, PNGReadFnHelper::ReadData);
-
- png_read_info(png, info);
-
- auto bit_depth = png_get_bit_depth(png, info);
-
- // PNG files store 16-bit pixels in network byte order (big-endian, ie
- // most significant bytes first). png_set_swap() shall switch the byte-order
- // to little-endian (ie, least significant bits first).
- if (bit_depth == 16)
- png_set_swap(png);
-
- auto color_type = png_get_color_type(png, info);
-
- // See http://www.libpng.org/pub/png/libpng-manual.txt
- if (color_type == PNG_COLOR_TYPE_PALETTE)
- {
- // Transform paletted images into 8-bit rgba
- png_set_palette_to_rgb(png);
- png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
- }
-
- // PNG_COLOR_TYPE_GRAY_ALPHA is always 8 or 16bit depth.
- if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
- {
- // Expand 1, 2, or 4-bit images to 8-bit
- png_set_expand_gray_1_2_4_to_8(png);
- }
-
- if (png_get_valid(png, info, PNG_INFO_tRNS))
- png_set_tRNS_to_alpha(png);
-
-#if 0
- // These color_type don't have an alpha channel then fill it with 0xff.
- if( color_type == PNG_COLOR_TYPE_RGB ||
- color_type == PNG_COLOR_TYPE_GRAY ||
- color_type == PNG_COLOR_TYPE_PALETTE )
- png_set_filler( png, 0xFF, PNG_FILLER_AFTER );
-
- if( color_type == PNG_COLOR_TYPE_GRAY ||
- color_type == PNG_COLOR_TYPE_GRAY_ALPHA )
- png_set_gray_to_rgb( png );
-#endif
-
- png_read_update_info(png, info);
-
- bit_depth = png_get_bit_depth(png, info);
- m_Desc.Width = png_get_image_width(png, info);
- m_Desc.Height = png_get_image_height(png, info);
- m_Desc.NumComponents = png_get_channels(png, info);
- switch (bit_depth)
- {
- case 8: m_Desc.ComponentType = VT_UINT8; break;
- case 16: m_Desc.ComponentType = VT_UINT16; break;
- case 32: m_Desc.ComponentType = VT_UINT32; break;
- default: LOG_ERROR_AND_THROW("Unsupported component bit depth: ", bit_depth, ". Only 8, 16 and 32-bit components are supported");
- }
-
- //Array of row pointers. One for every row.
- std::vector<png_bytep> rowPtrs(m_Desc.Height);
-
- //Alocate a buffer with enough space. Align stride to 4 bytes
- m_Desc.RowStride = Align(m_Desc.Width * static_cast<Uint32>(bit_depth) * m_Desc.NumComponents / 8u, 4u);
- m_pData->Resize(size_t{m_Desc.Height} * size_t{m_Desc.RowStride});
- for (size_t i = 0; i < m_Desc.Height; i++)
- rowPtrs[i] = reinterpret_cast<png_bytep>(m_pData->GetDataPtr()) + i * m_Desc.RowStride;
-
- //Read the imagedata and write it to the adresses pointed to
- //by rowptrs (in other words: our image databuffer)
- png_read_image(png, rowPtrs.data());
-
- png_destroy_read_struct(&png, &info, (png_infopp)0);
-}
-
-
-
-struct my_jpeg_error_mgr
-{
- jpeg_error_mgr pub;
- char padding[8];
- jmp_buf setjmp_buffer; // for return to caller
-};
-
-// Here's the routine that will replace the standard error_exit method:
-METHODDEF(void)
-my_error_exit(j_common_ptr cinfo)
-{
- // cinfo->err really points to a my_jpeg_error_mgr struct, so coerce pointer
- my_jpeg_error_mgr* myerr = (my_jpeg_error_mgr*)cinfo->err;
-
- /* Always display the message. */
- /* We could postpone this until after returning, if we chose. */
- (*cinfo->err->output_message)(cinfo);
-
- // Return control to the setjmp point
- longjmp(myerr->setjmp_buffer, 1);
-}
-
-void Image::LoadJpegFile(IDataBlob* pFileData, const ImageLoadInfo& LoadInfo)
-{
- // https://github.com/LuaDist/libjpeg/blob/master/example.c
-
- // This struct contains the JPEG decompression parameters and pointers to
- // working space (which is allocated as needed by the JPEG library).
- jpeg_decompress_struct cinfo;
-
- // We use our private extension JPEG error handler.
- // Note that this struct must live as long as the main JPEG parameter
- // struct, to avoid dangling-pointer problems.
- my_jpeg_error_mgr jerr;
-
- // Step 1: allocate and initialize JPEG decompression object
-
- // We set up the normal JPEG error routines, then override error_exit.
- cinfo.err = jpeg_std_error(&jerr.pub);
- jerr.pub.error_exit = my_error_exit;
- // Establish the setjmp return context for my_error_exit to use.
- if (setjmp(jerr.setjmp_buffer))
- {
- // If we get here, the JPEG code has signaled an error.
- // We need to clean up the JPEG object, close the input file, and return.
- jpeg_destroy_decompress(&cinfo);
- LOG_ERROR_AND_THROW("Failed to decompress JPEG image");
- }
- // Now we can initialize the JPEG decompression object.
- jpeg_create_decompress(&cinfo);
-
- // Step 2: specify data source
- jpeg_mem_src(&cinfo, reinterpret_cast<unsigned char*>(pFileData->GetDataPtr()), static_cast<unsigned long>(pFileData->GetSize()));
-
- // Step 3: read file parameters with jpeg_read_header()
- jpeg_read_header(&cinfo, TRUE);
- // We can ignore the return value from jpeg_read_header since
- // (a) suspension is not possible with the stdio data source, and
- // (b) we passed TRUE to reject a tables-only JPEG file as an error.
- // See libjpeg.txt for more info.
-
-
- // Step 4: set parameters for decompression
-
- // In this example, we don't need to change any of the defaults set by
- // jpeg_read_header(), so we do nothing here.
-
-
- // Step 5: Start decompressor
-
- jpeg_start_decompress(&cinfo);
- // We can ignore the return value since suspension is not possible
- // with the stdio data source.
-
- // We may need to do some setup of our own at this point before reading
- // the data. After jpeg_start_decompress() we have the correct scaled
- // output image dimensions available, as well as the output colormap
- // if we asked for color quantization.
-
- m_Desc.Width = cinfo.output_width;
- m_Desc.Height = cinfo.output_height;
- m_Desc.ComponentType = VT_UINT8;
- m_Desc.NumComponents = cinfo.output_components;
- m_Desc.RowStride = Align(m_Desc.Width * m_Desc.NumComponents, 4u);
-
- m_pData->Resize(size_t{m_Desc.RowStride} * size_t{m_Desc.Height});
- // Step 6: while (scan lines remain to be read)
- // jpeg_read_scanlines(...);
-
- // Here we use the library's state variable cinfo.output_scanline as the
- // loop counter, so that we don't have to keep track ourselves.
- while (cinfo.output_scanline < cinfo.output_height)
- {
- // jpeg_read_scanlines expects an array of pointers to scanlines.
- // Here the array is only one element long, but you could ask for
- // more than one scanline at a time if that's more convenient.
-
-
- auto* pDstScanline = reinterpret_cast<Uint8*>(m_pData->GetDataPtr()) + size_t{cinfo.output_scanline} * size_t{m_Desc.RowStride};
- JSAMPROW RowPtrs[] = {reinterpret_cast<JSAMPROW>(pDstScanline)};
- jpeg_read_scanlines(&cinfo, RowPtrs, 1);
- }
-
- // Step 7: Finish decompression
-
- jpeg_finish_decompress(&cinfo);
- // We can ignore the return value since suspension is not possible
- // with the stdio data source.
-
- // Step 8: Release JPEG decompression object
-
- // This is an important step since it will release a good deal of memory.
- jpeg_destroy_decompress(&cinfo);
-
- // At this point you may want to check to see whether any corrupt-data
- // warnings occurred (test whether jerr.pub.num_warnings is nonzero).
-}
-
Image::Image(IReferenceCounters* pRefCounters,
IDataBlob* pFileData,
const ImageLoadInfo& LoadInfo) :
TBase{pRefCounters},
m_pData{MakeNewRCObj<DataBlobImpl>()(0)}
{
- if (LoadInfo.Format == EImageFileFormat::tiff)
+ if (LoadInfo.Format == IMAGE_FILE_FORMAT_TIFF)
{
LoadTiffFile(pFileData, LoadInfo);
}
- else if (LoadInfo.Format == EImageFileFormat::png)
+ else if (LoadInfo.Format == IMAGE_FILE_FORMAT_PNG)
{
- LoadPngFile(pFileData, LoadInfo);
+ auto Res = DecodePng(pFileData, m_pData.RawPtr(), &m_Desc);
+ if (Res != DECODE_PNG_RESULT_OK)
+ LOG_ERROR_MESSAGE("Failed to decode png image");
}
- else if (LoadInfo.Format == EImageFileFormat::jpeg)
+ else if (LoadInfo.Format == IMAGE_FILE_FORMAT_JPEG)
{
- LoadJpegFile(pFileData, LoadInfo);
+ auto Res = DecodeJpeg(pFileData, m_pData.RawPtr(), &m_Desc);
+ if (Res != DECODE_JPEG_RESULT_OK)
+ LOG_ERROR_MESSAGE("Failed to decode jpeg image");
}
- else if (LoadInfo.Format == EImageFileFormat::dds)
+ else if (LoadInfo.Format == IMAGE_FILE_FORMAT_DDS)
{
LOG_ERROR_MESSAGE("An image can't be created from DDS file. Use CreateTextureFromFile() or CreateTextureFromDDS() functions.");
}
- else if (LoadInfo.Format == EImageFileFormat::ktx)
+ else if (LoadInfo.Format == IMAGE_FILE_FORMAT_KTX)
{
LOG_ERROR_MESSAGE("An image can't be created from KTX file. Use CreateTextureFromFile() or CreateTextureFromKTX() functions.");
}
@@ -502,151 +263,6 @@ void Image::CreateFromDataBlob(IDataBlob* pFileData,
}
-static void WritePng(const Uint8* pData, Uint32 Width, Uint32 Height, Uint32 Stride, int PngColorType, IDataBlob* pEncodedData)
-{
- struct PngWrapper
- {
- PngWrapper()
- {
- strct = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
- VERIFY(strct, "png_create_write_struct() failed");
- info = png_create_info_struct(strct);
- VERIFY(info, "png_create_info_struct() failed");
- }
-
- ~PngWrapper()
- {
- if (strct)
- {
- png_destroy_write_struct(&strct, &info);
- }
- }
-
- png_struct* strct = nullptr;
- png_info* info = nullptr;
- } Png;
-
- VERIFY(setjmp(png_jmpbuf(Png.strct)) == 0, "setjmp(png_jmpbuf(p) failed");
- png_set_IHDR(Png.strct, Png.info, Width, Height, 8,
- PngColorType,
- PNG_INTERLACE_NONE,
- PNG_COMPRESSION_TYPE_DEFAULT,
- PNG_FILTER_TYPE_DEFAULT);
- //png_set_compression_level(p, 1);
- std::vector<Uint8*> rows(Height);
- for (size_t y = 0; y < Height; ++y)
- rows[y] = const_cast<Uint8*>(pData) + y * Stride;
- png_set_rows(Png.strct, Png.info, rows.data());
-
- auto PngWriteCallback = [](png_structp png_ptr, png_bytep data, png_size_t length) {
- auto* pEncodedData = reinterpret_cast<IDataBlob*>(png_get_io_ptr(png_ptr));
- pEncodedData->Resize(pEncodedData->GetSize() + length);
- auto* pBytes = reinterpret_cast<Uint8*>(pEncodedData->GetDataPtr());
- memcpy(pBytes + pEncodedData->GetSize() - length, data, length);
- };
-
- png_set_write_fn(Png.strct, pEncodedData, PngWriteCallback, NULL);
- png_write_png(Png.strct, Png.info, PNG_TRANSFORM_IDENTITY, NULL);
-}
-
-static void WriteJPEG(JSAMPLE* pRGBData, Uint32 Width, Uint32 Height, int quality, IDataBlob* pEncodedData)
-{
- /* This struct contains the JPEG compression parameters and pointers to
- * working space (which is allocated as needed by the JPEG library).
- * It is possible to have several such structures, representing multiple
- * compression/decompression processes, in existence at once. We refer
- * to any one struct (and its associated working data) as a "JPEG object".
- */
- jpeg_compress_struct cinfo;
-
- /* This struct represents a JPEG error handler. It is declared separately
- * because applications often want to supply a specialized error handler
- * (see the second half of this file for an example). But here we just
- * take the easy way out and use the standard error handler, which will
- * print a message on stderr and call exit() if compression fails.
- * Note that this struct must live as long as the main JPEG parameter
- * struct, to avoid dangling-pointer problems.
- */
- jpeg_error_mgr jerr;
-
- /* Step 1: allocate and initialize JPEG compression object */
-
- /* We have to set up the error handler first, in case the initialization
- * step fails. (Unlikely, but it could happen if you are out of memory.)
- * This routine fills in the contents of struct jerr, and returns jerr's
- * address which we place into the link field in cinfo.
- */
- cinfo.err = jpeg_std_error(&jerr);
- /* Now we can initialize the JPEG compression object. */
- jpeg_create_compress(&cinfo);
-
- /* Step 2: specify data destination (memory) */
- /* Note: steps 2 and 3 can be done in either order. */
- unsigned char* mem = NULL;
- unsigned long mem_size = 0;
- jpeg_mem_dest(&cinfo, &mem, &mem_size);
-
- /* Step 3: set parameters for compression */
-
- /* First we supply a description of the input image.
- * Four fields of the cinfo struct must be filled in:
- */
- cinfo.image_width = Width; /* image width and height, in pixels */
- cinfo.image_height = Height;
- cinfo.input_components = 3; /* # of color components per pixel */
- cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
- /* Now use the library's routine to set default compression parameters.
- * (You must set at least cinfo.in_color_space before calling this,
- * since the defaults depend on the source color space.)
- */
- jpeg_set_defaults(&cinfo);
- /* Now you can set any non-default parameters you wish to.
- * Here we just illustrate the use of quality (quantization table) scaling:
- */
- jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
-
- /* Step 4: Start compressor */
-
- /* TRUE ensures that we will write a complete interchange-JPEG file.
- * Pass TRUE unless you are very sure of what you're doing.
- */
- jpeg_start_compress(&cinfo, TRUE);
-
- /* Step 5: while (scan lines remain to be written) */
- /* jpeg_write_scanlines(...); */
-
- /* Here we use the library's state variable cinfo.next_scanline as the
- * loop counter, so that we don't have to keep track ourselves.
- * To keep things simple, we pass one scanline per call; you can pass
- * more if you wish, though.
- */
- auto row_stride = Width * 3; /* JSAMPLEs per row in image_buffer */
-
- while (cinfo.next_scanline < cinfo.image_height)
- {
- /* jpeg_write_scanlines expects an array of pointers to scanlines.
- * Here the array is only one element long, but you could pass
- * more than one scanline at a time if that's more convenient.
- */
- JSAMPROW row_pointer[1] = {&pRGBData[cinfo.next_scanline * row_stride]};
- jpeg_write_scanlines(&cinfo, row_pointer, 1);
- }
-
- /* Step 6: Finish compression */
- jpeg_finish_compress(&cinfo);
-
- pEncodedData->Resize(mem_size);
- memcpy(pEncodedData->GetDataPtr(), mem, mem_size);
-
- /* After finish_compress, we can free memory buffer. */
- free(mem);
-
- /* Step 7: release JPEG compression object */
-
- /* This is an important step since it will release a good deal of memory. */
- jpeg_destroy_compress(&cinfo);
-}
-
static const std::array<Uint8, 4> GetRGBAOffsets(TEXTURE_FORMAT Format)
{
switch (Format)
@@ -701,12 +317,15 @@ std::vector<Uint8> Image::ConvertImageData(Uint32 Width,
void Image::Encode(const EncodeInfo& Info, IDataBlob** ppEncodedData)
{
RefCntAutoPtr<IDataBlob> pEncodedData(MakeNewRCObj<DataBlobImpl>()(0));
- if (Info.FileFormat == EImageFileFormat::jpeg)
+ if (Info.FileFormat == IMAGE_FILE_FORMAT_JPEG)
{
auto RGBData = ConvertImageData(Info.Width, Info.Height, reinterpret_cast<const Uint8*>(Info.pData), Info.Stride, Info.TexFormat, TEX_FORMAT_RGBA8_UNORM, false);
- WriteJPEG(RGBData.data(), Info.Width, Info.Height, Info.JpegQuality, pEncodedData);
+
+ auto Res = EncodeJpeg(RGBData.data(), Info.Width, Info.Height, Info.JpegQuality, pEncodedData.RawPtr());
+ if (Res != ENCODE_JPEG_RESULT_OK)
+ LOG_ERROR_MESSAGE("Failed to encode jpeg file");
}
- else if (Info.FileFormat == EImageFileFormat::png)
+ else if (Info.FileFormat == IMAGE_FILE_FORMAT_PNG)
{
const auto* pData = reinterpret_cast<const Uint8*>(Info.pData);
auto Stride = Info.Stride;
@@ -718,7 +337,9 @@ void Image::Encode(const EncodeInfo& Info, IDataBlob** ppEncodedData)
Stride = Info.Width * (Info.KeepAlpha ? 4 : 3);
}
- WritePng(pData, Info.Width, Info.Height, Stride, Info.KeepAlpha ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB, pEncodedData);
+ auto Res = EncodePng(pData, Info.Width, Info.Height, Stride, Info.KeepAlpha ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB, pEncodedData.RawPtr());
+ if (Res != ENCODE_PNG_RESULT_OK)
+ LOG_ERROR_MESSAGE("Failed to encode png file");
}
else
{
@@ -727,42 +348,42 @@ void Image::Encode(const EncodeInfo& Info, IDataBlob** ppEncodedData)
pEncodedData->QueryInterface(IID_DataBlob, reinterpret_cast<IObject**>(ppEncodedData));
}
-EImageFileFormat Image::GetFileFormat(const Uint8* pData, size_t Size)
+IMAGE_FILE_FORMAT Image::GetFileFormat(const Uint8* pData, size_t Size)
{
if (Size >= 3 && pData[0] == 0xFF && pData[1] == 0xD8 && pData[2] == 0xFF)
- return EImageFileFormat::jpeg;
+ return IMAGE_FILE_FORMAT_JPEG;
if (Size >= 8 &&
pData[0] == 0x89 && pData[1] == 0x50 && pData[2] == 0x4E && pData[3] == 0x47 &&
pData[4] == 0x0D && pData[5] == 0x0A && pData[6] == 0x1A && pData[7] == 0x0A)
- return EImageFileFormat::png;
+ return IMAGE_FILE_FORMAT_PNG;
if (Size >= 4 &&
((pData[0] == 0x49 && pData[1] == 0x20 && pData[2] == 0x49) ||
(pData[0] == 0x49 && pData[1] == 0x49 && pData[2] == 0x2A && pData[3] == 0x00) ||
(pData[0] == 0x4D && pData[1] == 0x4D && pData[2] == 0x00 && pData[3] == 0x2A) ||
(pData[0] == 0x4D && pData[1] == 0x4D && pData[2] == 0x00 && pData[3] == 0x2B)))
- return EImageFileFormat::tiff;
+ return IMAGE_FILE_FORMAT_TIFF;
if (Size >= 4 && pData[0] == 0x44 && pData[1] == 0x44 && pData[2] == 0x53 && pData[3] == 0x20)
- return EImageFileFormat::dds;
+ return IMAGE_FILE_FORMAT_DDS;
static constexpr Uint8 KTX10FileIdentifier[12] = {0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A};
static constexpr Uint8 KTX20FileIdentifier[12] = {0xAB, 0x4B, 0x54, 0x58, 0x20, 0x32, 0x30, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A};
if (Size >= 12 &&
(memcmp(pData, KTX10FileIdentifier, sizeof(KTX10FileIdentifier)) == 0 ||
memcmp(pData, KTX20FileIdentifier, sizeof(KTX20FileIdentifier)) == 0))
- return EImageFileFormat::ktx;
+ return IMAGE_FILE_FORMAT_KTX;
- return EImageFileFormat::unknown;
+ return IMAGE_FILE_FORMAT_UNKNOWN;
}
-EImageFileFormat CreateImageFromFile(const Char* FilePath,
- Image** ppImage,
- IDataBlob** ppRawData)
+IMAGE_FILE_FORMAT CreateImageFromFile(const Char* FilePath,
+ Image** ppImage,
+ IDataBlob** ppRawData)
{
- EImageFileFormat ImgFileFormat = EImageFileFormat::unknown;
+ auto ImgFileFormat = IMAGE_FILE_FORMAT_UNKNOWN;
try
{
RefCntAutoPtr<BasicFileStream> pFileStream(MakeNewRCObj<BasicFileStream>()(FilePath, EFileAccessMode::Read));
@@ -773,7 +394,7 @@ EImageFileFormat CreateImageFromFile(const Char* FilePath,
pFileStream->ReadBlob(pFileData);
ImgFileFormat = Image::GetFileFormat(reinterpret_cast<Uint8*>(pFileData->GetDataPtr()), pFileData->GetSize());
- if (ImgFileFormat == EImageFileFormat::unknown)
+ if (ImgFileFormat == IMAGE_FILE_FORMAT_UNKNOWN)
{
LOG_WARNING_MESSAGE("Unable to derive image format from the header for file \"", FilePath, "\". Trying to analyze extension.");
@@ -788,22 +409,22 @@ EImageFileFormat CreateImageFromFile(const Char* FilePath,
String Extension = StrToLower(pExtension);
if (Extension == "png")
- ImgFileFormat = EImageFileFormat::png;
+ ImgFileFormat = IMAGE_FILE_FORMAT_PNG;
else if (Extension == "jpeg" || Extension == "jpg")
- ImgFileFormat = EImageFileFormat::jpeg;
+ ImgFileFormat = IMAGE_FILE_FORMAT_JPEG;
else if (Extension == "tiff" || Extension == "tif")
- ImgFileFormat = EImageFileFormat::tiff;
+ ImgFileFormat = IMAGE_FILE_FORMAT_TIFF;
else if (Extension == "dds")
- ImgFileFormat = EImageFileFormat::dds;
+ ImgFileFormat = IMAGE_FILE_FORMAT_DDS;
else if (Extension == "ktx")
- ImgFileFormat = EImageFileFormat::ktx;
+ ImgFileFormat = IMAGE_FILE_FORMAT_KTX;
else
LOG_ERROR_AND_THROW("Unsupported file format ", Extension);
}
- if (ImgFileFormat == EImageFileFormat::png ||
- ImgFileFormat == EImageFileFormat::jpeg ||
- ImgFileFormat == EImageFileFormat::tiff)
+ if (ImgFileFormat == IMAGE_FILE_FORMAT_PNG ||
+ ImgFileFormat == IMAGE_FILE_FORMAT_JPEG ||
+ ImgFileFormat == IMAGE_FILE_FORMAT_TIFF)
{
ImageLoadInfo ImgLoadInfo;
ImgLoadInfo.Format = ImgFileFormat;
diff --git a/TextureLoader/src/JPEGCodec.c b/TextureLoader/src/JPEGCodec.c
new file mode 100644
index 0000000..d5398a5
--- /dev/null
+++ b/TextureLoader/src/JPEGCodec.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2019-2020 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <setjmp.h>
+#include <stdio.h>
+
+#include "jpeglib.h"
+
+#include "JPEGCodec.h"
+
+
+struct my_jpeg_error_mgr
+{
+ struct jpeg_error_mgr pub;
+ char padding[8];
+ jmp_buf setjmp_buffer; // for return to caller
+};
+typedef struct my_jpeg_error_mgr my_jpeg_error_mgr;
+
+// Here's the routine that will replace the standard error_exit method:
+METHODDEF(void)
+my_error_exit(j_common_ptr cinfo)
+{
+ // cinfo->err really points to a my_jpeg_error_mgr struct, so coerce pointer
+ my_jpeg_error_mgr* myerr = (my_jpeg_error_mgr*)cinfo->err;
+
+ /* Always display the message. */
+ /* We could postpone this until after returning, if we chose. */
+ (*cinfo->err->output_message)(cinfo);
+
+ // Return control to the setjmp point
+ longjmp(myerr->setjmp_buffer, 1);
+}
+
+DECODE_JPEG_RESULT Diligent_DecodeJpeg(IDataBlob* pSrcJpegBits,
+ IDataBlob* pDstPixels,
+ ImageDesc* pDstImgDesc)
+{
+ if (!pSrcJpegBits || !pDstPixels || !pDstImgDesc)
+ return DECODE_JPEG_RESULT_INVALID_ARGUMENTS;
+
+ // https://github.com/LuaDist/libjpeg/blob/master/example.c
+
+ // This struct contains the JPEG decompression parameters and pointers to
+ // working space (which is allocated as needed by the JPEG library).
+ struct jpeg_decompress_struct cinfo;
+
+ // We use our private extension JPEG error handler.
+ // Note that this struct must live as long as the main JPEG parameter
+ // struct, to avoid dangling-pointer problems.
+ my_jpeg_error_mgr jerr;
+
+ // Step 1: allocate and initialize JPEG decompression object
+
+ // We set up the normal JPEG error routines, then override error_exit.
+ cinfo.err = jpeg_std_error(&jerr.pub);
+ jerr.pub.error_exit = my_error_exit;
+ // Establish the setjmp return context for my_error_exit to use.
+ if (setjmp(jerr.setjmp_buffer))
+ {
+ // If we get here, the JPEG code has signaled an error.
+ // We need to clean up the JPEG object, close the input file, and return.
+ jpeg_destroy_decompress(&cinfo);
+ return DECODE_JPEG_RESULT_INITIALIZATION_FAILED;
+ }
+
+ // Now we can initialize the JPEG decompression object.
+ jpeg_create_decompress(&cinfo);
+
+ // Step 2: specify data source
+ unsigned char* pSrcPtr = IDataBlob_GetDataPtr(pSrcJpegBits);
+ unsigned long SrcSize = (unsigned long)IDataBlob_GetSize(pSrcJpegBits);
+ jpeg_mem_src(&cinfo, pSrcPtr, SrcSize);
+
+ // Step 3: read file parameters with jpeg_read_header()
+ jpeg_read_header(&cinfo, TRUE);
+ // We can ignore the return value from jpeg_read_header since
+ // (a) suspension is not possible with the stdio data source, and
+ // (b) we passed TRUE to reject a tables-only JPEG file as an error.
+ // See libjpeg.txt for more info.
+
+
+ // Step 4: set parameters for decompression
+
+ // In this example, we don't need to change any of the defaults set by
+ // jpeg_read_header(), so we do nothing here.
+
+
+ // Step 5: Start decompressor
+
+ jpeg_start_decompress(&cinfo);
+ // We can ignore the return value since suspension is not possible
+ // with the stdio data source.
+
+ // We may need to do some setup of our own at this point before reading
+ // the data. After jpeg_start_decompress() we have the correct scaled
+ // output image dimensions available, as well as the output colormap
+ // if we asked for color quantization.
+
+ pDstImgDesc->Width = cinfo.output_width;
+ pDstImgDesc->Height = cinfo.output_height;
+ pDstImgDesc->ComponentType = VT_UINT8;
+ pDstImgDesc->NumComponents = cinfo.output_components;
+ pDstImgDesc->RowStride = pDstImgDesc->Width * pDstImgDesc->NumComponents;
+ pDstImgDesc->RowStride = (pDstImgDesc->RowStride + 3u) & ~3u;
+
+ IDataBlob_Resize(pDstPixels, pDstImgDesc->RowStride * pDstImgDesc->Height);
+ // Step 6: while (scan lines remain to be read)
+ // jpeg_read_scanlines(...);
+
+ // Here we use the library's state variable cinfo.output_scanline as the
+ // loop counter, so that we don't have to keep track ourselves.
+ while (cinfo.output_scanline < cinfo.output_height)
+ {
+ // jpeg_read_scanlines expects an array of pointers to scanlines.
+ // Here the array is only one element long, but you could ask for
+ // more than one scanline at a time if that's more convenient.
+
+ Uint8* pScanline0 = IDataBlob_GetDataPtr(pDstPixels);
+ Uint8* pDstScanline = pScanline0 + cinfo.output_scanline * pDstImgDesc->RowStride;
+ JSAMPROW RowPtrs[1];
+ RowPtrs[0] = (JSAMPROW)pDstScanline;
+ jpeg_read_scanlines(&cinfo, RowPtrs, 1);
+ }
+
+ // Step 7: Finish decompression
+
+ jpeg_finish_decompress(&cinfo);
+ // We can ignore the return value since suspension is not possible
+ // with the stdio data source.
+
+ // Step 8: Release JPEG decompression object
+
+ // This is an important step since it will release a good deal of memory.
+ jpeg_destroy_decompress(&cinfo);
+
+ // At this point you may want to check to see whether any corrupt-data
+ // warnings occurred (test whether jerr.pub.num_warnings is nonzero).
+
+ return DECODE_JPEG_RESULT_OK;
+}
+
+
+
+ENCODE_JPEG_RESULT Diligent_EncodeJpeg(Uint8* pSrcRGBPixels,
+ Uint32 Width,
+ Uint32 Height,
+ int quality,
+ IDataBlob* pDstJpegBits)
+{
+ if (!pSrcRGBPixels || !pDstJpegBits || quality < 0 || Width == 0 || Height == 0)
+ return ENCODE_JPEG_RESULT_INVALID_ARGUMENTS;
+
+ /* This struct contains the JPEG compression parameters and pointers to
+ * working space (which is allocated as needed by the JPEG library).
+ * It is possible to have several such structures, representing multiple
+ * compression/decompression processes, in existence at once. We refer
+ * to any one struct (and its associated working data) as a "JPEG object".
+ */
+ struct jpeg_compress_struct cinfo;
+
+ /* This struct represents a JPEG error handler. It is declared separately
+ * because applications often want to supply a specialized error handler
+ * (see the second half of this file for an example). But here we just
+ * take the easy way out and use the standard error handler, which will
+ * print a message on stderr and call exit() if compression fails.
+ * Note that this struct must live as long as the main JPEG parameter
+ * struct, to avoid dangling-pointer problems.
+ */
+ struct jpeg_error_mgr jerr;
+
+ /* Step 1: allocate and initialize JPEG compression object */
+
+ /* We have to set up the error handler first, in case the initialization
+ * step fails. (Unlikely, but it could happen if you are out of memory.)
+ * This routine fills in the contents of struct jerr, and returns jerr's
+ * address which we place into the link field in cinfo.
+ */
+ cinfo.err = jpeg_std_error(&jerr);
+ /* Now we can initialize the JPEG compression object. */
+ jpeg_create_compress(&cinfo);
+
+ /* Step 2: specify data destination (memory) */
+ /* Note: steps 2 and 3 can be done in either order. */
+ unsigned char* mem = NULL;
+ unsigned long mem_size = 0;
+ jpeg_mem_dest(&cinfo, &mem, &mem_size);
+
+ /* Step 3: set parameters for compression */
+
+ /* First we supply a description of the input image.
+ * Four fields of the cinfo struct must be filled in:
+ */
+ cinfo.image_width = Width; /* image width and height, in pixels */
+ cinfo.image_height = Height;
+ cinfo.input_components = 3; /* # of color components per pixel */
+ cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
+ /* Now use the library's routine to set default compression parameters.
+ * (You must set at least cinfo.in_color_space before calling this,
+ * since the defaults depend on the source color space.)
+ */
+ jpeg_set_defaults(&cinfo);
+ /* Now you can set any non-default parameters you wish to.
+ * Here we just illustrate the use of quality (quantization table) scaling:
+ */
+ jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
+
+ /* Step 4: Start compressor */
+
+ /* TRUE ensures that we will write a complete interchange-JPEG file.
+ * Pass TRUE unless you are very sure of what you're doing.
+ */
+ jpeg_start_compress(&cinfo, TRUE);
+
+ /* Step 5: while (scan lines remain to be written) */
+ /* jpeg_write_scanlines(...); */
+
+ /* Here we use the library's state variable cinfo.next_scanline as the
+ * loop counter, so that we don't have to keep track ourselves.
+ * To keep things simple, we pass one scanline per call; you can pass
+ * more if you wish, though.
+ */
+ Uint32 row_stride = Width * 3; /* JSAMPLEs per row in image_buffer */
+
+ while (cinfo.next_scanline < cinfo.image_height)
+ {
+ /* jpeg_write_scanlines expects an array of pointers to scanlines.
+ * Here the array is only one element long, but you could pass
+ * more than one scanline at a time if that's more convenient.
+ */
+ JSAMPROW row_pointer[1];
+ row_pointer[0] = &pSrcRGBPixels[cinfo.next_scanline * row_stride];
+ jpeg_write_scanlines(&cinfo, row_pointer, 1);
+ }
+
+ /* Step 6: Finish compression */
+ jpeg_finish_compress(&cinfo);
+
+ IDataBlob_Resize(pDstJpegBits, mem_size);
+ void* pDstPtr = IDataBlob_GetDataPtr(pDstJpegBits);
+ memcpy(pDstPtr, mem, mem_size);
+
+ /* After finish_compress, we can free memory buffer. */
+ free(mem);
+
+ /* Step 7: release JPEG compression object */
+
+ /* This is an important step since it will release a good deal of memory. */
+ jpeg_destroy_compress(&cinfo);
+
+ return ENCODE_JPEG_RESULT_OK;
+}
diff --git a/TextureLoader/src/PNGCodec.c b/TextureLoader/src/PNGCodec.c
new file mode 100644
index 0000000..96a3046
--- /dev/null
+++ b/TextureLoader/src/PNGCodec.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2019-2020 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "png.h"
+#include "GraphicsTypes.h"
+
+#include "PNGCodec.h"
+
+struct PNGReadFnState
+{
+ IDataBlob* pPngBits;
+ size_t Offset;
+};
+typedef struct PNGReadFnState PNGReadFnState;
+
+static void PngReadCallback(png_structp pngPtr, png_bytep data, png_size_t length)
+{
+ PNGReadFnState* pState = (PNGReadFnState*)(png_get_io_ptr(pngPtr));
+ Uint8* pDstPtr = (Uint8*)IDataBlob_GetDataPtr(pState->pPngBits) + pState->Offset;
+ memcpy(data, pDstPtr, length);
+ pState->Offset += length;
+}
+
+DECODE_PNG_RESULT Diligent_DecodePng(IDataBlob* pSrcPngBits,
+ IDataBlob* pDstPixels,
+ ImageDesc* pDstImgDesc)
+{
+ if (!pSrcPngBits || !pDstPixels || !pDstImgDesc)
+ return DECODE_PNG_RESULT_INVALID_ARGUMENTS;
+
+ // http://www.piko3d.net/tutorials/libpng-tutorial-loading-png-files-from-streams/
+ // http://www.libpng.org/pub/png/book/chapter13.html#png.ch13.div.10
+ // https://gist.github.com/niw/5963798
+
+ const size_t PngSigSize = 8;
+ png_const_bytep pngsig = (png_const_bytep)IDataBlob_GetDataPtr(pSrcPngBits);
+ //Let LibPNG check the signature. If this function returns 0, everything is OK.
+ if (png_sig_cmp(pngsig, 0, PngSigSize) != 0)
+ {
+ return DECODE_PNG_RESULT_INVALID_SIGNATURE;
+ }
+
+ png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (!png)
+ {
+ return DECODE_PNG_RESULT_INITIALIZATION_FAILED;
+ }
+
+ png_infop info = png_create_info_struct(png);
+ if (!info)
+ {
+ png_destroy_read_struct(&png, &info, (png_infopp)0);
+ return DECODE_PNG_RESULT_INITIALIZATION_FAILED;
+ }
+
+ png_bytep* rowPtrs = NULL;
+ if (setjmp(png_jmpbuf(png)))
+ {
+ if (rowPtrs)
+ free(rowPtrs);
+ // When an error occurs during parsing, libPNG will jump to here
+ png_destroy_read_struct(&png, &info, (png_infopp)0);
+ return DECODE_PNG_RESULT_DECODING_ERROR;
+ }
+
+ PNGReadFnState ReadState;
+ ReadState.pPngBits = pSrcPngBits;
+ ReadState.Offset = 0;
+
+ png_set_read_fn(png, (png_voidp)&ReadState, PngReadCallback);
+
+ png_read_info(png, info);
+
+ png_byte bit_depth = png_get_bit_depth(png, info);
+
+ // PNG files store 16-bit pixels in network byte order (big-endian, ie
+ // most significant bytes first). png_set_swap() shall switch the byte-order
+ // to little-endian (ie, least significant bits first).
+ if (bit_depth == 16)
+ png_set_swap(png);
+
+ png_byte color_type = png_get_color_type(png, info);
+
+ // See http://www.libpng.org/pub/png/libpng-manual.txt
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ // Transform paletted images into 8-bit rgba
+ png_set_palette_to_rgb(png);
+ png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
+ }
+
+ // PNG_COLOR_TYPE_GRAY_ALPHA is always 8 or 16bit depth.
+ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
+ {
+ // Expand 1, 2, or 4-bit images to 8-bit
+ png_set_expand_gray_1_2_4_to_8(png);
+ }
+
+ if (png_get_valid(png, info, PNG_INFO_tRNS))
+ png_set_tRNS_to_alpha(png);
+
+#if 0
+ // These color_type don't have an alpha channel then fill it with 0xff.
+ if( color_type == PNG_COLOR_TYPE_RGB ||
+ color_type == PNG_COLOR_TYPE_GRAY ||
+ color_type == PNG_COLOR_TYPE_PALETTE )
+ png_set_filler( png, 0xFF, PNG_FILLER_AFTER );
+
+ if( color_type == PNG_COLOR_TYPE_GRAY ||
+ color_type == PNG_COLOR_TYPE_GRAY_ALPHA )
+ png_set_gray_to_rgb( png );
+#endif
+
+ png_read_update_info(png, info);
+
+ bit_depth = png_get_bit_depth(png, info);
+ pDstImgDesc->Width = png_get_image_width(png, info);
+ pDstImgDesc->Height = png_get_image_height(png, info);
+ pDstImgDesc->NumComponents = png_get_channels(png, info);
+ switch (bit_depth)
+ {
+ case 8: pDstImgDesc->ComponentType = VT_UINT8; break;
+ case 16: pDstImgDesc->ComponentType = VT_UINT16; break;
+ case 32: pDstImgDesc->ComponentType = VT_UINT32; break;
+ default:
+ {
+ png_destroy_read_struct(&png, &info, (png_infopp)0);
+ return DECODE_PNG_RESULT_INVALID_BIT_DEPTH;
+ }
+ }
+
+ //Array of row pointers. One for every row.
+ rowPtrs = malloc(sizeof(png_bytep) * pDstImgDesc->Height);
+
+ //Alocate a buffer with enough space.
+ pDstImgDesc->RowStride = pDstImgDesc->Width * (Uint32)bit_depth * pDstImgDesc->NumComponents / 8u;
+ // Align stride to 4 bytes
+ pDstImgDesc->RowStride = (pDstImgDesc->RowStride + 3u) & ~3u;
+
+ IDataBlob_Resize(pDstPixels, pDstImgDesc->Height * pDstImgDesc->RowStride);
+ png_bytep pRow0 = IDataBlob_GetDataPtr(pDstPixels);
+ for (size_t i = 0; i < pDstImgDesc->Height; i++)
+ rowPtrs[i] = pRow0 + i * pDstImgDesc->RowStride;
+
+ //Read the imagedata and write it to the adresses pointed to
+ //by rowptrs (in other words: our image databuffer)
+ png_read_image(png, rowPtrs);
+
+ free(rowPtrs);
+ png_destroy_read_struct(&png, &info, (png_infopp)0);
+
+ return DECODE_PNG_RESULT_OK;
+}
+
+static void PngWriteCallback(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ IDataBlob* pEncodedData = (IDataBlob*)png_get_io_ptr(png_ptr);
+ size_t PrevSize = IDataBlob_GetSize(pEncodedData);
+ IDataBlob_Resize(pEncodedData, PrevSize + length);
+ Uint8* pBytes = (Uint8*)IDataBlob_GetDataPtr(pEncodedData);
+ memcpy(pBytes + PrevSize, data, length);
+}
+
+ENCODE_PNG_RESULT Diligent_EncodePng(const Uint8* pSrcPixels,
+ Uint32 Width,
+ Uint32 Height,
+ Uint32 StrideInBytes,
+ int PngColorType,
+ IDataBlob* pDstPngBits)
+{
+ if (!pSrcPixels || !pDstPngBits || Width == 0 || Height == 0 || StrideInBytes == 0)
+ return ENCODE_PNG_RESULT_INVALID_ARGUMENTS;
+
+ png_struct* strct = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (!strct)
+ {
+ return ENCODE_PNG_RESULT_INITIALIZATION_FAILED;
+ }
+
+ png_info* info = png_create_info_struct(strct);
+ if (!info)
+ {
+ png_destroy_write_struct(&strct, &info);
+ return ENCODE_PNG_RESULT_INITIALIZATION_FAILED;
+ }
+
+ png_bytep* rowPtrs = NULL;
+ if (setjmp(png_jmpbuf(strct)) != 0)
+ {
+ if (rowPtrs)
+ free(rowPtrs);
+ png_destroy_write_struct(&strct, &info);
+ return ENCODE_PNG_RESULT_INITIALIZATION_FAILED;
+ }
+
+ png_set_IHDR(strct, info, Width, Height, 8,
+ PngColorType,
+ PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_DEFAULT,
+ PNG_FILTER_TYPE_DEFAULT);
+
+ //png_set_compression_level(p, 1);
+ rowPtrs = malloc(sizeof(png_bytep) * Height);
+ for (size_t y = 0; y < Height; ++y)
+ rowPtrs[y] = (Uint8*)pSrcPixels + y * StrideInBytes;
+
+ png_set_rows(strct, info, rowPtrs);
+
+ png_set_write_fn(strct, pDstPngBits, PngWriteCallback, NULL);
+ png_write_png(strct, info, PNG_TRANSFORM_IDENTITY, NULL);
+
+ free(rowPtrs);
+
+ png_destroy_write_struct(&strct, &info);
+
+ return ENCODE_PNG_RESULT_OK;
+}
diff --git a/TextureLoader/src/TextureLoader.cpp b/TextureLoader/src/TextureLoader.cpp
index 2665b5e..3f5d63d 100644
--- a/TextureLoader/src/TextureLoader.cpp
+++ b/TextureLoader/src/TextureLoader.cpp
@@ -34,8 +34,34 @@
#include "TextureLoader.h"
#include "GraphicsAccessories.hpp"
#include "DDSLoader.h"
+#include "PNGCodec.h"
+#include "JPEGCodec.h"
#include "ColorConversion.h"
-#include "Image.hpp"
+#include "Image.h"
+
+extern "C"
+{
+ Diligent::DECODE_PNG_RESULT Diligent_DecodePng(Diligent::IDataBlob* pSrcPngBits,
+ Diligent::IDataBlob* pDstPixels,
+ Diligent::ImageDesc* pDstImgDesc);
+
+ Diligent::ENCODE_PNG_RESULT Diligent_EncodePng(const Diligent::Uint8* pSrcPixels,
+ Diligent::Uint32 Width,
+ Diligent::Uint32 Height,
+ Diligent::Uint32 StrideInBytes,
+ int PngColorType,
+ Diligent::IDataBlob* pDstPngBits);
+
+ Diligent::DECODE_JPEG_RESULT Diligent_DecodeJpeg(Diligent::IDataBlob* pSrcJpegBits,
+ Diligent::IDataBlob* pDstPixels,
+ Diligent::ImageDesc* pDstImgDesc);
+
+ Diligent::ENCODE_JPEG_RESULT Diligent_EncodeJpeg(Diligent::Uint8* pSrcRGBData,
+ Diligent::Uint32 Width,
+ Diligent::Uint32 Height,
+ int quality,
+ Diligent::IDataBlob* pDstJpegBits);
+}
namespace Diligent
{
@@ -248,6 +274,40 @@ void CreateTextureFromDDS(IDataBlob* pDDSData,
ppTexture);
}
+DECODE_PNG_RESULT DecodePng(IDataBlob* pSrcPngBits,
+ IDataBlob* pDstPixels,
+ ImageDesc* pDstImgDesc)
+{
+ return Diligent_DecodePng(pSrcPngBits, pDstPixels, pDstImgDesc);
+}
+
+ENCODE_PNG_RESULT EncodePng(const Uint8* pSrcPixels,
+ Uint32 Width,
+ Uint32 Height,
+ Uint32 StrideInBytes,
+ int PngColorType,
+ IDataBlob* pDstPngBits)
+{
+ return Diligent_EncodePng(pSrcPixels, Width, Height, StrideInBytes, PngColorType, pDstPngBits);
+}
+
+
+DECODE_JPEG_RESULT DecodeJpeg(IDataBlob* pSrcJpegBits,
+ IDataBlob* pDstPixels,
+ ImageDesc* pDstImgDesc)
+{
+ return Diligent_DecodeJpeg(pSrcJpegBits, pDstPixels, pDstImgDesc);
+}
+
+ENCODE_JPEG_RESULT EncodeJpeg(Uint8* pSrcRGBPixels,
+ Uint32 Width,
+ Uint32 Height,
+ int quality,
+ IDataBlob* pDstJpegBits)
+{
+ return Diligent_EncodeJpeg(pSrcRGBPixels, Width, Height, quality, pDstJpegBits);
+}
+
} // namespace Diligent
extern "C"
diff --git a/TextureLoader/src/TextureUtilities.cpp b/TextureLoader/src/TextureUtilities.cpp
index 858c6b3..ca131b9 100644
--- a/TextureLoader/src/TextureUtilities.cpp
+++ b/TextureLoader/src/TextureUtilities.cpp
@@ -29,7 +29,7 @@
#include "TextureUtilities.h"
#include "Errors.hpp"
#include "TextureLoader.h"
-#include "Image.hpp"
+#include "Image.h"
#include "RefCntAutoPtr.hpp"
#include "DataBlobImpl.hpp"
@@ -50,9 +50,9 @@ void CreateTextureFromFile(const Char* FilePath,
CreateTextureFromImage(pImage, TexLoadInfo, pDevice, ppTexture);
else if (pRawData)
{
- if (ImgFmt == EImageFileFormat::dds)
+ if (ImgFmt == IMAGE_FILE_FORMAT_DDS)
CreateTextureFromDDS(pRawData, TexLoadInfo, pDevice, ppTexture);
- else if (ImgFmt == EImageFileFormat::ktx)
+ else if (ImgFmt == IMAGE_FILE_FORMAT_KTX)
CreateTextureFromKTX(pRawData, TexLoadInfo, pDevice, ppTexture);
else
UNEXPECTED("Unexpected format");
diff --git a/TextureLoader/src/pch.cpp b/TextureLoader/src/pch.cpp
deleted file mode 100644
index 3eef26a..0000000
--- a/TextureLoader/src/pch.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-/* Copyright 2015-2018 Egor Yusov
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
- *
- * In no event and under no legal theory, whether in tort (including negligence),
- * contract, or otherwise, unless required by applicable law (such as deliberate
- * and grossly negligent acts) or agreed to in writing, shall any Contributor be
- * liable for any damages, including any direct, indirect, special, incidental,
- * or consequential damages of any character arising as a result of this License or
- * out of the use or inability to use the software (including but not limited to damages
- * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
- * all other commercial damages or losses), even if such Contributor has been advised
- * of the possibility of such damages.
- */
-
-#include "pch.h"