From 24ccf4008bac168cd3e4777492150a3fbf8371bd Mon Sep 17 00:00:00 2001 From: Joseph Davies Date: Mon, 10 Oct 2022 11:27:45 -0700 Subject: [PATCH 01/10] Add hsStream output functionality to plJPEG interface. --- core/Util/plJPEG.cpp | 111 ++++++++++++++++++++++++++++++++++++++++++- core/Util/plJPEG.h | 6 ++- 2 files changed, 114 insertions(+), 3 deletions(-) diff --git a/core/Util/plJPEG.cpp b/core/Util/plJPEG.cpp index d18d9b44..d8b404e6 100644 --- a/core/Util/plJPEG.cpp +++ b/core/Util/plJPEG.cpp @@ -22,6 +22,9 @@ extern "C" { #include } + +// Input Stream interface + #define INPUT_BUF_SIZE 4096 /* hsStream JPEG source -- modelled after IJG's stdio src */ @@ -107,6 +110,73 @@ GLOBAL(void) jpeg_hsStream_src(j_decompress_ptr dinfo, hsStream* S) src->pub.next_input_byte = nullptr; } + +// Output Stream interface + +#define OUTPUT_BUF_SIZE 4096 + +/* hsStream JPEG destination -- modelled after IJG's stdio dest */ +typedef struct +{ + struct jpeg_destination_mgr pub; + hsStream* stream; + JOCTET* buffer; + boolean start_of_stream; +} jpeg_hsStream_destination; + +METHODDEF(void) init_hsStream_destination(j_compress_ptr cinfo) +{ + jpeg_hsStream_destination* dest = (jpeg_hsStream_destination*)cinfo->dest; + dest->start_of_stream = TRUE; +} + +METHODDEF(boolean) hsStream_empty_output_buffer(j_compress_ptr cinfo) +{ + jpeg_hsStream_destination* dest = (jpeg_hsStream_destination*)cinfo->dest; + + dest->stream->write(OUTPUT_BUF_SIZE, dest->buffer); + + memset(dest->buffer, 0, OUTPUT_BUF_SIZE); + + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; + dest->start_of_stream = FALSE; + + return TRUE; +} + +METHODDEF(void) hsStream_term_destination(j_compress_ptr cinfo) +{ + jpeg_hsStream_destination* dest = (jpeg_hsStream_destination*)cinfo->dest; + size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; + if (datacount > 0) + dest->stream->write(datacount, dest->buffer); + dest->stream->flush(); +} + +GLOBAL(void) jpeg_hsStream_dest(j_compress_ptr cinfo, hsStream* S) +{ + jpeg_hsStream_destination* dest; + + if (cinfo->dest == nullptr) { + cinfo->dest = (struct jpeg_destination_mgr*) + (*cinfo->mem->alloc_small)((j_common_ptr)cinfo, JPOOL_PERMANENT, + sizeof(jpeg_hsStream_destination)); + dest = (jpeg_hsStream_destination*)cinfo->dest; + dest->buffer = (JOCTET*) + (*cinfo->mem->alloc_small)((j_common_ptr)cinfo, JPOOL_PERMANENT, + OUTPUT_BUF_SIZE * sizeof(JOCTET)); + } + + dest = (jpeg_hsStream_destination*)cinfo->dest; + dest->pub.init_destination = init_hsStream_destination; + dest->pub.empty_output_buffer = hsStream_empty_output_buffer; + dest->pub.term_destination = hsStream_term_destination; + dest->stream = S; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; + dest->pub.next_output_byte = dest->buffer; +} + // JPEG error handler for libPlasma static char jpeg_error_buf[JMSG_LENGTH_MAX] = { 0 }; @@ -207,7 +277,44 @@ void plJPEG::DecompressJPEG(hsStream* S, void* buf, size_t size) jpeg_finish_decompress(&ji.dinfo); } -void plJPEG::CompressJPEG(hsStream* S, void* buf, size_t size) +void plJPEG::CompressJPEG(hsStream* S, void* buf, size_t size, uint32_t width, uint32_t height, uint32_t bpp) { - throw hsNotImplementedException(__FILE__, __LINE__); + plJPEG& ji = Instance(); + + JSAMPLE* image_buffer = reinterpret_cast(buf); + + jpeg_create_compress(&ji.cinfo); + jpeg_hsStream_dest(&ji.cinfo, S); + + ji.cinfo.image_width = width; + ji.cinfo.image_height = height; + ji.cinfo.input_components = bpp / 8; + if (ji.cinfo.input_components == 4) + ji.cinfo.in_color_space = JCS_EXT_RGBX; + else + ji.cinfo.in_color_space = JCS_RGB; + + jpeg_set_defaults(&ji.cinfo); + jpeg_set_quality(&ji.cinfo, 100, TRUE); + jpeg_start_compress(&ji.cinfo, TRUE); + + uint32_t row_stride = ji.cinfo.image_width * ji.cinfo.input_components; + RAII_JSAMPROW<1> jbuffer(row_stride); + + size_t offs = 0; + while (ji.cinfo.next_scanline < ji.cinfo.image_height) { + if (offs + row_stride > size) + throw hsJPEGException(__FILE__, __LINE__, "buffer overread"); + + for (size_t x = 0; x < ji.cinfo.image_width; x++) { + memcpy(jbuffer.data[0] + (x * ji.cinfo.input_components), + ((unsigned char*)image_buffer) + offs + (x * ji.cinfo.input_components), + ji.cinfo.input_components); + } + (void)jpeg_write_scanlines(&ji.cinfo, jbuffer.data, 1); + offs += row_stride; + } + + jpeg_finish_compress(&ji.cinfo); + jpeg_destroy_compress(&ji.cinfo); } diff --git a/core/Util/plJPEG.h b/core/Util/plJPEG.h index 19a57ee9..7a2fca2a 100644 --- a/core/Util/plJPEG.h +++ b/core/Util/plJPEG.h @@ -44,8 +44,12 @@ class HSPLASMA_EXPORT plJPEG jpeg_error_mgr jerr; public: + /* Read JPEG file from stream into buffer as bitmap data. */ static void DecompressJPEG(hsStream* S, void* buf, size_t size); - static void CompressJPEG(hsStream* S, void* buf, size_t size); + + /* Write JPEG file to stream from bitmap data buffer. */ + static void CompressJPEG(hsStream* S, void* buf, size_t size, + uint32_t width, uint32_t height, uint32_t bpp); private: plJPEG(); From ebde3a2957fdad589489d6e4354179a51cabf2be Mon Sep 17 00:00:00 2001 From: Joseph Davies Date: Mon, 10 Oct 2022 11:43:54 -0700 Subject: [PATCH 02/10] Add matching comments to plPNG interface for clarity. --- core/Util/plPNG.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/Util/plPNG.h b/core/Util/plPNG.h index 793574ef..3fd012c5 100644 --- a/core/Util/plPNG.h +++ b/core/Util/plPNG.h @@ -37,7 +37,10 @@ class hsPNGException : public hsException class HSPLASMA_EXPORT plPNG { public: + /* Read PNG file from stream into buffer as bitmap data. */ static void DecompressPNG(hsStream* S, void* buf, size_t size); + + /* Write PNG file to stream from bitmap data buffer. */ static void CompressPNG(hsStream* S, const void* buf, size_t size, uint32_t width, uint32_t height, int pixelSize); From f1e434eb8d08d54b5e8f16a71703aaa450f490b5 Mon Sep 17 00:00:00 2001 From: Joseph Davies Date: Mon, 17 Oct 2022 17:38:03 -0700 Subject: [PATCH 03/10] Add functions to load PNGs and JPGs directly into plMipmaps. --- core/Util/plJPEG.cpp | 51 ++++++++++++++++++++++++ core/Util/plJPEG.h | 9 ++++- core/Util/plPNG.cpp | 93 ++++++++++++++++++++++++++++++++++++++++++++ core/Util/plPNG.h | 9 ++++- 4 files changed, 160 insertions(+), 2 deletions(-) diff --git a/core/Util/plJPEG.cpp b/core/Util/plJPEG.cpp index d8b404e6..8ba97874 100644 --- a/core/Util/plJPEG.cpp +++ b/core/Util/plJPEG.cpp @@ -16,6 +16,7 @@ #include "plJPEG.h" #include "Debug/plDebug.h" +#include "PRP/Surface/plMipmap.h" #include extern "C" { @@ -277,6 +278,56 @@ void plJPEG::DecompressJPEG(hsStream* S, void* buf, size_t size) jpeg_finish_decompress(&ji.dinfo); } + +plMipmap* plJPEG::DecompressJPEG(hsStream* S) +{ + plJPEG& ji = Instance(); + + jpeg_hsStream_src(&ji.dinfo, S); + jpeg_read_header(&ji.dinfo, TRUE); + jpeg_start_decompress(&ji.dinfo); + + int row_stride = ji.dinfo.output_width * ji.dinfo.output_components; + int out_stride = ji.dinfo.output_width * 4; // Always decompress to RGBA + RAII_JSAMPROW<1> jbuffer(row_stride); + + // Start with a reasonable guess for the size of the buffer + auto buffer = new std::vector(ji.dinfo.output_width * ji.dinfo.output_height * 4); + + size_t offs = 0; + while (ji.dinfo.output_scanline < ji.dinfo.output_height) { + while (offs + out_stride > buffer->capacity()) { + buffer->reserve(buffer->capacity() + INPUT_BUF_SIZE); + } + jpeg_read_scanlines(&ji.dinfo, jbuffer.data, 1); + memset(((unsigned char*)buffer->data()) + offs, 255, out_stride); + for (size_t x = 0; x < ji.dinfo.output_width; x++) { + memcpy(((unsigned char*)buffer->data()) + offs + (x * 4), + jbuffer.data[0] + (x * ji.dinfo.output_components), + ji.dinfo.out_color_components); + } + offs += out_stride; + } + + // Data stored as RGB on disk but Plasma uses BGR + uint32_t* dp = reinterpret_cast(buffer->data()); + for (size_t i = 0; i < buffer->size(); i += 4) { + *dp = (*dp & 0xFF00FF00) + | (*dp & 0x00FF0000) >> 16 + | (*dp & 0x000000FF) << 16; + dp++; + } + + jpeg_finish_decompress(&ji.dinfo); + buffer->shrink_to_fit(); + + plMipmap* newMipmap = new plMipmap(ji.dinfo.output_width, ji.dinfo.output_height, 1, plMipmap::kUncompressed, plMipmap::kRGB8888); + newMipmap->setImageData(buffer->data(), buffer->size()); + + delete buffer; + return newMipmap; +} + void plJPEG::CompressJPEG(hsStream* S, void* buf, size_t size, uint32_t width, uint32_t height, uint32_t bpp) { plJPEG& ji = Instance(); diff --git a/core/Util/plJPEG.h b/core/Util/plJPEG.h index 7a2fca2a..06966579 100644 --- a/core/Util/plJPEG.h +++ b/core/Util/plJPEG.h @@ -17,7 +17,8 @@ #ifndef _PLJPEG_H #define _PLJPEG_H -#include "PRP/Surface/plMipmap.h" +#include "PlasmaDefs.h" +#include "Debug/hsExceptions.hpp" extern "C" { #include @@ -36,6 +37,9 @@ class hsJPEGException : public hsException }; +class hsStream; +class plMipmap; + class HSPLASMA_EXPORT plJPEG { private: @@ -47,6 +51,9 @@ class HSPLASMA_EXPORT plJPEG /* Read JPEG file from stream into buffer as bitmap data. */ static void DecompressJPEG(hsStream* S, void* buf, size_t size); + /* Read JPEG file from stream directly into a plMipmap. */ + static plMipmap* DecompressJPEG(hsStream* S); + /* Write JPEG file to stream from bitmap data buffer. */ static void CompressJPEG(hsStream* S, void* buf, size_t size, uint32_t width, uint32_t height, uint32_t bpp); diff --git a/core/Util/plPNG.cpp b/core/Util/plPNG.cpp index 090673f5..3303bb6b 100644 --- a/core/Util/plPNG.cpp +++ b/core/Util/plPNG.cpp @@ -16,6 +16,7 @@ #include "plPNG.h" #include "Debug/plDebug.h" +#include "PRP/Surface/plMipmap.h" #include @@ -120,6 +121,98 @@ void plPNG::DecompressPNG(hsStream* S, void* buf, size_t size) png_destroy_read_struct(&pngReader, &pngInfo, &endInfo); } +plMipmap* plPNG::DecompressPNG(hsStream* S) +{ + plMipmap* newMipmap = nullptr; + + png_structp pngReader; + png_infop pngInfo; + png_infop endInfo; + + png_byte sig[PNG_SIG_LENGTH]; + S->read(sizeof(sig), sig); + if (!png_check_sig(sig, PNG_SIG_LENGTH)) + throw hsPNGException(__FILE__, __LINE__, "Invalid PNG header"); + + pngReader = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + if (!pngReader) + throw hsPNGException(__FILE__, __LINE__, "Error initializing PNG reader"); + + pngInfo = png_create_info_struct(pngReader); + if (!pngInfo) { + png_destroy_read_struct(&pngReader, nullptr, nullptr); + throw hsPNGException(__FILE__, __LINE__, "Error initializing PNG info structure"); + } + + endInfo = png_create_info_struct(pngReader); + if (!endInfo) { + png_destroy_read_struct(&pngReader, &pngInfo, nullptr); + throw hsPNGException(__FILE__, __LINE__, "Error initializing PNG info structure"); + } + + png_set_read_fn(pngReader, (png_voidp)S, &pl_png_read); + png_set_sig_bytes(pngReader, PNG_SIG_LENGTH); + + png_read_info(pngReader, pngInfo); + png_uint_32 pngWidth = png_get_image_width(pngReader, pngInfo); + png_uint_32 pngHeight = png_get_image_height(pngReader, pngInfo); + png_uint_32 depth = png_get_bit_depth(pngReader, pngInfo); + png_uint_32 channels = png_get_channels(pngReader, pngInfo); + png_uint_32 colorType = png_get_color_type(pngReader, pngInfo); + + // Convert input to RGB + switch (colorType) { + case PNG_COLOR_TYPE_PALETTE: + png_set_palette_to_rgb(pngReader); + channels = 3; + break; + + case PNG_COLOR_TYPE_GRAY: + if (depth < 8) + png_set_expand_gray_1_2_4_to_8(pngReader); + depth = 8; + break; + + default: + /* Already RGB - nothing to do */ + break; + } + + if (png_get_valid(pngReader, pngInfo, PNG_INFO_tRNS)) { + // Convert 1-bit alpha to 8-bit alpha if necessary + png_set_tRNS_to_alpha(pngReader); + channels += 1; + } else if (channels == 3) { + // Add opaque alpha channel + png_set_filler(pngReader, 0xFF, PNG_FILLER_AFTER); + channels += 1; + } + + // Plasma uses BGR for DirectX + png_set_bgr(pngReader); + + /// Construct a new mipmap to hold everything + newMipmap = new plMipmap(pngWidth, pngHeight, 1, plMipmap::kUncompressed, plMipmap::kRGB8888); + + char* destp = (char*)newMipmap->getImageData(); + png_bytep* row_ptrs = new png_bytep[pngHeight]; + const unsigned int stride = pngWidth * depth * channels / 8; + + // Assign row pointers to the appropriate locations in the newly-created Mipmap + for (size_t i = 0; i < pngHeight; i++) { + row_ptrs[i] = (png_bytep)destp + (i * stride); + } + + png_read_image(pngReader, row_ptrs); + png_read_end(pngReader, endInfo); + + // Clean up allocated structs + png_destroy_read_struct(&pngReader, &pngInfo, &endInfo); + delete[] row_ptrs; + + return newMipmap; +} + void plPNG::CompressPNG(hsStream* S, const void* buf, size_t size, uint32_t width, uint32_t height, int pixelSize) { diff --git a/core/Util/plPNG.h b/core/Util/plPNG.h index 3fd012c5..7daae637 100644 --- a/core/Util/plPNG.h +++ b/core/Util/plPNG.h @@ -17,7 +17,8 @@ #ifndef _PLPNG_H #define _PLPNG_H -#include "PRP/Surface/plMipmap.h" +#include "PlasmaDefs.h" +#include "Debug/hsExceptions.hpp" #include @@ -34,12 +35,18 @@ class hsPNGException : public hsException }; +class hsStream; +class plMipmap; + class HSPLASMA_EXPORT plPNG { public: /* Read PNG file from stream into buffer as bitmap data. */ static void DecompressPNG(hsStream* S, void* buf, size_t size); + /* Read PNG file from stream directly into a plMipmap. */ + static plMipmap* DecompressPNG(hsStream* S); + /* Write PNG file to stream from bitmap data buffer. */ static void CompressPNG(hsStream* S, const void* buf, size_t size, uint32_t width, uint32_t height, int pixelSize); From 32444fe40f41d8a63106af4aa5078f8cf1a76319 Mon Sep 17 00:00:00 2001 From: Joseph Davies Date: Tue, 18 Oct 2022 05:35:53 -0700 Subject: [PATCH 04/10] Use libjpeg-turbo's built-in settings to swap RGBA to BGRA. --- core/Util/plJPEG.cpp | 41 ++++++++++------------------------------- 1 file changed, 10 insertions(+), 31 deletions(-) diff --git a/core/Util/plJPEG.cpp b/core/Util/plJPEG.cpp index 8ba97874..39e6f3ad 100644 --- a/core/Util/plJPEG.cpp +++ b/core/Util/plJPEG.cpp @@ -243,10 +243,11 @@ void plJPEG::DecompressJPEG(hsStream* S, void* buf, size_t size) jpeg_hsStream_src(&ji.dinfo, S); jpeg_read_header(&ji.dinfo, TRUE); + ji.dinfo.out_color_space = JCS_EXT_BGRA; // Data stored as RGB on disk but Plasma uses BGR jpeg_start_decompress(&ji.dinfo); - int row_stride = ji.dinfo.output_width * ji.dinfo.output_components; - int out_stride = ji.dinfo.output_width * 4; // Always decompress to RGBA + int row_stride = ji.dinfo.output_width * ji.dinfo.out_color_components; + int out_stride = row_stride; RAII_JSAMPROW<1> jbuffer(row_stride); size_t offs = 0; @@ -254,27 +255,14 @@ void plJPEG::DecompressJPEG(hsStream* S, void* buf, size_t size) if (offs + out_stride > size) throw hsJPEGException(__FILE__, __LINE__, "buffer overflow"); jpeg_read_scanlines(&ji.dinfo, jbuffer.data, 1); - memset(((unsigned char*)buf) + offs, 0, out_stride); for (size_t x = 0; x(buf) % alignof(uint32_t) != 0) - throw hsBadParamException(__FILE__, __LINE__, "buf should be aligned on a 32-bit boundary"); - - uint32_t* dp = reinterpret_cast(buf); - for (size_t i=0; i> 16 - | (*dp & 0x000000FF) << 16; - dp++; - } - jpeg_finish_decompress(&ji.dinfo); } @@ -285,14 +273,15 @@ plMipmap* plJPEG::DecompressJPEG(hsStream* S) jpeg_hsStream_src(&ji.dinfo, S); jpeg_read_header(&ji.dinfo, TRUE); + ji.dinfo.out_color_space = JCS_EXT_BGRA; // Data stored as RGB on disk but Plasma uses BGR jpeg_start_decompress(&ji.dinfo); - int row_stride = ji.dinfo.output_width * ji.dinfo.output_components; - int out_stride = ji.dinfo.output_width * 4; // Always decompress to RGBA + int row_stride = ji.dinfo.output_width * ji.dinfo.out_color_components; + int out_stride = row_stride; RAII_JSAMPROW<1> jbuffer(row_stride); - // Start with a reasonable guess for the size of the buffer - auto buffer = new std::vector(ji.dinfo.output_width * ji.dinfo.output_height * 4); + // Start with a reasonable size for the buffer + auto buffer = new std::vector(ji.dinfo.output_width * ji.dinfo.output_height * ji.dinfo.out_color_components); size_t offs = 0; while (ji.dinfo.output_scanline < ji.dinfo.output_height) { @@ -300,24 +289,14 @@ plMipmap* plJPEG::DecompressJPEG(hsStream* S) buffer->reserve(buffer->capacity() + INPUT_BUF_SIZE); } jpeg_read_scanlines(&ji.dinfo, jbuffer.data, 1); - memset(((unsigned char*)buffer->data()) + offs, 255, out_stride); for (size_t x = 0; x < ji.dinfo.output_width; x++) { memcpy(((unsigned char*)buffer->data()) + offs + (x * 4), - jbuffer.data[0] + (x * ji.dinfo.output_components), + jbuffer.data[0] + (x * ji.dinfo.out_color_components), ji.dinfo.out_color_components); } offs += out_stride; } - // Data stored as RGB on disk but Plasma uses BGR - uint32_t* dp = reinterpret_cast(buffer->data()); - for (size_t i = 0; i < buffer->size(); i += 4) { - *dp = (*dp & 0xFF00FF00) - | (*dp & 0x00FF0000) >> 16 - | (*dp & 0x000000FF) << 16; - dp++; - } - jpeg_finish_decompress(&ji.dinfo); buffer->shrink_to_fit(); From ad02db9fab8e9a4b197f4754fcf7a5b293a8e085 Mon Sep 17 00:00:00 2001 From: Joseph Davies Date: Sun, 23 Oct 2022 16:07:40 -0700 Subject: [PATCH 05/10] Use stack for JPG read buffer. Apply suggestions from code review. Co-authored-by: Adam Johnson --- core/Util/plJPEG.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/core/Util/plJPEG.cpp b/core/Util/plJPEG.cpp index 39e6f3ad..75a4299d 100644 --- a/core/Util/plJPEG.cpp +++ b/core/Util/plJPEG.cpp @@ -281,16 +281,16 @@ plMipmap* plJPEG::DecompressJPEG(hsStream* S) RAII_JSAMPROW<1> jbuffer(row_stride); // Start with a reasonable size for the buffer - auto buffer = new std::vector(ji.dinfo.output_width * ji.dinfo.output_height * ji.dinfo.out_color_components); + std::vector buffer(ji.dinfo.output_width * ji.dinfo.output_height * ji.dinfo.out_color_components); size_t offs = 0; while (ji.dinfo.output_scanline < ji.dinfo.output_height) { - while (offs + out_stride > buffer->capacity()) { - buffer->reserve(buffer->capacity() + INPUT_BUF_SIZE); + while (offs + out_stride > buffer.capacity()) { + buffer.reserve(buffer.capacity() + INPUT_BUF_SIZE); } jpeg_read_scanlines(&ji.dinfo, jbuffer.data, 1); for (size_t x = 0; x < ji.dinfo.output_width; x++) { - memcpy(((unsigned char*)buffer->data()) + offs + (x * 4), + memcpy(((unsigned char*)buffer.data()) + offs + (x * 4), jbuffer.data[0] + (x * ji.dinfo.out_color_components), ji.dinfo.out_color_components); } @@ -298,12 +298,11 @@ plMipmap* plJPEG::DecompressJPEG(hsStream* S) } jpeg_finish_decompress(&ji.dinfo); - buffer->shrink_to_fit(); + buffer.shrink_to_fit(); plMipmap* newMipmap = new plMipmap(ji.dinfo.output_width, ji.dinfo.output_height, 1, plMipmap::kUncompressed, plMipmap::kRGB8888); - newMipmap->setImageData(buffer->data(), buffer->size()); + newMipmap->setImageData(buffer.data(), buffer.size()); - delete buffer; return newMipmap; } From d8a0bb41fa0a19e9f0871f9742446772c7fb8401 Mon Sep 17 00:00:00 2001 From: Joseph Davies Date: Sun, 23 Oct 2022 16:09:45 -0700 Subject: [PATCH 06/10] Use unique_ptr for PNG read. Apply suggestions from code review. Co-authored-by: Adam Johnson --- core/Util/plPNG.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core/Util/plPNG.cpp b/core/Util/plPNG.cpp index 3303bb6b..f7c2cef0 100644 --- a/core/Util/plPNG.cpp +++ b/core/Util/plPNG.cpp @@ -195,7 +195,7 @@ plMipmap* plPNG::DecompressPNG(hsStream* S) newMipmap = new plMipmap(pngWidth, pngHeight, 1, plMipmap::kUncompressed, plMipmap::kRGB8888); char* destp = (char*)newMipmap->getImageData(); - png_bytep* row_ptrs = new png_bytep[pngHeight]; + auto row_ptrs = std::make_unique(pngHeight); const unsigned int stride = pngWidth * depth * channels / 8; // Assign row pointers to the appropriate locations in the newly-created Mipmap @@ -203,12 +203,11 @@ plMipmap* plPNG::DecompressPNG(hsStream* S) row_ptrs[i] = (png_bytep)destp + (i * stride); } - png_read_image(pngReader, row_ptrs); + png_read_image(pngReader, row_ptrs.get()); png_read_end(pngReader, endInfo); // Clean up allocated structs png_destroy_read_struct(&pngReader, &pngInfo, &endInfo); - delete[] row_ptrs; return newMipmap; } From aef62ece2cb6acb2f9088d6f0258b649e1a7726b Mon Sep 17 00:00:00 2001 From: Joseph Davies Date: Tue, 5 Mar 2024 19:06:27 -0800 Subject: [PATCH 07/10] Apply style improvements to plJPEG. Apply suggestions from code review. Co-authored-by: Adam Johnson --- core/Util/plJPEG.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/Util/plJPEG.cpp b/core/Util/plJPEG.cpp index 75a4299d..4bf9fea5 100644 --- a/core/Util/plJPEG.cpp +++ b/core/Util/plJPEG.cpp @@ -117,13 +117,13 @@ GLOBAL(void) jpeg_hsStream_src(j_decompress_ptr dinfo, hsStream* S) #define OUTPUT_BUF_SIZE 4096 /* hsStream JPEG destination -- modelled after IJG's stdio dest */ -typedef struct +struct jpeg_hsStream_destination { struct jpeg_destination_mgr pub; hsStream* stream; JOCTET* buffer; boolean start_of_stream; -} jpeg_hsStream_destination; +}; METHODDEF(void) init_hsStream_destination(j_compress_ptr cinfo) { @@ -161,11 +161,11 @@ GLOBAL(void) jpeg_hsStream_dest(j_compress_ptr cinfo, hsStream* S) if (cinfo->dest == nullptr) { cinfo->dest = (struct jpeg_destination_mgr*) - (*cinfo->mem->alloc_small)((j_common_ptr)cinfo, JPOOL_PERMANENT, + cinfo->mem->alloc_small((j_common_ptr)cinfo, JPOOL_PERMANENT, sizeof(jpeg_hsStream_destination)); dest = (jpeg_hsStream_destination*)cinfo->dest; dest->buffer = (JOCTET*) - (*cinfo->mem->alloc_small)((j_common_ptr)cinfo, JPOOL_PERMANENT, + cinfo->mem->alloc_small((j_common_ptr)cinfo, JPOOL_PERMANENT, OUTPUT_BUF_SIZE * sizeof(JOCTET)); } @@ -290,7 +290,7 @@ plMipmap* plJPEG::DecompressJPEG(hsStream* S) } jpeg_read_scanlines(&ji.dinfo, jbuffer.data, 1); for (size_t x = 0; x < ji.dinfo.output_width; x++) { - memcpy(((unsigned char*)buffer.data()) + offs + (x * 4), + memcpy(buffer.data() + offs + (x * 4), jbuffer.data[0] + (x * ji.dinfo.out_color_components), ji.dinfo.out_color_components); } From b8755ee81b753b688cf856c11c58e118ae10c3e8 Mon Sep 17 00:00:00 2001 From: Joseph Davies Date: Sat, 22 Jul 2023 11:24:26 -0700 Subject: [PATCH 08/10] Make const plMipmap function actually const. --- core/PRP/Surface/plMipmap.cpp | 2 +- core/PRP/Surface/plMipmap.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/PRP/Surface/plMipmap.cpp b/core/PRP/Surface/plMipmap.cpp index e68c1d7c..b735a741 100644 --- a/core/PRP/Surface/plMipmap.cpp +++ b/core/PRP/Surface/plMipmap.cpp @@ -632,7 +632,7 @@ size_t plMipmap::GetUncompressedSize(size_t level) const return lvl.fHeight * lvl.fWidth * (fPixelSize / 8); } -void plMipmap::DecompressImage(size_t level, void* dest, size_t size) +void plMipmap::DecompressImage(size_t level, void* dest, size_t size) const { const LevelData& lvl = fLevelData[level]; diff --git a/core/PRP/Surface/plMipmap.h b/core/PRP/Surface/plMipmap.h index dff6f2d4..3bd327dc 100644 --- a/core/PRP/Surface/plMipmap.h +++ b/core/PRP/Surface/plMipmap.h @@ -110,7 +110,7 @@ class HSPLASMA_EXPORT plMipmap : public plBitmap bool isAlphaJPEG() const { return !fJAlphaCache.empty(); } size_t GetUncompressedSize(size_t level) const; - void DecompressImage(size_t level, void* dest, size_t size); + void DecompressImage(size_t level, void* dest, size_t size) const; void CompressImage(size_t level, void* src, size_t size, BlockQuality quality = kBlockQualityNormal); }; From 39ac1efecb63d01fb022097065939e380bbb1a70 Mon Sep 17 00:00:00 2001 From: Joseph Davies Date: Tue, 5 Mar 2024 21:56:13 -0800 Subject: [PATCH 09/10] Use explicit static_cast in plPNG decompressor. Apply suggestions from code review. Co-authored-by: Michael Hansen --- core/Util/plPNG.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/Util/plPNG.cpp b/core/Util/plPNG.cpp index f7c2cef0..ee1c8b3c 100644 --- a/core/Util/plPNG.cpp +++ b/core/Util/plPNG.cpp @@ -194,7 +194,7 @@ plMipmap* plPNG::DecompressPNG(hsStream* S) /// Construct a new mipmap to hold everything newMipmap = new plMipmap(pngWidth, pngHeight, 1, plMipmap::kUncompressed, plMipmap::kRGB8888); - char* destp = (char*)newMipmap->getImageData(); + char* destp = static_cast(newMipmap->getImageData()); auto row_ptrs = std::make_unique(pngHeight); const unsigned int stride = pngWidth * depth * channels / 8; From b7352898e08a650e4b390c1ad29d42811cd941fb Mon Sep 17 00:00:00 2001 From: Joseph Davies Date: Tue, 5 Mar 2024 22:11:31 -0800 Subject: [PATCH 10/10] Use unique_ptr for JPEG decompression buffer. Apply suggestions from code review. Co-authored-by: Adam Johnson --- core/Util/plJPEG.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/core/Util/plJPEG.cpp b/core/Util/plJPEG.cpp index 4bf9fea5..ca7f4703 100644 --- a/core/Util/plJPEG.cpp +++ b/core/Util/plJPEG.cpp @@ -17,7 +17,9 @@ #include "plJPEG.h" #include "Debug/plDebug.h" #include "PRP/Surface/plMipmap.h" + #include +#include extern "C" { #include @@ -281,16 +283,14 @@ plMipmap* plJPEG::DecompressJPEG(hsStream* S) RAII_JSAMPROW<1> jbuffer(row_stride); // Start with a reasonable size for the buffer - std::vector buffer(ji.dinfo.output_width * ji.dinfo.output_height * ji.dinfo.out_color_components); + auto buffer_size = ji.dinfo.output_width * ji.dinfo.output_height * ji.dinfo.out_color_components; + auto buffer = std::make_unique(buffer_size); size_t offs = 0; while (ji.dinfo.output_scanline < ji.dinfo.output_height) { - while (offs + out_stride > buffer.capacity()) { - buffer.reserve(buffer.capacity() + INPUT_BUF_SIZE); - } jpeg_read_scanlines(&ji.dinfo, jbuffer.data, 1); for (size_t x = 0; x < ji.dinfo.output_width; x++) { - memcpy(buffer.data() + offs + (x * 4), + memcpy(buffer.get() + offs + (x * 4), jbuffer.data[0] + (x * ji.dinfo.out_color_components), ji.dinfo.out_color_components); } @@ -298,10 +298,9 @@ plMipmap* plJPEG::DecompressJPEG(hsStream* S) } jpeg_finish_decompress(&ji.dinfo); - buffer.shrink_to_fit(); plMipmap* newMipmap = new plMipmap(ji.dinfo.output_width, ji.dinfo.output_height, 1, plMipmap::kUncompressed, plMipmap::kRGB8888); - newMipmap->setImageData(buffer.data(), buffer.size()); + newMipmap->setImageData(buffer.get(), buffer_size); return newMipmap; }