diff --git a/Source/Plugins/PSDParser.cpp b/Source/Plugins/PSDParser.cpp index fcf75fb..0f56854 100644 --- a/Source/Plugins/PSDParser.cpp +++ b/Source/Plugins/PSDParser.cpp @@ -777,6 +777,10 @@ int psdThumbnail::Read(FreeImageIO *io, fi_handle handle, int iResourceSize, boo FreeImage_Unload(_dib); } + if (_WidthBytes != _Width * _BitPerPixel / 8) { + throw "Invalid PSD image"; + } + if (_Format == 1) { // kJpegRGB thumbnail image _dib = FreeImage_LoadFromHandle(FIF_JPEG, io, handle); diff --git a/Source/Plugins/PluginICO.cpp b/Source/Plugins/PluginICO.cpp index 45e8801..637ce9b 100644 --- a/Source/Plugins/PluginICO.cpp +++ b/Source/Plugins/PluginICO.cpp @@ -65,7 +65,7 @@ typedef struct tagICONDIRECTORYENTRY { /** How wide, in bytes, would this many bits be, uint32_t aligned ? */ -static int +static int WidthBytes(int bits) { return ((((bits) + 31)>>5)<<2); } @@ -73,7 +73,7 @@ WidthBytes(int bits) { /** Calculates the size of a single icon image @return Returns the size for that image */ -static uint32_t +static uint32_t CalculateImageSize(FIBITMAP* icon_dib) { uint32_t dwNumBytes = 0; @@ -93,10 +93,10 @@ CalculateImageSize(FIBITMAP* icon_dib) { /** Calculates the file offset for an icon image @return Returns the file offset for that image */ -static uint32_t +static uint32_t CalculateImageOffset(const std::vector> &vPages, int nIndex ) { // calculate the ICO header size - uint32_t dwSize = sizeof(ICONHEADER); + uint32_t dwSize = sizeof(ICONHEADER); // add the ICONDIRENTRY's dwSize += (uint32_t)( vPages.size() * sizeof(ICONDIRENTRY) ); // add the sizes of the previous images @@ -220,7 +220,7 @@ SupportsExportDepth(int depth) { ); } -static FIBOOL DLL_CALLCONV +static FIBOOL DLL_CALLCONV SupportsExportType(FREE_IMAGE_TYPE type) { return (type == FIT_BITMAP) ? TRUE : FALSE; } @@ -297,6 +297,9 @@ LoadStandardIcon(FreeImageIO *io, fi_handle handle, int flags, FIBOOL header_onl const int width = bmih.biWidth; const int height = bmih.biHeight / 2; // height == xor + and mask const unsigned bit_count = bmih.biBitCount; + if (bit_count != 1 && bit_count != 2 && bit_count != 4 && bit_count != 8 && bit_count != 16 && bit_count != 24 && bit_count != 32) { + return NULL; + } const unsigned line = CalculateLine(width, bit_count); const unsigned pitch = CalculatePitch(line); @@ -318,7 +321,7 @@ LoadStandardIcon(FreeImageIO *io, fi_handle handle, int flags, FIBOOL header_onl } #endif } - + if (header_only) { // header only mode return dib.release(); @@ -445,7 +448,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { // ---------------------------------------------------------- -static FIBOOL +static FIBOOL SaveStandardIcon(FreeImageIO *io, FIBITMAP *dib, fi_handle handle) { // write the BITMAPINFOHEADER auto *bmih = FreeImage_GetInfoHeader(dib); @@ -558,13 +561,13 @@ SaveStandardIcon(FreeImageIO *io, FIBITMAP *dib, fi_handle handle) { for (int x = 0; x < width; x++) { if (bits[x].alpha != 0xFF) { // set any transparent color to full transparency - and_bits[x >> 3] |= (0x80 >> (x & 0x7)); + and_bits[x >> 3] |= (0x80 >> (x & 0x7)); } } and_bits += width_and; } - } + } else if (bit_count <= 8) { // create the AND mask from the transparency table @@ -586,7 +589,7 @@ SaveStandardIcon(FreeImageIO *io, FIBITMAP *dib, fi_handle handle) { uint8_t index = (bits[x >> 3] & (0x80 >> (x & 0x07))) != 0; if (trns[index] != 0xFF) { // set any transparent color to full transparency - and_bits[x >> 3] |= (0x80 >> (x & 0x7)); + and_bits[x >> 3] |= (0x80 >> (x & 0x7)); } } and_bits += width_and; @@ -604,7 +607,7 @@ SaveStandardIcon(FreeImageIO *io, FIBITMAP *dib, fi_handle handle) { uint8_t index = (bits[x >> 1] & (0x0F << shift)) >> shift; if (trns[index] != 0xFF) { // set any transparent color to full transparency - and_bits[x >> 3] |= (0x80 >> (x & 0x7)); + and_bits[x >> 3] |= (0x80 >> (x & 0x7)); } } and_bits += width_and; @@ -621,7 +624,7 @@ SaveStandardIcon(FreeImageIO *io, FIBITMAP *dib, fi_handle handle) { uint8_t index = bits[x]; if (trns[index] != 0xFF) { // set any transparent color to full transparency - and_bits[x >> 3] |= (0x80 >> (x & 0x7)); + and_bits[x >> 3] |= (0x80 >> (x & 0x7)); } } and_bits += width_and; @@ -663,7 +666,7 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void if (page == -1) { page = 0; } - + // get the icon header icon_header = (ICONHEADER*)data; @@ -696,7 +699,7 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void // write all icons // ... - + // save the icon descriptions std::unique_ptr safeList(calloc(icon_header->idCount, sizeof(ICONDIRENTRY)), &free); @@ -731,12 +734,12 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void io->write_proc(icon_list, sizeof(ICONDIRENTRY) * icon_header->idCount, 1, handle); // write the image bits for each image - + uint32_t dwImageOffset = (uint32_t)io->tell_proc(handle); for (k = 0; k < icon_header->idCount; k++) { icon_dib = vPages[k].get(); - + if ((icon_list[k].bWidth == 0) && (icon_list[k].bHeight == 0)) { // Vista icon support FreeImage_SaveToHandle(FIF_PNG, icon_dib, io, handle, PNG_DEFAULT); @@ -747,7 +750,7 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void SaveStandardIcon(io, icon_dib, handle); } - // update ICONDIRENTRY members + // update ICONDIRENTRY members uint32_t dwBytesInRes = (uint32_t)io->tell_proc(handle) - dwImageOffset; icon_list[k].dwImageOffset = dwImageOffset; icon_list[k].dwBytesInRes = dwBytesInRes; diff --git a/Source/Plugins/PluginJPEG.cpp b/Source/Plugins/PluginJPEG.cpp index 35a2e03..abf6ef6 100644 --- a/Source/Plugins/PluginJPEG.cpp +++ b/Source/Plugins/PluginJPEG.cpp @@ -26,7 +26,7 @@ // Use at your own risk! // ========================================================== -#ifdef _MSC_VER +#ifdef _MSC_VER #pragma warning (disable : 4786) // identifier was truncated to 'number' characters #endif @@ -58,12 +58,12 @@ static int s_format_id; // Constant declarations // ---------------------------------------------------------- -#define INPUT_BUF_SIZE 4096 // choose an efficiently fread'able size +#define INPUT_BUF_SIZE 4096 // choose an efficiently fread'able size #define OUTPUT_BUF_SIZE 4096 // choose an efficiently fwrite'able size #define EXIF_MARKER (JPEG_APP0+1) // EXIF marker / Adobe XMP marker #define ICC_MARKER (JPEG_APP0+2) // ICC profile marker -#define IPTC_MARKER (JPEG_APP0+13) // IPTC marker / BIM marker +#define IPTC_MARKER (JPEG_APP0+13) // IPTC marker / BIM marker #define ICC_HEADER_SIZE 14 // size of non-profile data in APP2 #define MAX_BYTES_IN_MARKER 65533L // maximum data length of a JPEG marker @@ -147,12 +147,12 @@ jpeg_error_exit (j_common_ptr cinfo) { // allow JPEG with unknown markers if (error_ptr->pub.msg_code != JERR_UNKNOWN_MARKER) { - + // let the memory manager delete any temp files before we die jpeg_destroy(cinfo); - + // return control to the setjmp point - longjmp(error_ptr->setjmp_buffer, 1); + longjmp(error_ptr->setjmp_buffer, 1); } } @@ -239,7 +239,7 @@ term_destination (j_compress_ptr cinfo) { if (dest->m_io->write_proc(dest->buffer, 1, (unsigned int)datacount, dest->outfile) != datacount) { // let the memory manager delete any temp files before we die jpeg_destroy((j_common_ptr)cinfo); - + JPEG_EXIT((j_common_ptr)cinfo, JERR_FILE_WRITE); } } @@ -390,12 +390,12 @@ jpeg_freeimage_src (j_decompress_ptr cinfo, fi_handle infile, FreeImageIO *io) { src->pub.init_source = init_source; src->pub.fill_input_buffer = fill_input_buffer; src->pub.skip_input_data = skip_input_data; - src->pub.resync_to_restart = jpeg_resync_to_restart; // use default method + src->pub.resync_to_restart = jpeg_resync_to_restart; // use default method src->pub.term_source = term_source; src->infile = infile; src->m_io = io; - src->pub.bytes_in_buffer = 0; // forces fill_input_buffer on first read - src->pub.next_input_byte = nullptr; // until buffer loaded + src->pub.bytes_in_buffer = 0; // forces fill_input_buffer on first read + src->pub.next_input_byte = nullptr; // until buffer loaded } /** @@ -427,7 +427,7 @@ jpeg_freeimage_dst (j_compress_ptr cinfo, fi_handle outfile, FreeImageIO *io) { /** Read JPEG_COM marker (comment) */ -static FIBOOL +static FIBOOL jpeg_read_comment(FIBITMAP *dib, const uint8_t *dataptr, unsigned int datalen) { size_t length = datalen; uint8_t *profile = (uint8_t*)dataptr; @@ -458,14 +458,14 @@ jpeg_read_comment(FIBITMAP *dib, const uint8_t *dataptr, unsigned int datalen) { return bSuccess ? TRUE : FALSE; } -/** +/** Read JPEG_APP2 marker (ICC profile) */ /** Handy subroutine to test whether a saved marker is an ICC profile marker. */ -static FIBOOL +static FIBOOL marker_is_icc(jpeg_saved_marker_ptr marker) { // marker identifying string "ICC_PROFILE" (null-terminated) const uint8_t icc_signature[12] = { 0x49, 0x43, 0x43, 0x5F, 0x50, 0x52, 0x4F, 0x46, 0x49, 0x4C, 0x45, 0x00 }; @@ -490,18 +490,18 @@ marker_is_icc(jpeg_saved_marker_ptr marker) { TRUE is returned if an ICC profile was found, FALSE if not. If TRUE is returned, *icc_data_ptr is set to point to the returned data, and *icc_data_len is set to its length. - + IMPORTANT: the data at **icc_data_ptr has been allocated with malloc() and must be freed by the caller with free() when the caller no longer needs it. (Alternatively, we could write this routine to use the IJG library's memory allocator, so that the data would be freed implicitly at jpeg_finish_decompress() time. But it seems likely that many apps will prefer to have the data stick around after decompression finishes.) - + NOTE: if the file contains invalid ICC APP2 markers, we just silently return FALSE. You might want to issue an error message instead. */ -static FIBOOL +static FIBOOL jpeg_read_icc_profile(j_decompress_ptr cinfo, JOCTET **icc_data_ptr, unsigned *icc_data_len) { jpeg_saved_marker_ptr marker; int num_markers = 0; @@ -513,17 +513,17 @@ jpeg_read_icc_profile(j_decompress_ptr cinfo, JOCTET **icc_data_ptr, unsigned *i uint8_t marker_present[MAX_SEQ_NO+1]; // 1 if marker found unsigned data_length[MAX_SEQ_NO+1]; // size of profile data in marker unsigned data_offset[MAX_SEQ_NO+1]; // offset for data in marker - + *icc_data_ptr = nullptr; // avoid confusion if FALSE return *icc_data_len = 0; - + /** this first pass over the saved markers discovers whether there are any ICC markers and verifies the consistency of the marker numbering. */ - + memset(marker_present, 0, (MAX_SEQ_NO + 1)); - + for (marker = cinfo->marker_list; marker; marker = marker->next) { if (marker_is_icc(marker)) { if (num_markers == 0) { @@ -531,29 +531,29 @@ jpeg_read_icc_profile(j_decompress_ptr cinfo, JOCTET **icc_data_ptr, unsigned *i num_markers = GETJOCTET(marker->data[13]); } else if (num_markers != GETJOCTET(marker->data[13])) { - return FALSE; // inconsistent num_markers fields + return FALSE; // inconsistent num_markers fields } // sequence number seq_no = GETJOCTET(marker->data[12]); if (seq_no <= 0 || seq_no > num_markers) { - return FALSE; // bogus sequence number + return FALSE; // bogus sequence number } if (marker_present[seq_no]) { - return FALSE; // duplicate sequence numbers + return FALSE; // duplicate sequence numbers } marker_present[seq_no] = 1; data_length[seq_no] = marker->data_length - ICC_HEADER_SIZE; } } - + if (num_markers == 0) return FALSE; - + /** check for missing markers, count total space needed, compute offset of each marker's part of the data. */ - + total_length = 0; for (seq_no = 1; seq_no <= num_markers; seq_no++) { if (marker_present[seq_no] == 0) { @@ -562,15 +562,15 @@ jpeg_read_icc_profile(j_decompress_ptr cinfo, JOCTET **icc_data_ptr, unsigned *i data_offset[seq_no] = total_length; total_length += data_length[seq_no]; } - + if (total_length <= 0) return FALSE; // found only empty markers ? - - // allocate space for assembled data + + // allocate space for assembled data icc_data = (JOCTET *) malloc(total_length * sizeof(JOCTET)); if (!icc_data) return FALSE; // out of memory - + // and fill it in for (marker = cinfo->marker_list; marker; marker = marker->next) { if (marker_is_icc(marker)) { @@ -586,10 +586,10 @@ jpeg_read_icc_profile(j_decompress_ptr cinfo, JOCTET **icc_data_ptr, unsigned *i } } } - + *icc_data_ptr = icc_data; *icc_data_len = total_length; - + return TRUE; } #endif @@ -597,7 +597,7 @@ jpeg_read_icc_profile(j_decompress_ptr cinfo, JOCTET **icc_data_ptr, unsigned *i /** Read JPEG_APPD marker (IPTC or Adobe Photoshop profile) */ -static FIBOOL +static FIBOOL jpeg_read_iptc_profile(FIBITMAP *dib, const uint8_t *dataptr, unsigned int datalen) { return read_iptc_profile(dib, dataptr, datalen); } @@ -609,7 +609,7 @@ jpeg_read_iptc_profile(FIBITMAP *dib, const uint8_t *dataptr, unsigned int datal @param datalen APP1 marker length @return Returns TRUE if successful, FALSE otherwise */ -static FIBOOL +static FIBOOL jpeg_read_xmp_profile(FIBITMAP *dib, const uint8_t *dataptr, unsigned int datalen) { // marker identifying string for XMP (null terminated) const char *xmp_signature = "http://ns.adobe.com/xap/1.0/"; @@ -620,7 +620,7 @@ jpeg_read_xmp_profile(FIBITMAP *dib, const uint8_t *dataptr, unsigned int datale uint8_t *profile = (uint8_t*)dataptr; if (length <= xmp_signature_size) { - // avoid reading corrupted or empty data + // avoid reading corrupted or empty data return FALSE; } @@ -640,7 +640,7 @@ jpeg_read_xmp_profile(FIBITMAP *dib, const uint8_t *dataptr, unsigned int datale bSuccess = bSuccess && FreeImage_SetTagCount(tag.get(), (uint32_t)length); bSuccess = bSuccess && FreeImage_SetTagType(tag.get(), FIDT_ASCII); bSuccess = bSuccess && FreeImage_SetTagValue(tag.get(), profile); - + // store the tag bSuccess = bSuccess && FreeImage_SetMetadata(FIMD_XMP, dib, FreeImage_GetTagKey(tag.get()), tag.get()); } @@ -656,16 +656,16 @@ jpeg_read_xmp_profile(FIBITMAP *dib, const uint8_t *dataptr, unsigned int datale @param datalen APP0 marker length @return Returns TRUE if successful, FALSE otherwise */ -static FIBOOL +static FIBOOL jpeg_read_jfxx(FIBITMAP *dib, const uint8_t *dataptr, unsigned int datalen) { if (datalen < 6) { return FALSE; } - + const int id_length = 5; const uint8_t *data = dataptr + id_length; unsigned remaining = datalen - id_length; - + const uint8_t type = *data; ++data, --remaining; @@ -697,7 +697,7 @@ jpeg_read_jfxx(FIBITMAP *dib, const uint8_t *dataptr, unsigned int datalen) { /** Read JPEG special markers */ -static FIBOOL +static FIBOOL read_markers(j_decompress_ptr cinfo, FIBITMAP *dib) { jpeg_saved_marker_ptr marker; @@ -711,7 +711,7 @@ read_markers(j_decompress_ptr cinfo, FIBITMAP *dib) { if (memcmp(marker->data, "JFXX" , 5) == 0) { if (!cinfo->saw_JFIF_marker || cinfo->JFIF_minor_version < 2) { FreeImage_OutputMessageProc(s_format_id, "Warning: non-standard JFXX segment"); - } + } jpeg_read_jfxx(dib, marker->data, marker->data_length); } // other values such as 'Picasa' : ignore safely unknown APP0 marker @@ -754,7 +754,7 @@ read_markers(j_decompress_ptr cinfo, FIBITMAP *dib) { /** Write JPEG_COM marker (comment) */ -static FIBOOL +static FIBOOL jpeg_write_comment(j_compress_ptr cinfo, FIBITMAP *dib) { FITAG *tag{}; @@ -773,10 +773,10 @@ jpeg_write_comment(j_compress_ptr cinfo, FIBITMAP *dib) { return FALSE; } -/** +/** Write JPEG_APP2 marker (ICC profile) */ -static FIBOOL +static FIBOOL jpeg_write_icc_profile(j_compress_ptr cinfo, FIBITMAP *dib) { // marker identifying string "ICC_PROFILE" (null-terminated) const uint8_t icc_signature[12] = { 0x49, 0x43, 0x43, 0x5F, 0x50, 0x52, 0x4F, 0x46, 0x49, 0x4C, 0x45, 0x00 }; @@ -803,17 +803,17 @@ jpeg_write_icc_profile(j_compress_ptr cinfo, FIBITMAP *dib) { free(profile); - return TRUE; + return TRUE; } - + return FALSE; } -/** +/** Write JPEG_APPD marker (IPTC or Adobe Photoshop profile) @return Returns TRUE if successful, FALSE otherwise */ -static FIBOOL +static FIBOOL jpeg_write_iptc_profile(j_compress_ptr cinfo, FIBITMAP *dib) { //const char *ps_header = "Photoshop 3.0\x08BIM\x04\x04\x0\x0\x0\x0"; const unsigned tag_length = 26; @@ -856,11 +856,11 @@ jpeg_write_iptc_profile(j_compress_ptr cinfo, FIBITMAP *dib) { return FALSE; } -/** +/** Write JPEG_APP1 marker (XMP profile) @return Returns TRUE if successful, FALSE otherwise */ -static FIBOOL +static FIBOOL jpeg_write_xmp_profile(j_compress_ptr cinfo, FIBITMAP *dib) { // marker identifying string for XMP (null terminated) const char *xmp_signature = "http://ns.adobe.com/xap/1.0/"; @@ -883,25 +883,25 @@ jpeg_write_xmp_profile(j_compress_ptr cinfo, FIBITMAP *dib) { for (uint32_t i = 0; i < tag_length; i += 65504L) { unsigned length = MIN((long)(tag_length - i), 65504L); - + memcpy(profile + xmp_header_size, tag_value + i, length); jpeg_write_marker(cinfo, EXIF_MARKER, profile, (length + xmp_header_size)); } free(profile); - return TRUE; + return TRUE; } } return FALSE; } -/** +/** Write JPEG_APP1 marker (Exif profile) @return Returns TRUE if successful, FALSE otherwise */ -static FIBOOL +static FIBOOL jpeg_write_exif_profile_raw(j_compress_ptr cinfo, FIBITMAP *dib) { // marker identifying string for Exif = "Exif\0\0" const uint8_t exif_signature[6] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 }; @@ -911,7 +911,7 @@ jpeg_write_exif_profile_raw(j_compress_ptr cinfo, FIBITMAP *dib) { if (tag_exif) { auto *tag_value = (const uint8_t*)FreeImage_GetTagValue(tag_exif); - + // verify the identifying string if (memcmp(exif_signature, tag_value, sizeof(exif_signature)) != 0) { // not an Exif profile @@ -926,7 +926,7 @@ jpeg_write_exif_profile_raw(j_compress_ptr cinfo, FIBITMAP *dib) { for (uint32_t i = 0; i < tag_length; i += 65504L) { unsigned length = MIN((long)(tag_length - i), 65504L); - + memcpy(profile, tag_value + i, length); jpeg_write_marker(cinfo, EXIF_MARKER, profile, length); } @@ -955,11 +955,11 @@ jpeg_write_jfxx(j_compress_ptr cinfo, FIBITMAP *dib) { FreeImage_OutputMessageProc(s_format_id, FI_MSG_WARNING_INVALID_THUMBNAIL); return FALSE; } - + // stores the thumbnail as a baseline JPEG into a memory block // return the memory block only if its size is within JFXX marker size limit! FIMEMORY *stream = FreeImage_OpenMemory(); - + if (FreeImage_SaveToMemory(FIF_JPEG, thumbnail, stream, JPEG_BASELINE)) { // check that the memory block size is within JFXX marker size limit FreeImage_SeekMemory(stream, 0, SEEK_END); @@ -976,43 +976,43 @@ jpeg_write_jfxx(j_compress_ptr cinfo, FIBITMAP *dib) { uint8_t* thData{}; uint32_t thSize = 0; - - FreeImage_AcquireMemory(stream, &thData, &thSize); - + + FreeImage_AcquireMemory(stream, &thData, &thSize); + uint8_t id_length = 5; //< "JFXX" uint8_t type = JFXX_TYPE_JPEG; - + uint32_t totalsize = id_length + sizeof(type) + thSize; jpeg_write_m_header(cinfo, JPEG_APP0, totalsize); - + jpeg_write_m_byte(cinfo, 'J'); jpeg_write_m_byte(cinfo, 'F'); jpeg_write_m_byte(cinfo, 'X'); jpeg_write_m_byte(cinfo, 'X'); jpeg_write_m_byte(cinfo, '\0'); - + jpeg_write_m_byte(cinfo, type); - + // write thumbnail to destination. // We "cram it straight into the data destination module", because write_m_byte is slow - + freeimage_dst_ptr dest = (freeimage_dst_ptr) cinfo->dest; - + uint8_t* & out = dest->pub.next_output_byte; size_t & bufRemain = dest->pub.free_in_buffer; - + const uint8_t *thData_end = thData + thSize; while (thData < thData_end) { *(out)++ = *(thData)++; - if (--bufRemain == 0) { + if (--bufRemain == 0) { // buffer full - flush if (!dest->pub.empty_output_buffer(cinfo)) { break; } } } - + FreeImage_CloseMemory(stream); return TRUE; @@ -1021,7 +1021,7 @@ jpeg_write_jfxx(j_compress_ptr cinfo, FIBITMAP *dib) { /** Write JPEG special markers */ -static FIBOOL +static FIBOOL write_markers(j_compress_ptr cinfo, FIBITMAP *dib) { // write thumbnail as a JFXX marker jpeg_write_jfxx(cinfo, dib); @@ -1047,7 +1047,7 @@ write_markers(j_compress_ptr cinfo, FIBITMAP *dib) { // ------------------------------------------------------------ // Keep original size info when using scale option on loading // ------------------------------------------------------------ -static void +static void store_size_info(FIBITMAP *dib, JDIMENSION width, JDIMENSION height) { char buffer[256]; // create a tag @@ -1122,7 +1122,7 @@ SupportsExportDepth(int depth) { ); } -static FIBOOL DLL_CALLCONV +static FIBOOL DLL_CALLCONV SupportsExportType(FREE_IMAGE_TYPE type) { return (type == FIT_BITMAP) ? TRUE : FALSE; } @@ -1157,7 +1157,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { cinfo.err = jpeg_std_error(&fi_error_mgr.pub); fi_error_mgr.pub.error_exit = jpeg_error_exit; fi_error_mgr.pub.output_message = jpeg_output_message; - + // establish the setjmp return context for jpeg_error_exit to use if (setjmp(fi_error_mgr.setjmp_buffer)) { // If we get here, the JPEG code has signaled an error. @@ -1173,7 +1173,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { jpeg_freeimage_src(&cinfo, handle, io); // step 2b: save special markers for later reading - + jpeg_save_markers(&cinfo, JPEG_COM, 0xFFFF); for (int m = 0; m < 16; m++) { jpeg_save_markers(&cinfo, JPEG_APP0 + m, 0xFFFF); @@ -1187,6 +1187,10 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { throw FI_MSG_ERROR_DIB_MEMORY; } + if (cinfo.image_width > JPEG_MAX_DIMENSION || cinfo.image_height > JPEG_MAX_DIMENSION) { + throw FI_MSG_ERROR_DIB_MEMORY; + } + // step 4: set parameters for decompression unsigned int scale_denom = 1; // fraction by which to scale image @@ -1266,9 +1270,9 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { FreeImage_SetDotsPerMeterX(dib.get(), (unsigned) (cinfo.X_density * 100)); FreeImage_SetDotsPerMeterY(dib.get(), (unsigned) (cinfo.Y_density * 100)); } - + // step 6: read special markers - + read_markers(&cinfo, dib.get()); // --- header only mode => clean-up and return @@ -1308,7 +1312,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { dst += 3; } } - + // if original image is CMYK but is converted to RGB, remove ICC profile from Exif-TIFF metadata FreeImage_SetMetadata(FIMD_EXIF_MAIN, dib.get(), "InterColorProfile", nullptr); @@ -1350,7 +1354,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { } // step 7b: swap red and blue components (see LibJPEG/jmorecfg.h: #define RGB_RED, ...) - // The default behavior of the JPEG library is kept "as is" because LibTIFF uses + // The default behavior of the JPEG library is kept "as is" because LibTIFF uses // LibJPEG "as is". #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR @@ -1406,7 +1410,7 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void } if (bpp == 8) { - // allow grey, reverse grey and palette + // allow grey, reverse grey and palette if ((color_type != FIC_MINISBLACK) && (color_type != FIC_MINISWHITE) && (color_type != FIC_PALETTE)) { throw sError; } @@ -1422,7 +1426,7 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void cinfo.err = jpeg_std_error(&fi_error_mgr.pub); fi_error_mgr.pub.error_exit = jpeg_error_exit; fi_error_mgr.pub.output_message = jpeg_output_message; - + // establish the setjmp return context for jpeg_error_exit to use if (setjmp(fi_error_mgr.setjmp_buffer)) { // If we get here, the JPEG code has signaled an error. @@ -1439,7 +1443,7 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void jpeg_freeimage_dst(&cinfo, handle, io); - // Step 3: set parameters for compression + // Step 3: set parameters for compression cinfo.image_width = FreeImage_GetWidth(dib); cinfo.image_height = FreeImage_GetHeight(dib); @@ -1466,7 +1470,7 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void if ((flags & JPEG_PROGRESSIVE) == JPEG_PROGRESSIVE) { jpeg_simple_progression(&cinfo); } - + // compute optimal Huffman coding tables for the image if ((flags & JPEG_OPTIMIZE) == JPEG_OPTIMIZE) { cinfo.optimize_coding = TRUE; @@ -1487,52 +1491,52 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void // baseline JPEG support if ((flags & JPEG_BASELINE) == JPEG_BASELINE) { cinfo.write_JFIF_header = static_cast(0); // No marker for non-JFIF colorspaces - cinfo.write_Adobe_marker = static_cast(0); // write no Adobe marker by default + cinfo.write_Adobe_marker = static_cast(0); // write no Adobe marker by default } // set subsampling options if required if (cinfo.in_color_space == JCS_RGB) { - if ((flags & JPEG_SUBSAMPLING_411) == JPEG_SUBSAMPLING_411) { + if ((flags & JPEG_SUBSAMPLING_411) == JPEG_SUBSAMPLING_411) { // 4:1:1 (4x1 1x1 1x1) - CrH 25% - CbH 25% - CrV 100% - CbV 100% // the horizontal color resolution is quartered - cinfo.comp_info[0].h_samp_factor = 4; // Y - cinfo.comp_info[0].v_samp_factor = 1; - cinfo.comp_info[1].h_samp_factor = 1; // Cb - cinfo.comp_info[1].v_samp_factor = 1; - cinfo.comp_info[2].h_samp_factor = 1; // Cr - cinfo.comp_info[2].v_samp_factor = 1; + cinfo.comp_info[0].h_samp_factor = 4; // Y + cinfo.comp_info[0].v_samp_factor = 1; + cinfo.comp_info[1].h_samp_factor = 1; // Cb + cinfo.comp_info[1].v_samp_factor = 1; + cinfo.comp_info[2].h_samp_factor = 1; // Cr + cinfo.comp_info[2].v_samp_factor = 1; } else if ((flags & JPEG_SUBSAMPLING_420) == JPEG_SUBSAMPLING_420) { // 4:2:0 (2x2 1x1 1x1) - CrH 50% - CbH 50% - CrV 50% - CbV 50% // the chrominance resolution in both the horizontal and vertical directions is cut in half cinfo.comp_info[0].h_samp_factor = 2; // Y - cinfo.comp_info[0].v_samp_factor = 2; + cinfo.comp_info[0].v_samp_factor = 2; cinfo.comp_info[1].h_samp_factor = 1; // Cb - cinfo.comp_info[1].v_samp_factor = 1; + cinfo.comp_info[1].v_samp_factor = 1; cinfo.comp_info[2].h_samp_factor = 1; // Cr - cinfo.comp_info[2].v_samp_factor = 1; - } else if ((flags & JPEG_SUBSAMPLING_422) == JPEG_SUBSAMPLING_422){ //2x1 (low) + cinfo.comp_info[2].v_samp_factor = 1; + } else if ((flags & JPEG_SUBSAMPLING_422) == JPEG_SUBSAMPLING_422){ //2x1 (low) // 4:2:2 (2x1 1x1 1x1) - CrH 50% - CbH 50% - CrV 100% - CbV 100% - // half of the horizontal resolution in the chrominance is dropped (Cb & Cr), + // half of the horizontal resolution in the chrominance is dropped (Cb & Cr), // while the full resolution is retained in the vertical direction, with respect to the luminance - cinfo.comp_info[0].h_samp_factor = 2; // Y - cinfo.comp_info[0].v_samp_factor = 1; - cinfo.comp_info[1].h_samp_factor = 1; // Cb - cinfo.comp_info[1].v_samp_factor = 1; - cinfo.comp_info[2].h_samp_factor = 1; // Cr - cinfo.comp_info[2].v_samp_factor = 1; - } - else if ((flags & JPEG_SUBSAMPLING_444) == JPEG_SUBSAMPLING_444){ //1x1 (no subsampling) + cinfo.comp_info[0].h_samp_factor = 2; // Y + cinfo.comp_info[0].v_samp_factor = 1; + cinfo.comp_info[1].h_samp_factor = 1; // Cb + cinfo.comp_info[1].v_samp_factor = 1; + cinfo.comp_info[2].h_samp_factor = 1; // Cr + cinfo.comp_info[2].v_samp_factor = 1; + } + else if ((flags & JPEG_SUBSAMPLING_444) == JPEG_SUBSAMPLING_444){ //1x1 (no subsampling) // 4:4:4 (1x1 1x1 1x1) - CrH 100% - CbH 100% - CrV 100% - CbV 100% - // the resolution of chrominance information (Cb & Cr) is preserved + // the resolution of chrominance information (Cb & Cr) is preserved // at the same rate as the luminance (Y) information - cinfo.comp_info[0].h_samp_factor = 1; // Y - cinfo.comp_info[0].v_samp_factor = 1; - cinfo.comp_info[1].h_samp_factor = 1; // Cb - cinfo.comp_info[1].v_samp_factor = 1; - cinfo.comp_info[2].h_samp_factor = 1; // Cr - cinfo.comp_info[2].v_samp_factor = 1; - } + cinfo.comp_info[0].h_samp_factor = 1; // Y + cinfo.comp_info[0].v_samp_factor = 1; + cinfo.comp_info[1].h_samp_factor = 1; // Cb + cinfo.comp_info[1].v_samp_factor = 1; + cinfo.comp_info[2].h_samp_factor = 1; // Cr + cinfo.comp_info[2].v_samp_factor = 1; + } } // Step 4: set quality @@ -1561,17 +1565,17 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void jpeg_set_quality(&cinfo, quality, TRUE); /* limit to baseline-JPEG values */ - // Step 5: Start compressor + // Step 5: Start compressor jpeg_start_compress(&cinfo, TRUE); // Step 6: Write special markers - + if ((flags & JPEG_BASELINE) != JPEG_BASELINE) { write_markers(&cinfo, dib); } - // Step 7: while (scan lines remain to be written) + // Step 7: while (scan lines remain to be written) if (color_type == FIC_RGB) { // 24-bit RGB image : need to swap red and blue channels @@ -1603,11 +1607,11 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void if (!target) { throw FI_MSG_ERROR_MEMORY; } - + while (cinfo.next_scanline < cinfo.image_height) { // get a copy of the scanline memcpy(target, FreeImage_GetScanLine(dib, FreeImage_GetHeight(dib) - cinfo.next_scanline - 1), pitch); - + uint8_t *target_p = target; for (unsigned x = 0; x < cinfo.image_width; x++) { // CMYK pixels are inverted @@ -1618,7 +1622,7 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void target_p += 4; } - + // write the scanline jpeg_write_scanlines(&cinfo, &target, 1); } @@ -1683,11 +1687,11 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void free(target); } - // Step 8: Finish compression + // Step 8: Finish compression jpeg_finish_compress(&cinfo); - // Step 9: release JPEG compression object + // Step 9: release JPEG compression object jpeg_destroy_compress(&cinfo); @@ -1698,7 +1702,7 @@ Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void FreeImage_OutputMessageProc(s_format_id, text); } return FALSE; - } + } } return FALSE; diff --git a/Source/Plugins/PluginTIFF.cpp b/Source/Plugins/PluginTIFF.cpp index 1679df3..16c6bfd 100644 --- a/Source/Plugins/PluginTIFF.cpp +++ b/Source/Plugins/PluginTIFF.cpp @@ -1,7 +1,7 @@ // ========================================================== // TIFF Loader and Writer // -// Design and implementation by +// Design and implementation by // - Floris van den Berg (flvdberg@wxs.nl) // - Herve Drolon (drolon@infonie.fr) // - Markus Loibl (markus.loibl@epost.de) @@ -24,7 +24,7 @@ // Use at your own risk! // ========================================================== -#ifdef _MSC_VER +#ifdef _MSC_VER #pragma warning (disable : 4786) // identifier was truncated to 'number' characters #endif @@ -72,10 +72,10 @@ void tiff_ConvertLineRGBToXYZ(uint8_t *target, uint8_t *source, int width_in_pix /** Supported loading methods */ typedef enum { - LoadAsRBGA = 0, - LoadAsCMYK = 1, - LoadAs8BitTrns = 2, - LoadAsGenericStrip = 3, + LoadAsRBGA = 0, + LoadAsCMYK = 1, + LoadAs8BitTrns = 2, + LoadAsGenericStrip = 3, LoadAsTiled = 4, LoadAsLogLuv = 5, LoadAsHalfFloat = 6 @@ -133,10 +133,10 @@ typedef struct { } fi_TIFFIO; // ---------------------------------------------------------- -// libtiff interface +// libtiff interface // ---------------------------------------------------------- -static tmsize_t +static tmsize_t _tiffReadProc(thandle_t handle, void *buf, tmsize_t size) { fi_TIFFIO *fio = (fi_TIFFIO*)handle; return fio->io->read_proc(buf, (unsigned)size, 1, fio->handle) * size; @@ -207,7 +207,7 @@ msdosWarningHandler(const char* module, const char* fmt, va_list ap) { static void msdosErrorHandler(const char* module, const char* fmt, va_list ap) { - + // use this for diagnostic only (do not use otherwise, even in DEBUG mode) /* if (module) { @@ -264,7 +264,7 @@ GetPhotometric(FIBITMAP *dib) { /** Get the resolution from the TIFF and fill the dib with universal units */ -static void +static void ReadResolution(TIFF *tiff, FIBITMAP *dib) { float fResX = 300.0; float fResY = 300.0; @@ -273,7 +273,7 @@ ReadResolution(TIFF *tiff, FIBITMAP *dib) { TIFFGetField(tiff, TIFFTAG_RESOLUTIONUNIT, &resUnit); TIFFGetField(tiff, TIFFTAG_XRESOLUTION, &fResX); TIFFGetField(tiff, TIFFTAG_YRESOLUTION, &fResY); - + // If we don't have a valid resolution unit and valid resolution is specified then assume inch if (resUnit == RESUNIT_NONE && fResX > 0.0 && fResY > 0.0) { resUnit = RESUNIT_INCH; @@ -290,7 +290,7 @@ ReadResolution(TIFF *tiff, FIBITMAP *dib) { /** Set the resolution to the TIFF using english units */ -static void +static void WriteResolution(TIFF *tiff, FIBITMAP *dib) { double res; @@ -306,10 +306,14 @@ WriteResolution(TIFF *tiff, FIBITMAP *dib) { /** Fill the dib palette according to the TIFF photometric */ -static void +static void ReadPalette(TIFF *tiff, uint16_t photometric, uint16_t bitspersample, FIBITMAP *dib) { FIRGBA8 *pal = FreeImage_GetPalette(dib); + if (!pal) { + return; + } + switch (photometric) { case PHOTOMETRIC_MINISBLACK: // bitmap and greyscale image types case PHOTOMETRIC_MINISWHITE: @@ -350,7 +354,7 @@ ReadPalette(TIFF *tiff, uint16_t photometric, uint16_t bitspersample, FIBITMAP * uint16_t *green; uint16_t *blue; - TIFFGetField(tiff, TIFFTAG_COLORMAP, &red, &green, &blue); + TIFFGetField(tiff, TIFFTAG_COLORMAP, &red, &green, &blue); // load the palette in the DIB @@ -358,13 +362,13 @@ ReadPalette(TIFF *tiff, uint16_t photometric, uint16_t bitspersample, FIBITMAP * for (int i = (1 << bitspersample) - 1; i >= 0; i--) { pal[i].red =(uint8_t) CVT(red[i]); pal[i].green = (uint8_t) CVT(green[i]); - pal[i].blue = (uint8_t) CVT(blue[i]); + pal[i].blue = (uint8_t) CVT(blue[i]); } } else { for (int i = (1 << bitspersample) - 1; i >= 0; i--) { pal[i].red = (uint8_t) red[i]; pal[i].green = (uint8_t) green[i]; - pal[i].blue = (uint8_t) blue[i]; + pal[i].blue = (uint8_t) blue[i]; } } @@ -372,7 +376,7 @@ ReadPalette(TIFF *tiff, uint16_t photometric, uint16_t bitspersample, FIBITMAP * } } -/** +/** Allocate a FIBITMAP @param header_only If TRUE, allocate a 'header only' FIBITMAP, otherwise allocate a full FIBITMAP @param fit Image type @@ -382,7 +386,7 @@ Allocate a FIBITMAP @param samplesperpixel # samples per pixel @return Returns the allocated image if successful, returns NULL otherwise */ -static FIBITMAP* +static FIBITMAP* CreateImageType(FIBOOL header_only, FREE_IMAGE_TYPE fit, int width, int height, uint16_t bitspersample, uint16_t samplesperpixel) { FIBITMAP *dib{}; @@ -394,7 +398,7 @@ CreateImageType(FIBOOL header_only, FREE_IMAGE_TYPE fit, int width, int height, int bpp = bitspersample * samplesperpixel; if (fit == FIT_BITMAP) { - // standard bitmap type + // standard bitmap type if (bpp == 16) { @@ -422,17 +426,17 @@ CreateImageType(FIBOOL header_only, FREE_IMAGE_TYPE fit, int width, int height, return dib; } -/** +/** Read the TIFFTAG_SAMPLEFORMAT tag and convert to FREE_IMAGE_TYPE @param tiff LibTIFF TIFF Handle @param bitspersample # bit per sample @param samplesperpixel # samples per pixel @return Returns the image type as a FREE_IMAGE_TYPE value */ -static FREE_IMAGE_TYPE +static FREE_IMAGE_TYPE ReadImageType(TIFF *tiff, uint16_t bitspersample, uint16_t samplesperpixel) { uint16_t sampleformat = 0; - FREE_IMAGE_TYPE fit = FIT_BITMAP ; + FREE_IMAGE_TYPE fit = FIT_BITMAP ; uint16_t bpp = bitspersample * samplesperpixel; @@ -557,7 +561,7 @@ ReadImageType(TIFF *tiff, uint16_t bitspersample, uint16_t samplesperpixel) { fit = FIT_RGB16; } } - else if (samplesperpixel >= 4) { + else if (samplesperpixel >= 4) { if (bitspersample > 8 && bitspersample <= 16) { fit = FIT_RGBA16; } @@ -568,12 +572,12 @@ ReadImageType(TIFF *tiff, uint16_t bitspersample, uint16_t samplesperpixel) { return fit; } -/** +/** Convert FREE_IMAGE_TYPE and write TIFFTAG_SAMPLEFORMAT @param tiff LibTIFF TIFF Handle @param fit Image type as a FREE_IMAGE_TYPE value */ -static void +static void WriteImageType(TIFF *tiff, FREE_IMAGE_TYPE fit) { switch (fit) { case FIT_BITMAP: // standard image: 1-, 4-, 8-, 16-, 24-, 32-bit @@ -605,9 +609,9 @@ WriteImageType(TIFF *tiff, FREE_IMAGE_TYPE fit) { /** Select the compression algorithm @param tiff LibTIFF TIFF Handle -@param +@param */ -static void +static void WriteCompression(TIFF *tiff, uint16_t bitspersample, uint16_t samplesperpixel, uint16_t photometric, int flags) { uint16_t compression; uint16_t bitsperpixel = bitspersample * samplesperpixel; @@ -673,13 +677,13 @@ WriteCompression(TIFF *tiff, uint16_t bitspersample, uint16_t samplesperpixel, u TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression); if (compression == COMPRESSION_LZW) { - // This option is only meaningful with LZW compression: a predictor value of 2 - // causes each scanline of the output image to undergo horizontal differencing + // This option is only meaningful with LZW compression: a predictor value of 2 + // causes each scanline of the output image to undergo horizontal differencing // before it is encoded; a value of 1 forces each scanline to be encoded without differencing. - // Found on LibTIFF mailing list : - // LZW without differencing works well for 1-bit images, 4-bit grayscale images, - // and many palette-color images. But natural 24-bit color images and some 8-bit + // Found on LibTIFF mailing list : + // LZW without differencing works well for 1-bit images, 4-bit grayscale images, + // and many palette-color images. But natural 24-bit color images and some 8-bit // grayscale images do much better with differencing. if ((bitspersample == 8) || (bitspersample == 16)) { @@ -702,7 +706,7 @@ WriteCompression(TIFF *tiff, uint16_t bitspersample, uint16_t samplesperpixel, u // try to be compliant with the TIFF Class F specification // that documents the TIFF tags specific to FAX applications // see http://palimpsest.stanford.edu/bytopic/imaging/std/tiff-f.html - uint32_t group3options = GROUP3OPT_2DENCODING | GROUP3OPT_FILLBITS; + uint32_t group3options = GROUP3OPT_2DENCODING | GROUP3OPT_FILLBITS; TIFFSetField(tiff, TIFFTAG_GROUP3OPTIONS, group3options); // 2d-encoded, has aligned EOL TIFFSetField(tiff, TIFFTAG_FILLORDER, FILLORDER_LSB2MSB); // lsb-to-msb fillorder } @@ -716,7 +720,7 @@ WriteCompression(TIFF *tiff, uint16_t bitspersample, uint16_t samplesperpixel, u /** Read the TIFFTAG_RICHTIFFIPTC tag (IPTC/NAA or Adobe Photoshop profile) */ -static FIBOOL +static FIBOOL tiff_read_iptc_profile(TIFF *tiff, FIBITMAP *dib) { uint8_t *profile{}; uint32_t profile_size = 0; @@ -738,7 +742,7 @@ tiff_read_iptc_profile(TIFF *tiff, FIBITMAP *dib) { @param tiff LibTIFF TIFF handle @return Returns TRUE if successful, FALSE otherwise */ -static FIBOOL +static FIBOOL tiff_read_xmp_profile(TIFF *tiff, FIBITMAP *dib) { uint8_t *profile{}; uint32_t profile_size = 0; @@ -768,7 +772,7 @@ tiff_read_xmp_profile(TIFF *tiff, FIBITMAP *dib) { @param tiff LibTIFF TIFF handle @return Returns TRUE if successful, FALSE otherwise */ -static FIBOOL +static FIBOOL tiff_read_exif_profile(FreeImageIO *io, fi_handle handle, TIFF *tiff, FIBITMAP *dib) { FIBOOL bResult = FALSE; toff_t exif_offset = 0; @@ -798,7 +802,7 @@ tiff_read_exif_profile(FreeImageIO *io, fi_handle handle, TIFF *tiff, FIBITMAP * /** Read TIFF special profiles */ -static void +static void ReadMetadata(FreeImageIO *io, fi_handle handle, TIFF *tiff, FIBITMAP *dib) { // IPTC/NAA @@ -819,7 +823,7 @@ ReadMetadata(FreeImageIO *io, fi_handle handle, TIFF *tiff, FIBITMAP *dib) { /** Write the TIFFTAG_RICHTIFFIPTC tag (IPTC/NAA or Adobe Photoshop profile) */ -static FIBOOL +static FIBOOL tiff_write_iptc_profile(TIFF *tiff, FIBITMAP *dib) { if (FreeImage_GetMetadataCount(FIMD_IPTC, dib)) { uint8_t *profile{}; @@ -856,7 +860,7 @@ tiff_write_iptc_profile(TIFF *tiff, FIBITMAP *dib) { @param tiff LibTIFF TIFF handle @return Returns TRUE if successful, FALSE otherwise */ -static FIBOOL +static FIBOOL tiff_write_xmp_profile(TIFF *tiff, FIBITMAP *dib) { FITAG *tag_xmp{}; FreeImage_GetMetadata(FIMD_XMP, dib, g_TagLib_XMPFieldName, &tag_xmp); @@ -880,7 +884,7 @@ tiff_write_xmp_profile(TIFF *tiff, FIBITMAP *dib) { static FIBOOL tiff_write_exif_profile(TIFF *tiff, FIBITMAP *dib) { FIBOOL bResult = FALSE; - + // write EXIF_MAIN tags, EXIF_EXIF not supported yet bResult = tiff_write_exif_tags(tiff, TagLib::EXIF_MAIN, dib); @@ -890,7 +894,7 @@ tiff_write_exif_profile(TIFF *tiff, FIBITMAP *dib) { /** Write TIFF special profiles */ -static void +static void WriteMetadata(TIFF *tiff, FIBITMAP *dib) { // IPTC tiff_write_iptc_profile(tiff, dib); @@ -935,7 +939,7 @@ MimeType() { } static FIBOOL DLL_CALLCONV -Validate(FreeImageIO *io, fi_handle handle) { +Validate(FreeImageIO *io, fi_handle handle) { const uint8_t tiff_id1[] = { 0x49, 0x49, 0x2A, 0x00 }; // Classic TIFF, little-endian const uint8_t tiff_id2[] = { 0x4D, 0x4D, 0x00, 0x2A }; // Classic TIFF, big-endian const uint8_t tiff_id3[] = { 0x49, 0x49, 0x2B, 0x00 }; // Big TIFF, little-endian @@ -967,7 +971,7 @@ SupportsExportDepth(int depth) { ); } -static FIBOOL DLL_CALLCONV +static FIBOOL DLL_CALLCONV SupportsExportType(FREE_IMAGE_TYPE type) { return ( (type == FIT_BITMAP) || @@ -977,9 +981,9 @@ SupportsExportType(FREE_IMAGE_TYPE type) { (type == FIT_INT32) || (type == FIT_FLOAT) || (type == FIT_DOUBLE) || - (type == FIT_COMPLEX) || - (type == FIT_RGB16) || - (type == FIT_RGBA16) || + (type == FIT_COMPLEX) || + (type == FIT_RGB16) || + (type == FIT_RGBA16) || (type == FIT_RGBF) || (type == FIT_RGBAF) ); @@ -1057,14 +1061,14 @@ check for uncommon bitspersample values (e.g. 10, 12, ...) @param samplesperpixel TIFFTAG_SAMPLESPERPIXEL tiff tag @return Returns FALSE if a uncommon bit-depth is encountered, returns TRUE otherwise */ -static FIBOOL +static FIBOOL IsValidBitsPerSample(uint16_t photometric, uint16_t bitspersample, uint16_t samplesperpixel) { switch (bitspersample) { case 1: case 2: case 4: - if ((photometric == PHOTOMETRIC_MINISWHITE) || (photometric == PHOTOMETRIC_MINISBLACK) || (photometric == PHOTOMETRIC_PALETTE)) { + if ((photometric == PHOTOMETRIC_MINISWHITE) || (photometric == PHOTOMETRIC_MINISBLACK) || (photometric == PHOTOMETRIC_PALETTE)) { return TRUE; } else { return FALSE; @@ -1086,14 +1090,14 @@ IsValidBitsPerSample(uint16_t photometric, uint16_t bitspersample, uint16_t samp return FALSE; } case 16: - if (photometric != PHOTOMETRIC_PALETTE) { + if (photometric != PHOTOMETRIC_PALETTE) { return TRUE; } else { return FALSE; } break; case 32: - if ((photometric == PHOTOMETRIC_MINISWHITE) || (photometric == PHOTOMETRIC_MINISBLACK) || (photometric == PHOTOMETRIC_LOGLUV)) { + if ((photometric == PHOTOMETRIC_MINISWHITE) || (photometric == PHOTOMETRIC_MINISBLACK) || (photometric == PHOTOMETRIC_LOGLUV)) { return TRUE; } else if ((photometric == PHOTOMETRIC_RGB) && (samplesperpixel == 3) || (samplesperpixel == 4)) { // RGB[A]F @@ -1104,7 +1108,7 @@ IsValidBitsPerSample(uint16_t photometric, uint16_t bitspersample, uint16_t samp break; case 64: case 128: - if (photometric == PHOTOMETRIC_MINISBLACK) { + if (photometric == PHOTOMETRIC_MINISBLACK) { return TRUE; } else { return FALSE; @@ -1115,7 +1119,7 @@ IsValidBitsPerSample(uint16_t photometric, uint16_t bitspersample, uint16_t samp } } -static TIFFLoadMethod +static TIFFLoadMethod FindLoadMethod(TIFF *tif, FREE_IMAGE_TYPE image_type, int flags) { uint16_t bitspersample = (uint16_t)-1; uint16_t samplesperpixel = (uint16_t)-1; @@ -1135,9 +1139,9 @@ FindLoadMethod(TIFF *tif, FREE_IMAGE_TYPE image_type, int flags) { // convert to 24 or 32 bits RGB if the image is full color case PHOTOMETRIC_RGB: if ((image_type == FIT_RGB16) || (image_type == FIT_RGBA16)) { - // load 48-bit RGB and 64-bit RGBA without conversion + // load 48-bit RGB and 64-bit RGBA without conversion loadMethod = LoadAsGenericStrip; - } + } else if (image_type == FIT_RGBF) { if ((samplesperpixel == 3) && (bitspersample == 16)) { // load 3 x 16-bit half as RGBF @@ -1155,11 +1159,11 @@ FindLoadMethod(TIFF *tif, FREE_IMAGE_TYPE image_type, int flags) { loadMethod = LoadAsLogLuv; break; case PHOTOMETRIC_SEPARATED: - // if image is PHOTOMETRIC_SEPARATED _and_ comes with an ICC profile, - // then the image should preserve its original (CMYK) colour model and - // should be read as CMYK (to keep the match of pixel and profile and - // to avoid multiple conversions. Conversion can be done by changing - // the profile from it's original CMYK to an RGB profile with an + // if image is PHOTOMETRIC_SEPARATED _and_ comes with an ICC profile, + // then the image should preserve its original (CMYK) colour model and + // should be read as CMYK (to keep the match of pixel and profile and + // to avoid multiple conversions. Conversion can be done by changing + // the profile from it's original CMYK to an RGB profile with an // apropriate color management system. Works with non-tiled TIFFs. if (!bIsTiled) { loadMethod = LoadAsCMYK; @@ -1199,7 +1203,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data); /** Read embedded thumbnail */ -static void +static void ReadThumbnail(FreeImageIO *io, fi_handle handle, void *data, TIFF *tiff, FIBITMAP *dib) { std::unique_ptr thumbnail(nullptr, &FreeImage_Unload); @@ -1208,22 +1212,22 @@ ReadThumbnail(FreeImageIO *io, fi_handle handle, void *data, TIFF *tiff, FIBITMA /* // this code can cause unwanted recursion causing an overflow, it is thus disabled until we have a better solution // do we really need to read a thumbnail from the Exif segment ? knowing that TIFF store the thumbnail in the subIFD ... - // + // toff_t exif_offset = 0; if (TIFFGetField(tiff, TIFFTAG_EXIFIFD, &exif_offset)) { - + if (!TIFFLastDirectory(tiff)) { // save current position const long tell_pos = io->tell_proc(handle); const uint16_t cur_dir = TIFFCurrentDirectory(tiff); - + // load the thumbnail int page = 1; int flags = TIFF_DEFAULT; thumbnail.reset(Load(io, handle, page, flags, data)); // store the thumbnail (remember to release it before return) FreeImage_SetThumbnail(dib, thumbnail.get()); - + // restore current position io->seek_proc(handle, tell_pos, SEEK_SET); TIFFSetDirectory(tiff, cur_dir); @@ -1238,17 +1242,17 @@ ReadThumbnail(FreeImageIO *io, fi_handle handle, void *data, TIFF *tiff, FIBITMA toff_t* subIFD_offsets{}; // This will also read the first (and only) subIFD from a Photoshop-created "pyramid" file. - // Subsequent, smaller images are 'nextIFD' in that subIFD. Currently we only load the first one. - + // Subsequent, smaller images are 'nextIFD' in that subIFD. Currently we only load the first one. + if (TIFFGetField(tiff, TIFFTAG_SUBIFD, &subIFD_count, &subIFD_offsets)) { if (subIFD_count > 0) { // save current position const long tell_pos = io->tell_proc(handle); const uint16_t cur_dir = TIFFCurrentDirectory(tiff); - + if (TIFFSetSubDirectory(tiff, subIFD_offsets[0])) { // load the thumbnail - int page = -1; + int page = -1; int flags = TIFF_DEFAULT; thumbnail.reset(Load(io, handle, page, flags, data)); // store the thumbnail (remember to release it before return) @@ -1261,13 +1265,13 @@ ReadThumbnail(FreeImageIO *io, fi_handle handle, void *data, TIFF *tiff, FIBITMA } } } - + // ... or read Photoshop thumbnail - + if (!thumbnail) { uint32_t ps_size = 0; void *ps_data{}; - + if (TIFFGetField(tiff, TIFFTAG_PHOTOSHOP, &ps_size, &ps_data)) { FIMEMORY *handle = FreeImage_OpenMemory((uint8_t*)ps_data, ps_size); @@ -1317,17 +1321,17 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { } TIFF *tif{}; - uint32_t height = 0; - uint32_t width = 0; + uint32_t height = 0; + uint32_t width = 0; uint16_t bitspersample = 1; uint16_t samplesperpixel = 1; - uint32_t rowsperstrip = (uint32_t)-1; + uint32_t rowsperstrip = (uint32_t)-1; uint16_t photometric = PHOTOMETRIC_MINISWHITE; uint16_t compression = (uint16_t)-1; uint16_t planar_config; uint32_t iccSize = 0; // ICC profile length - void *iccBuf{}; // ICC profile data + void *iccBuf{}; // ICC profile data const FIBOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS; @@ -1375,12 +1379,19 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { // --------------------------------------------------------------------------------- if (!IsValidBitsPerSample(photometric, bitspersample, samplesperpixel)) { - FreeImage_OutputMessageProc(s_format_id, - "Unable to handle this format: bitspersample = %d, samplesperpixel = %d, photometric = %d", + FreeImage_OutputMessageProc(s_format_id, + "Unable to handle this format: bitspersample = %d, samplesperpixel = %d, photometric = %d", (int)bitspersample, (int)samplesperpixel, (int)photometric); throw (char*)nullptr; } + if (planar_config == PLANARCONFIG_SEPARATE && bitspersample < 8) { + FreeImage_OutputMessageProc(s_format_id, + "Unable to handle this format: bitspersample = 8, TIFFTAG_PLANARCONFIG = PLANARCONFIG_SEPARATE" + ); + throw (char*)NULL; + } + // --------------------------------------------------------------------------------- // get image data type @@ -1399,9 +1410,9 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { // RGB[A] loading using the TIFFReadRGBAImage() API // --------------------------------------------------------------------------------- - FIBOOL has_alpha = FALSE; + FIBOOL has_alpha = FALSE; - // Read the whole image into one big RGBA buffer and then + // Read the whole image into one big RGBA buffer and then // convert it to a DIB. This is using the traditional // TIFFReadRGBAImage() API that we trust. @@ -1418,7 +1429,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { } } // TIFFReadRGBAImage always deliveres 3 or 4 samples per pixel images - // (RGB or RGBA, see below). Cut-off possibly present channels (additional + // (RGB or RGBA, see below). Cut-off possibly present channels (additional // alpha channels) from e.g. Photoshop. Any CMYK(A..) is now treated as RGB, // any additional alpha channel on RGB(AA..) is lost on conversion to RGB(A) @@ -1427,7 +1438,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { samplesperpixel = 4; } - // create a new DIB (take care of different samples-per-pixel in case + // create a new DIB (take care of different samples-per-pixel in case // of converted CMYK image (RGB conversion is on sample per pixel less) if (photometric == PHOTOMETRIC_SEPARATED && samplesperpixel == 4) { @@ -1438,7 +1449,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { if (!dib) { throw FI_MSG_ERROR_DIB_MEMORY; } - + // fill in the resolution (english or universal) ReadResolution(tif, dib.get()); @@ -1447,7 +1458,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { // read the raster lines and save them in the DIB // with RGB mode, we have to change the order of the 3 samples RGB - // We use macros for extracting components from the packed ABGR + // We use macros for extracting components from the packed ABGR // form returned by TIFFReadRGBAImage. const auto *row = safeRaster.get(); @@ -1518,11 +1529,11 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { // transparency table for 8-bit + 8-bit alpha images - uint8_t trns[256]; + uint8_t trns[256]; // clear the transparency table memset(trns, 0xFF, 256 * sizeof(uint8_t)); - // In the tiff file the lines are saved from up to down + // In the tiff file the lines are saved from up to down // In a DIB the lines must be saved from down to up uint8_t *bits = FreeImage_GetScanLine(dib.get(), height - 1); @@ -1591,7 +1602,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { } } } - + FreeImage_SetTransparencyTable(dib.get(), &trns[0], 256); FreeImage_SetTransparent(dib.get(), TRUE); @@ -1602,7 +1613,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { // At this place, samplesperpixel could be > 4, esp. when a CMYK(A) format // is recognized. Where all other formats are handled straight-forward, this - // format has to be handled special + // format has to be handled special FIBOOL isCMYKA = (photometric == PHOTOMETRIC_SEPARATED) && (samplesperpixel > 4); @@ -1629,7 +1640,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { alpha_pitch = FreeImage_GetPitch(alpha.get()); alpha_Bpp = FreeImage_GetBPP(alpha.get()) / 8; } - + } // create a new DIB @@ -1654,9 +1665,9 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { const unsigned Bpc = dibBpp / chCount; const unsigned srcBpp = bitspersample * samplesperpixel / 8; - assert(Bpc <= 2); //< CMYK is only uint8_t or SHORT - - // In the tiff file the lines are save from up to down + assert(Bpc <= 2); //< CMYK is only uint8_t or SHORT + + // In the tiff file the lines are save from up to down // In a DIB the lines must be saved from down to up uint8_t *bits = FreeImage_GetScanLine(dib.get(), height - 1); @@ -1689,7 +1700,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { pixel[b] = src_pixel[b]; } // TODO write the remaining bytes to extra channel(s) - + // HACK write the first alpha to a separate dib (assume uint8_t or uint16_t) al_pixel[0] = src_pixel[b]; if (Bpc > 1) { @@ -1710,7 +1721,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { } } } - else { + else { // CMYK to CMYK for (uint32_t l = 0; l < strips; l++) { uint8_t *b = buf.get() + l * src_line; @@ -1720,7 +1731,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { } } // height - + } else if (planar_config == PLANARCONFIG_SEPARATE) { @@ -1731,15 +1742,15 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { for (uint32_t y = 0; y < height; y += rowsperstrip) { const uint32_t strips = std::min(height - y, rowsperstrip); - + // - loop for channels (planes) - - + for (uint16_t sample = 0; sample < samplesperpixel; sample++) { - + if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, y, sample), buf.get(), strips * src_line) == -1) { throw FI_MSG_ERROR_PARSING; - } - + } + uint8_t *dst_strip = dib_strip; unsigned dst_pitch = dib_pitch; uint16_t ch = sample; @@ -1747,7 +1758,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { if (sample >= chCount) { // TODO Write to Extra Channel - + // HACK redirect write to temp alpha if (alpha && sample == chCount) { @@ -1758,7 +1769,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { Bpp = alpha_Bpp; } else { - break; + break; } } @@ -1828,7 +1839,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { // set up the colormap based on photometric ReadPalette(tif, photometric, bitspersample, dib.get()); - + if (!header_only) { // calculate the line + pitch (separate for scr & dest) @@ -1839,7 +1850,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { const unsigned srcBpp = bitspersample * samplesperpixel / 8; const unsigned srcBits = bitspersample * samplesperpixel; - // In the tiff file the lines are save from up to down + // In the tiff file the lines are save from up to down // In a DIB the lines must be saved from down to up uint8_t *bits = FreeImage_GetScanLine(dib.get(), height - 1); @@ -2001,7 +2012,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { // read the tiff lines and save them in the DIB if (planar_config == PLANARCONFIG_CONTIG && !header_only) { - + // get the maximum number of bytes required to contain a tile const tmsize_t tileSize = TIFFTileSize(tif); @@ -2013,12 +2024,16 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { const uint32_t tileRowSize = (uint32_t)TIFFTileRowSize(tif); const uint32_t imageRowSize = (uint32_t)TIFFScanlineSize(tif); + if (width / tileWidth * tileRowSize * 8 > bitspersample * samplesperpixel * width) { + free(tileBuffer); + throw "Corrupted tiled TIFF file"; + } - // In the tiff file the lines are saved from up to down + // In the tiff file the lines are saved from up to down // In a DIB the lines must be saved from down to up uint8_t *bits = FreeImage_GetScanLine(dib.get(), height - 1); - + for (uint32_t y = 0; y < height; y += tileHeight) { const uint32_t nrows = std::min(height - y, tileHeight); @@ -2082,7 +2097,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { const tmsize_t src_line = TIFFScanlineSize(tif); const int dst_pitch = FreeImage_GetPitch(dib.get()); - // In the tiff file the lines are save from up to down + // In the tiff file the lines are save from up to down // In a DIB the lines must be saved from down to up uint8_t *bits = FreeImage_GetScanLine(dib.get(), height - 1); @@ -2131,7 +2146,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { const tmsize_t src_line = TIFFScanlineSize(tif); const unsigned dst_pitch = FreeImage_GetPitch(dib.get()); - // In the tiff file the lines are save from up to down + // In the tiff file the lines are save from up to down // In a DIB the lines must be saved from down to up uint8_t *bits = FreeImage_GetScanLine(dib.get(), height - 1); @@ -2147,7 +2162,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, y, 0), buf.get(), nrow * src_line) == -1) { throw FI_MSG_ERROR_PARSING; - } + } // convert from half (16-bit) to float (32-bit) // !!! use OpenEXR half helper class @@ -2171,7 +2186,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { // this use case was never encountered yet throw "Unable to handle PLANARCONFIG_SEPARATE RGB half float images"; } - + } // !header only } else { @@ -2181,13 +2196,13 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { throw FI_MSG_ERROR_UNSUPPORTED_FORMAT; } - + // copy TIFF metadata (must be done after FreeImage_Allocate) ReadMetadata(io, handle, tif, dib.get()); // copy ICC profile data (must be done after FreeImage_Allocate) - + FreeImage_CreateICCProfile(dib.get(), iccBuf, iccSize); if (photometric == PHOTOMETRIC_SEPARATED) { if (asCMYK) { @@ -2201,7 +2216,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { } // copy TIFF thumbnail (must be done after FreeImage_Allocate) - + ReadThumbnail(io, handle, data, tif, dib.get()); return dib.release(); @@ -2233,7 +2248,7 @@ Save a single image into a TIF @param ifdCount 1 if no thumbnail to save, 2 if image + thumbnail to save @return Returns TRUE if successful, returns FALSE otherwise */ -static FIBOOL +static FIBOOL SaveOneTIFF(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data, unsigned ifd, unsigned ifdCount) { if (!dib || !handle || !data) { return FALSE; @@ -2250,9 +2265,9 @@ SaveOneTIFF(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flag const uint16_t bitsperpixel = (uint16_t)FreeImage_GetBPP(dib); const FIICCPROFILE* iccProfile = FreeImage_GetICCProfile(dib); - + // setup out-variables based on dib and flag options - + uint16_t bitspersample; uint16_t samplesperpixel; uint16_t photometric; @@ -2280,7 +2295,7 @@ SaveOneTIFF(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flag } else if (photometric == PHOTOMETRIC_RGB) { // transparency mask support - uint16_t sampleinfo[1]; + uint16_t sampleinfo[1]; // unassociated alpha data is transparency information sampleinfo[0] = EXTRASAMPLE_UNASSALPHA; TIFFSetField(out, TIFFTAG_EXTRASAMPLES, 1, sampleinfo); @@ -2306,7 +2321,7 @@ SaveOneTIFF(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flag else { photometric = PHOTOMETRIC_RGB; // transparency mask support - uint16_t sampleinfo[1]; + uint16_t sampleinfo[1]; // unassociated alpha data is transparency information sampleinfo[0] = EXTRASAMPLE_UNASSALPHA; TIFFSetField(out, TIFFTAG_EXTRASAMPLES, 1, sampleinfo); @@ -2320,7 +2335,7 @@ SaveOneTIFF(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flag if ((flags & TIFF_LOGLUV) == TIFF_LOGLUV) { photometric = PHOTOMETRIC_LOGLUV; TIFFSetField(out, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_FLOAT); - // TIFFSetField(out, TIFFTAG_STONITS, 1.0); // assume unknown + // TIFFSetField(out, TIFFTAG_STONITS, 1.0); // assume unknown } else { // store with default compression (LZW) or with input compression flag @@ -2344,7 +2359,7 @@ SaveOneTIFF(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flag // set image data type WriteImageType(out, image_type); - + // write possible ICC profile if (iccProfile->size && iccProfile->data) { @@ -2358,10 +2373,10 @@ SaveOneTIFF(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flag TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel); TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, bitspersample); TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric); - TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); // single image plane + TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); // single image plane TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); TIFFSetField(out, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB); - TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(out, (uint32_t) -1)); + TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(out, (uint32_t) -1)); // handle metrics @@ -2378,7 +2393,7 @@ SaveOneTIFF(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flag TIFFSetField(out, TIFFTAG_PAGENAME, page_number); } else { - // is it a thumbnail ? + // is it a thumbnail ? TIFFSetField(out, TIFFTAG_SUBFILETYPE, (ifd == 0) ? (uint32_t)0 : (uint32_t)FILETYPE_REDUCEDIMAGE); } @@ -2489,9 +2504,9 @@ SaveOneTIFF(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flag #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR if (photometric != PHOTOMETRIC_SEPARATED) { // TIFFs store color data RGB(A) instead of BGR(A) - + auto *pBuf = static_cast(buffer.get()); - + for (uint32_t x = 0; x < width; x++) { INPLACESWAP(pBuf[0], pBuf[2]); pBuf += samplesperpixel; @@ -2587,7 +2602,7 @@ InitTIFF(Plugin *plugin, int format_id) { // Set up the callback for extended TIFF directory tag support (see XTIFF.cpp) // Must be called before using libtiff - XTIFFInitialize(); + XTIFFInitialize(); plugin->format_proc = Format; plugin->description_proc = Description;