turbojpeg.c


Log

Author Commit Date CI Message
DRC 7bb958b7 2024-03-04T12:12:03 12-bit: Don't gen opt Huff tbls if tbls supplied (regression introduced by e8b40f3c2ba187ba95c13c3e8ce21c8534256df7) The documented behavior of the libjpeg API is to compute optimal Huffman tables when generating 12-bit lossy Huffman-coded JPEG images, unless the calling application supplies its own Huffman tables. However, e8b40f3c2ba187ba95c13c3e8ce21c8534256df7 and 96bc40c1b36775afdbad4ae05a6b3f48e2eebeb9 modified jinit_c_master_control() so that it always set cinfo->optimize_coding to TRUE when generarating 12-bit lossy Huffman-coded JPEG images, which prevented calling applications from supplying custom Huffman tables for such images. This commit modifies jinit_c_master_control() so that it only overrides cinfo->optimize_coding when generating 12-bit lossy Huffman-coded JPEG images if all Huffman table slots are empty or all slots contain default Huffman tables. Determining whether the latter is true requires using memcmp() to compare the allocated Huffman tables with the default Huffman tables, because: - The documented behavior of jpeg_set_defaults() is to initialize any empty Huffman table slot with the default Huffman table corresponding to that slot, regardless of the data precision. There is also no requirement that the data precision be specified prior to calling jpeg_set_defaults(). Thus, there is no reliable way to prevent jpeg_set_defaults() from initializing empty Huffman table slots with default Huffman tables, which are useless for 12-bit data precision. - There is no requirement that custom Huffman tables be defined prior to calling jpeg_set_defaults(). A calling application could call jpeg_set_defaults() and modify the values in the default Huffman tables rather than allocating new tables. Thus, there is no reliable way to detect whether the allocated Huffman tables contain default values without comparing the tables with the default Huffman tables. Fortunately, comparing the allocated Huffman tables with the default Huffman tables is the last stop on the logic train, so it won't happen unless cinfo->data_precision == 12, cinfo->arith_code == FALSE, cinfo->optimize_coding == FALSE, and one or more Huffman tables are allocated. (If the compressor object is reused, this ensures that the full comparison will be performed at most once.) Custom Huffman tables will be flagged as non-default when the first non-default value is encountered, and the worst case (comparing 400 bytes) is very fast on modern CPUs anyhow. Fixes #751
DRC 55d342c7 2023-11-16T15:36:47 TurboJPEG: Expose/extend hidden "max pixels" param TJPARAM_MAXPIXELS was previously hidden and used only for fuzz testing, but it is potentially useful for calling applications as well, particularly if they want to guard against excessive memory consumption by the tj3LoadImage*() functions. The parameter has also been extended to decompression and lossless transformation functions/methods, mainly as a convenience. (It was already possible for calling applications to impose their own JPEG image size limits by reading the JPEG header prior to decompressing or transforming the image.)
DRC 8a4ce73c 2023-11-15T10:54:58 tj3Transform(): Range check transform operations
DRC a27bad65 2023-11-14T14:47:40 tj3Transform(): Ensure JPEG hdr successfully read Because of the TurboJPEG 3 API overhaul, the legacy decompression and lossless transformation functions now wrap the new TurboJPEG 3 functions. For performance reasons, we don't want to read the JPEG header more than once during the same operation, so the wrapped functions do not read the header if it has already been read by a wrapper function. Initially the TurboJPEG 3 functions used a state variable to track whether the header had already been read, but b94041390c477a02b3cab79d0cc0ef321dc889e8 made this more robust by using the libjpeg global decompression state instead. If a wrapper function has already read the JPEG header successfully, then the global decompression state will be DSTATE_READY, and the logic introduced in b94041390c477a02b3cab79d0cc0ef321dc889e8 will prevent the header from being read again. A subtle issue arises because tj3DecompressHeader() does not call jpeg_abort_decompress() if jpeg_read_header() fails. (That is arguably a bug, but it has existed since the very first implementation of the function.) Depending on the nature of the failure, this can cause tj3DecompressHeader() to return an error code and leave the libjpeg global decompression state set to DSTATE_INHEADER. If a misbehaved application ignored the error and subsequently called a TurboJPEG decompression or lossless transformation function, then the function would fail to read the JPEG header because the global decompression state was greater than DSTATE_START. In the case of the decompression functions, this was innocuous, because jpeg_calc_output_dimensions() and jpeg_start_decompress() both sanity check the global decompression state. However, it was possible for a misbehaved application to call tj3DecompressHeader() with junk data, ignore the return value, and pass the same junk data into tj3Transform(). Because tj3DecompressHeader() left the global decompression state set to DSTATE_INHEADER, tj3Transform() failed to detect the junk data (because it didn't try to read the JPEG header), and it called jtransform_request_workspace() with dinfo->image_width and dinfo->image_height still initialized to 0. Because jtransform_request_workspace() does not sanity check the decompression state, a division-by-zero error occurred with certain combinations of transform options in which TJXOPT_TRIM or TJXOPT_CROP was specified. However, it should be noted that TJXOPT_TRIM and TJXOPT_CROP cannot be expected to work properly without foreknowledge of the JPEG source image dimensions, which cannot be gained except by calling tj3DecompressHeader() successfully. Thus, a calling application is inviting trouble if it does not check the return value of tj3DecompressHeader() and sanity check the JPEG source image dimensions before calling tj3Transform(). This commit softens the failure, but the failure is still due to improper API usage.
DRC df9dbff8 2023-11-11T12:25:03 TurboJPEG: New param to limit virt array mem usage This corresponds to max_memory_to_use in the jpeg_memory_mgr struct in the libjpeg API, except that the TurboJPEG parameter is specified in megabytes. Because this is 2023 and computers with less than 1 MB of memory are not a thing (at least not within the scope of libjpeg-turbo support), it isn't useful to allow a limit less than 1 MB to be specified. Furthermore, because TurboJPEG parameters are signed integers, if we allowed the memory limit to be specified in bytes, then it would be impossible to specify a limit larger than 2 GB on 64-bit machines. Because max_memory_to_use is a long signed integer, effectively we can specify a limit of up to 2 petabytes on 64-bit machines if the TurboJPEG parameter is specified in megabytes. (2 PB should be enough for anybody, right?) This commit also bumps the TurboJPEG API version to 3.0.1. Since the TurboJPEG API version no longer tracks the libjpeg-turbo version, it makes sense to increment the API revision number when adding constants, to increment the minor version number when adding functions, and to increment the major version number for a complete overhaul. This commit also removes the vestigial TJ_NUMPARAM macro, which was never defined because it proved unnecessary. Partially implements #735
DRC bf248a50 2023-11-11T15:14:07 tj3Compress*(): Free virt arrays if mem limit hit This is very subtle, but if a user specifies a libjpeg virtual array memory limit via the JPEGMEM environment variable and one of the tj3Compress*() functions hits that limit, the libjpeg error handler will be invoked in jpeg_start_compress() (more specifically in realize_virt_arrays() in jinit_compress_master()) before the libjpeg global compression state can be incremented. Thus, jpeg_abort_compress() will not be called before the tj3Compress*() function exits, the unrealized virtual arrays will not be freed, and if the TurboJPEG compression instance is reused, those unrealized virtual arrays will count against the specified memory limit. This could cause subsequent compression operations that require smaller virtual arrays (or even no virtual arrays at all) to fail when they would otherwise succeed. In reality, the vast majority of calling programs would abort and free the TurboJPEG compression instance if one of the tj3Compress*() functions failed, but TJBench is a rare exception. This issue does not bear documenting because of its subtlety and rarity and because JPEGMEM is not a documented feature of the TurboJPEG API. Note that the issue does not exist in the tj3Encode*() and tj3Decode*() functions, because realize_virt_arrays() is never called in the body of those functions. The issue also does not exist in the tj3Decompress*() and tj3Transform() functions, because those functions ensure that the JPEG header is read (and thus the libjpeg global decompression state is incremented) prior to calling a function that calls realize_virt_arrays() (i.e. jpeg_start_decompress() or jpeg_read_coefficients().) If realize_virt_arrays() failed in the body of jpeg_write_coefficients(), then tj3Transform() would abort without calling jpeg_abort_compress(). However, since jpeg_start_compress() is never called in the body of tj3Transform(), no virtual arrays are ever requested from the compression object, so failing to call jpeg_abort_compress() would be innocuous.
DRC 78eaf0d4 2023-11-07T13:44:40 tj3*YUV8(): Fix int overflow w/ huge row alignment If the align parameter was set to an unreasonably large value, such as 0x2000000, strides[0] * ph0 and strides[1] * ph1 could have overflowed the int datatype and wrapped around when computing (src|dst)Planes[1] and (src|dst)Planes[2] (respectively.) This would have caused (src|dst)Planes[1] and (src|dst)Planes[2] to point to lower addresses in the YUV buffer than expected, so the worst case would have been a visually incorrect output image, not a buffer overrun or other exploitable issue.
DRC c8d52f1c 2023-06-26T11:53:03 tj3Transform: Calc dst buf size from xformed dims When used with TJPARAM_NOREALLOC and with TJXOP_TRANSPOSE, TJXOP_TRANSVERSE, TJXOP_ROT90, or TJXOP_ROT270, tj3Transform() incorrectly based the destination buffer size for a transform on the source image dimensions rather than the transformed image dimensions. This was apparently a long-standing bug that had existed in the tj*Transform() function since its inception. As initially implemented in the evolving libjpeg-turbo v1.2 code base, tjTransform() required dstSizes[i] to be set regardless of whether TJFLAG_NOREALLOC (the predecessor to TJPARAM_NOREALLOC) was set. ff78e37595c8462f64fd100f928aa1d08539527e, which was introduced later in the evolving libjpeg-turbo v1.2 code base, removed that requirement and planted the seed for the bug. However, the bug was not activated until 9b49f0e4c77c727648c6d3a4915eefdf5436de4a was introduced still later in the evolving libjpeg-turbo v1.2 code base, adding a subsampling type argument to the (new at the time) tjBufSize() function and thus making the width and height arguments no longer commutative. The bug opened up the possibility that a JPEG source image could cause tj3Transform() to overflow the destination buffer for a transform if all of the following were true: - The JPEG source image used 4:2:2, 4:4:0, 4:1:1, or 4:4:1 subsampling. (These are the only subsampling types for which the width and height arguments to tj3JPEGBufSize() are not commutative.) - The width and height of the JPEG source image were such that tj3JPEGBufSize(height, width, subsamplingType) returned a smaller value than tj3JPEGBufSize(width, height, subsamplingType). - The JPEG source image contained enough metadata that the size of the transformed image was larger than tj3JPEGBufSize(height, width, subsamplingType). - TJPARAM_NOREALLOC was set. - TJXOP_TRANSPOSE, TJXOP_TRANSVERSE, TJXOP_ROT90, or TJXOP_ROT270 was used. - TJXOPT_COPYNONE was not set. - TJXOPT_CROP was not set. - The calling program allocated tj3JPEGBufSize(height, width, subsamplingType) bytes for the destination buffer, as the API documentation instructs. The API documentation cautions that JPEG source images containing a large amount of extraneous metadata (EXIF, IPTC, ICC, etc.) cannot reliably be transformed if TJPARAM_NOREALLOC is set and TJXOPT_COPYNONE is not set. Irrespective of the bug, there are still cases in which a JPEG source image with a large amount of metadata can, when transformed, exceed the worst-case transformed JPEG image size. For instance, if you try to losslessly crop a JPEG image with 3 kB of EXIF data to 16x16 pixels, then you are guaranteed to exceed the worst-case 16x16 JPEG image size unless you discard the EXIF data. Even without the bug, tj3Transform() will still fail with "Buffer passed to JPEG library is too small" when attempting to transform JPEG source images that meet the aforementioned criteria. The bug is that the function segfaults rather than failing gracefully, but the chances of that occurring in a real-world application are very slim. Any real-world application developers who attempted to transform arbitrary JPEG source images with TJPARAM_NOREALLOC set would very quickly realize that they cannot reliably do that without also setting TJXOPT_COPYNONE. Thus, I posit that the actual risk posed by this bug is low. Applications such as web browsers that are the most exposed to security risks from arbitrary JPEG source images do not use the TurboJPEG lossless transform feature. (None of those applications even use the TurboJPEG API, to the best of my knowledge, and the public libjpeg API has no equivalent transform function.) Our only command-line interface to the tj3Transform() function, TJBench, was not exposed to the bug because it had a compatible bug whereby it allocated the JPEG destination buffer to the same size that tj3Transform() erroneously expected. The TurboJPEG Java API was also not exposed to the bug because of a similar compatible bug in the Java_org_libjpegturbo_turbojpeg_TJTransformer_transform() JNI function. (This commit fixes both compatible bugs.) In short, best practices for tj3Transform() are to use TJPARAM_NOREALLOC only with JPEG source images that are known to be free of metadata (such as images generated by tj3Compress*()) or to use TJXOPT_COPYNONE along with TJPARAM_NOREALLOC. Still, however, the function shouldn't segfault as long as the calling program allocates the suggested amount of space for the JPEG destination buffer. Usability notes: tj3Transform() could hypothetically require dstSizes[i] to be set regardless of the value of TJPARAM_NOREALLOC, but there are usability pitfalls either way. The main pitfall I sought to avoid with ff78e37595c8462f64fd100f928aa1d08539527e was a calling program failing to set dstSizes[i] at all, thus leaving its value undefined. It could be argued that requiring dstSizes[i] to be set in all cases is more consistent, but it could also be argued that not requiring it to be set when TJPARAM_NOREALLOC is set is more user-proof. tj3Transform() could also hypothetically set TJXOPT_COPYNONE automatically when TJPARAM_NOREALLOC is set, but that could lead to user confusion. Ultimately, I would like to address these issues in TurboJPEG v4 by using managed buffer objects, but that would be an extensive overhaul.
DRC 54f571f8 2023-01-27T12:31:44 TurboJPEG: Clean up/repurpose THROWI() macro We already had a use case for two integer arguments, and the new use cases benefit from two integer arguments as well.
DRC 8c57aad0 2023-01-27T12:19:16 turbojpeg.c: Use THROWG() macro whenever possible
DRC b9404139 2023-01-27T07:20:10 TurboJPEG: Robustify JPEG header prefetching In decompression and transform functions, use the libjpeg API state rather than a TurboJPEG instance variable to determine whether jpeg_mem_src_tj() and jpeg_read_header() have already been called by a wrapper function.
DRC 96bc40c1 2023-01-26T13:11:58 Implement arithmetic coding with 12-bit precision This actually works and apparently always has worked. It only failed because the libjpeg code, which did not originally support arithmetic coding, assumed that optimize_coding should always be TRUE for 12-bit data precision.
DRC fc01f467 2023-01-05T06:36:46 TurboJPEG 3 API overhaul (ChangeLog update forthcoming) - Prefix all function names with "tj3" and remove version suffixes from function names. (Future API overhauls will increment the prefix to "tj4", etc., thus retaining backward API/ABI compatibility without versioning each individual function.) - Replace stateless boolean flags (including TJ*FLAG_ARITHMETIC and TJ*FLAG_LOSSLESS, which were never released) with stateful integer parameters, the value of which persists between function calls. * Use parameters for the JPEG quality and subsampling as well, in order to eliminate the awkwardness of specifying function arguments that weren't relevant for lossless compression. * tj3DecompressHeader() now stores all relevant information about the JPEG image, including the width, height, subsampling type, entropy coding type, etc. in parameters rather than returning that information in its arguments. * TJ*FLAG_LIMITSCANS has been reimplemented as an integer parameter (TJ*PARAM_SCANLIMIT) that allows the number of scans to be specified. - Use the const keyword for all pointer arguments to unmodified buffers, as well as for both dimensions of 2D pointers. Addresses #395. - Use size_t rather than unsigned long to represent buffer sizes, since unsigned long is a 32-bit type on Windows. Addresses #24. - Return 0 from all buffer size functions if an error occurs, rather than awkwardly trying to return -1 in an unsigned data type. - Implement 12-bit and 16-bit data precision using dedicated compression, decompression, and image I/O functions/methods. * Suffix the names of all data-precision-specific functions with 8, 12, or 16. * Because the YUV functions are intended to be used for video, they are currently only implemented with 8-bit data precision, but they can be expanded to 12-bit data precision in the future, if necessary. * Extend TJUnitTest and TJBench to test 12-bit and 16-bit data precision, using a new -precision option. * Add appropriate regression tests for all of the above to the 'test' target. * Extend tjbenchtest to test 12-bit and 16-bit data precision, and add separate 'tjtest12' and 'tjtest16' targets. * BufferedImage I/O in the Java API is currently limited to 8-bit data precision, since the BufferedImage class does not straightforwardly support higher data precisions. * Extend the PPM reader to convert 12-bit and 16-bit PBMPLUS files to grayscale or CMYK pixels, as it already does for 8-bit files. - Properly accommodate lossless JPEG using dedicated parameters (TJ*PARAM_LOSSLESS, TJ*PARAM_LOSSLESSPSV, and TJ*PARAM_LOSSLESSPT), rather than using a flag and awkwardly repurposing the JPEG quality. Update TJBench to properly reflect whether a JPEG image is lossless. - Re-organize the TJBench usage screen. - Update the Java docs using Java 11, to improve the formatting and eliminate HTML frames. - Use the accurate integer DCT algorithm by default for both compression and decompression, since the "fast" algorithm is a legacy feature, it does not pass the ISO compliance tests, and it is not actually faster on modern x86 CPUs. * Remove the -accuratedct option from TJBench and TJExample. - Re-implement the 'tjtest' target using a CMake script that enables the appropriate tests, depending on the data precision and whether or not the Java API is part of the build. - Consolidate the C and Java versions of tjbenchtest into one script. - Consolidate the C and Java versions of tjexampletest into one script. - Combine all initialization functions into a single function (tj3Init()) that accepts an integer parameter specifying the subsystems to initialize. - Enable decompression scaling explicitly, using a new function/method (tj3SetScalingFactor()/TJDecompressor.setScalingFactor()), rather than implicitly using awkward "desired width"/"desired height" parameters. - Introduce a new macro/constant (TJUNSCALED/TJ.UNSCALED) that maps to a scaling factor of 1/1. - Implement partial image decompression, using a new function/method (tj3SetCroppingRegion()/TJDecompressor.setCroppingRegion()) and TJBench option (-crop). Extend tjbenchtest to test the new feature. Addresses #1. - Allow the JPEG colorspace to be specified explicitly when compressing, using a new parameter (TJ*PARAM_COLORSPACE). This allows JPEG images with the RGB and CMYK colorspaces to be created. - Remove the error/difference image feature from TJBench. Identical images to the ones that TJBench created can be generated using ImageMagick with 'magick composite <original_image> <output_image> -compose difference <diff_image>' - Handle JPEG images with unknown subsampling types. TJ*PARAM_SUBSAMP is set to TJ*SAMP_UNKNOWN (== -1) for such images, but they can still be decompressed fully into packed-pixel images or losslessly transformed (with the exception of lossless cropping.) They cannot be partially decompressed or decompressed into planar YUV images. Note also that TJBench, due to its lack of support for imperfect transforms, requires that the subsampling type be known when rotating, flipping, or transversely transposing an image. Addresses #436 - The Java version of TJBench now has identical functionality to the C version. This was accomplished by (somewhat hackishly) calling the TurboJPEG C image I/O functions through JNI and copying the pixels between the C heap and the Java heap. - Add parameters (TJ*PARAM_RESTARTROWS and TJ*PARAM_RESTARTBLOCKS) and a TJBench option (-restart) to allow the restart marker interval to be specified when compressing. Eliminate the undocumented TJ_RESTART environment variable. - Add a parameter (TJ*PARAM_OPTIMIZE), a transform option (TJ*OPT_OPTIMIZE), and a TJBench option (-optimize) to allow optimized baseline Huffman coding to be specified when compressing. Eliminate the undocumented TJ_OPTIMIZE environment variable. - Add parameters (TJ*PARAM_XDENSITY, TJ*PARAM_DENSITY, and TJ*DENSITYUNITS) to allow the pixel density to be specified when compressing or saving a Windows BMP image and to be queried when decompressing or loading a Windows BMP image. Addresses #77. - Refactor the fuzz targets to use the new API. * Extend decompression coverage to 12-bit and 16-bit data precision. * Replace the awkward cjpeg12 and cjpeg16 targets with proper TurboJPEG-based compress12, compress12-lossless, and compress16-lossless targets - Fix innocuous UBSan warnings uncovered by the new fuzzers. - Implement previous versions of the TurboJPEG API by wrapping the new functions (tested by running the 2.1.x versions of TJBench, via tjbenchtest, and TJUnitTest against the new implementation.) * Remove all JNI functions for deprecated Java methods and implement the deprecated methods using pure Java wrappers. It should be understood that backward API compatibility in Java applies only to the Java classes and that one cannot mix and match a JAR file from one version of libjpeg-turbo with a JNI library from another version. - tj3Destroy() now silently accepts a NULL handle. - tj3Alloc() and tj3Free() now return/accept void pointers, as malloc() and free() do. - The image I/O functions now accept a TurboJPEG instance handle, which is used to transmit/receive parameters and to receive error information. Closes #517
DRC 1a1ea4ee 2023-01-25T12:28:42 Merge branch 'main' into dev
DRC 1485beaa 2023-01-25T12:13:21 turbojpeg.c: Fix UBSan warning (introduced by previous commit)
DRC 8a1526a4 2023-01-25T09:52:06 tjPlane*(): Guard against int overflow tjPlaneWidth() and tjPlaneHeight() could overflow a signed int and return a negative value if passed a width/height argument of INT_MAX and a subsampling type for which the MCU block size is larger than 8x8.
DRC 7ab6222c 2023-01-20T14:09:25 Merge branch 'main' into dev
DRC fb15efe9 2023-01-18T06:44:46 TurboJPEG: More documentation improvements - TJBench/TJUnitTest: Wordsmith command-line output - Java: "decompress operations"="decompression operations" - tjLoadImage(): Error message tweak - Don't mention compression performance in the description of TJXOPT_PROGRESSIVE/TJTransform.OPT_PROGRESSIVE, because the image has already been compressed at that point. (Oversights from 9a146f0f23b01869e1bf7c478e12b43f83d59c32)
DRC d859232d 2023-01-14T18:27:37 TurboJPEG: Use 4:4:4 for lossless JPEG buf calcs
DRC d4589f4f 2023-01-14T18:07:53 Merge branch 'main' into dev
DRC 94a2b953 2023-01-11T15:01:35 tjDecompressToYUV2: Use scaled dims for plane calc The documented behavior of the function is to use decompression scaling to generate the largest possible image that will fit within the desired image dimensions. Thus, if the desired image dimensions are larger than the scaled image dimensions, then tjDecompressToYUV2() should use the scaled image dimensions when computing the plane pointers and strides to pass to tjDecompressToYUVPlanes(). Note that this bug was not previously detected, because tjunittest and tjbench always passed the scaled image dimensions to tjDecompressToYUV2().
DRC 9a146f0f 2023-01-06T10:29:10 TurboJPEG: Numerous documentation improvements - Wordsmithing, formatting, and grammar tweaks - Various clarifications and corrections, including specifying whether a particular buffer or image is used as a source or destination - Accommodate/mention features that were introduced since the API documentation was created. - For clarity, use "packed-pixel" to describe uncompressed source/destination images that are not planar YUV. - Use "row" rather than "line" to refer to a single horizontal group of pixels or component values, for consistency with the libjpeg API documentation. (libjpeg also uses "scanline", which is a more archaic term.) - Use "alignment" rather than "padding" to refer to the number of bytes by which a row's width is evenly divisible. This consistifies the documention of the YUV functions and tjLoadImage(). ("Padding" typically refers to the number of bytes added to each row, which is not the same thing.) - Remove all references to "the underlying codec." Although the TurboJPEG API originated as a cross-platform wrapper for the Intel Integrated Performance Primitives, Sun mediaLib, QuickTime, and libjpeg, none of those TurboJPEG implementations has been maintained since 2009. Nothing would prevent someone from implementing the TurboJPEG API without libjpeg-turbo, but such an implementation would not necessarily have an "underlying codec." (It could be fully self-contained.) - Use "destination image" rather than "output image", for consistency, or describe the type of image that will be output. - Avoid the term "image buffer" and instead use "byte buffer" to refer to buffers that will hold JPEG images, or describe the type of image that will be contained in the buffer. (The Java documentation doesn't use "byte buffer", because the buffer arrays literally have "byte" in front of them, and since Java doesn't have pointers, it is not possible for mere mortals to store any other type of data in those arrays.) - C: Use "unified" to describe YUV images stored in a single buffer, for consistency with the Java documentation. - Use "planar YUV" rather than "YUV planar". Is is our convention to describe images using {component layout} {colorspace/pixel format} {image function}, e.g. "packed-pixel RGB source image" or "planar YUV destination image." - C: Document the TurboJPEG API version in which a particular function or macro was introduced, and reorder the backward compatibility function stubs in turbojpeg.h alphabetically by API version. - C: Use Markdown rather than HTML tags, where possible, in the Doxygen comments.
DRC b03ee8b8 2023-01-05T11:17:40 TurboJPEG: Don't use backward compatibility macros Macros from older versions of the TurboJPEG API are supported but not documented, so using the current version of those macros makes the code more readable.
DRC d2608583 2023-01-05T10:51:12 TurboJPEG: Ensure 'pad' arg is a power of 2 Because the PAD() macro can only handle powers of 2, this is a necessary restriction (and a documented one, except in the case of tjCompressFromYUV()-- oops.) Failing to check the 'pad' argument caused tjBufSizeYUV2() to return bogus results if 'pad' was less than 1 or otherwise not a power of 2. tjEncodeYUV3() and tjDecodeYUV() effectively treated a 'pad' value of 0 as unpadded, but that was subtle and undocumented behavior. tjCompressFromYUV() did not check whether 'pad' was a power of 2, so the strides passed to tjCompressFromYUVPlanes() would have been incorrect if 'pad' was not a power of 2. That would not have caused tjCompressFromYUV() to overrun the source buffer, as long as the calling application allocated the buffer based on the return value of tjBufSizeYUV2() (which computes the strides in the same manner as tjCompressFromYUV().) However, if the calling application attempted to initialize the source buffer using correctly-computed strides, then it could have overrun its own buffer in certain cases or produced incorrect JPEG images in others. Realistically, there is no reason why an application would want to pass a non-power-of-2 'pad' value to a TurboJPEG API function, so this commit is about user-proofing the API rather than fixing any known issue.
DRC e2a98701 2022-11-30T11:06:37 turbojpeg.c: Fix build if !C_LOSSLESS_SUPPORTED
DRC 73ca9712 2022-11-30T11:03:43 Merge branch 'main' into dev
DRC c4105ba7 2022-11-30T10:40:48 turbojpeg.c: Fix build if !C_PROGRESSIVE_SUPPORTED
DRC 140a1ea3 2022-11-22T10:37:19 tjEncodeYUVPlanes(): Ignore TJFLAG_LOSSLESS TJFLAG_LOSSLESS is irrelevant to planar YUV encoding, and setting the flag caused tjEncode*() to fail with "Invalid lossless parameters" because tjEncodeYUVPlanes() passes a JPEG quality value of -1 to setCompDefaults(). This commit modifies setCompDefaults() so that it takes no action related to the jpegQual parameter unless jpegQual >= 0.
DRC 98ff1fd1 2022-11-21T20:57:39 TurboJPEG: Add lossless JPEG detection capability Add a new TurboJPEG C API function (tjDecompressHeader4()) and Java API method (TJDecompressor.getFlags()) that return the bitwise OR of any flags that are relevant to the JPEG image being decompressed (currently TJFLAG_PROGRESSIVE, TJFLAG_ARITHMETIC, TJFLAG_LOSSLESS, and their Java equivalents.) This allows a calling program to determine whether the image being decompressed is a lossless JPEG image, which means that the decompression scaling feature will not be available and that a full-sized destination buffer should be allocated. More specifically, this fixes a buffer overrun in TJBench, TJExample, and the decompress* fuzz targets that occurred when attempting (in vain) to decompress a lossless JPEG image with decompression scaling enabled.
DRC 25ccad99 2022-11-16T15:57:25 TurboJPEG: 8-bit lossless JPEG support
DRC 6002720c 2022-11-15T23:10:35 TurboJPEG: Opt. enable arithmetic entropy coding
DRC ed73fdc9 2022-11-15T21:28:01 Merge branch 'main' into dev
DRC aa3dd0bd 2022-11-15T15:41:07 TurboJPEG: Nix unneeded setDecodeDefaults ret val The return value was inherited from setDecompDefaults() in 34dca052271f4a75b3c0f7b11a2c5024159628d4, but it was never needed.
DRC e8b40f3c 2022-11-01T21:45:39 Vastly improve 12-bit JPEG integration The Gordian knot that 7fec5074f962b20ed00b4f5da4533e1e8d4ed8ac attempted to unravel was caused by the fact that there are several data-precision-dependent (JSAMPLE-dependent) fields and methods in the exposed libjpeg API structures, and if you change the exposed libjpeg API structures, then you have to change the whole API. If you change the whole API, then you have to provide a whole new library to support the new API, and that makes it difficult to support multiple data precisions in the same application. (It is not impossible, as example.c demonstrated, but using data-precision-dependent libjpeg API structures would have made the cjpeg, djpeg, and jpegtran source code hard to read, so it made more sense to build, install, and package 12-bit-specific versions of those applications.) Unfortunately, the result of that initial integration effort was an unreadable and unmaintainable mess, which is a problem for a library that is an ISO/ITU-T reference implementation. Also, as I dug into the problem of lossless JPEG support, I realized that 16-bit lossless JPEG images are a thing, and supporting yet another version of the libjpeg API just for those images is untenable. In fact, however, the touch points for JSAMPLE in the exposed libjpeg API structures are minimal: - The colormap and sample_range_limit fields in jpeg_decompress_struct - The alloc_sarray() and access_virt_sarray() methods in jpeg_memory_mgr - jpeg_write_scanlines() and jpeg_write_raw_data() - jpeg_read_scanlines() and jpeg_read_raw_data() - jpeg_skip_scanlines() and jpeg_crop_scanline() (This is subtle, but both of those functions use JSAMPLE-dependent opaque structures behind the scenes.) It is much more readable and maintainable to provide 12-bit-specific versions of those six top-level API functions and to document that the aforementioned methods and fields must be type-cast when using 12-bit samples. Since that eliminates the need to provide a 12-bit-specific version of the exposed libjpeg API structures, we can: - Compile only the precision-dependent libjpeg modules (the coefficient buffer controllers, the colorspace converters, the DCT/IDCT managers, the main buffer controllers, the preprocessing and postprocessing controller, the downsampler and upsamplers, the quantizers, the integer DCT methods, and the IDCT methods) for multiple data precisions. - Introduce 12-bit-specific methods into the various internal structures defined in jpegint.h. - Create precision-independent data type, macro, method, field, and function names that are prefixed by an underscore, and use an internal header to convert those into precision-dependent data type, macro, method, field, and function names, based on the value of BITS_IN_JSAMPLE, when compiling the precision-dependent libjpeg modules. - Expose precision-dependent jinit*() functions for each of the precision-dependent libjpeg modules. - Abstract the precision-dependent libjpeg modules by calling the appropriate precision-dependent jinit*() function, based on the value of cinfo->data_precision, from top-level libjpeg API functions.
DRC 5acd9f20 2022-10-04T12:58:11 Merge branch 'main' into dev
DRC eb0a024a 2022-10-04T12:51:38 Remove redundant jconfigint.h #includes Because of 607b668ff96e40fdc749de9b1bb98e7f40c86d93, jconfigint.h is included by jinclude.h.
DRC aa5a3599 2022-06-24T14:21:33 Merge branch 'main' into dev
DRC ba22c0f7 2022-06-24T14:03:03 tjDecompressHeader3(): Accept tables-only streams Inspired by: https://github.com/amyspark/libjpeg-turbo/commit/b3b15cfe74cf07914122e26cf1e408a9a9cf3135 Closes #604 Closes #605
DRC 263386c2 2022-03-11T17:35:59 Merge branch 'main' into dev
DRC a0148454 2022-03-11T10:50:47 Win: Fix build with Visual Studio 2010 (broken by 607b668ff96e40fdc749de9b1bb98e7f40c86d93) - Visual Studio 2010 apparently doesn't have the snprintf() inline function, so restore the macro that emulates that function using _snprintf_s(). - Explicitly include errno.h in strtest.c, since jinclude.h doesn't include it when building with Visual Studio.
DRC 7fec5074 2022-03-08T12:34:11 Support 8-bit & 12-bit JPEGs using the same build Partially implements #199 This commit also implements a request from #178 (the ability to compile the libjpeg example as a standalone program.)
DRC 9abeff46 2022-03-09T11:48:30 Remove extraneous #include directives jinclude.h already includes stdio.h, stdlib.h, and string.h.
DRC 13377e6b 2022-02-11T13:58:31 MSVC: Eliminate int conversion warnings (C4244)
DRC 607b668f 2022-02-10T11:33:49 MSVC: Eliminate C4996 warnings in API libs The primary purpose of this is to encourage adoption of libjpeg-turbo in downstream Windows projects that forbid the use of "deprecated" functions. libjpeg-turbo's usage of those functions was not actually unsafe, because: - libjpeg-turbo always checks the return value of fopen() and ensures that a NULL filename can never be passed to it. - libjpeg-turbo always checks the return value of getenv() and never passes a NULL argument to it. - The sprintf() calls in format_message() (jerror.c) could never overflow the destination string buffer or leave it unterminated as long as the buffer was at least JMSG_LENGTH_MAX bytes in length, as instructed. (Regardless, this commit replaces those calls with snprintf() calls.) - libjpeg-turbo never uses sscanf() to read strings or multi-byte character arrays. - Because of b7d6e84d6a9283dc2bc50ef9fcaadc0cdeb25c9f, wrjpgcom explicitly checks the bounds of the source and destination strings before calling strcat() and strcpy(). - libjpeg-turbo always ensures that the destination string is terminated when using strncpy(). (548490fe5e2aa31cb00f6602d5a478b068b99682 made this explicit.) Regarding thread safety: Technically speaking, getenv() is not thread-safe, because the returned pointer may be invalidated if another thread sets the same environment variable between the time that the first thread calls getenv() and the time that that thread uses the return value. In practice, however, this could only occur with libjpeg-turbo if: (1) A multithreaded calling application used the deprecated and undocumented TJFLAG_FORCEMMX/TJFLAG_FORCESSE/TJFLAG_FORCESSE2 flags in the TurboJPEG API or set one of the corresponding environment variables (which are only intended for testing purposes.) Since the TurboJPEG API library only ever passed string constants to putenv(), the only inherent risk (i.e. the only risk introduced by the library and not the calling application) was that the SIMD extensions may have read an incorrect value from one of the aforementioned environment variables. or (2) A multithreaded calling application modified the value of the JPEGMEM environment variable in one thread while another thread was reading the value of that environment variable (in the body of jpeg_create_compress() or jpeg_create_decompress().) Given that the libjpeg API provides a thread-safe way for applications to modify the default memory limit without using the JPEGMEM environment variable, direct modification of that environment variable by calling applications is not supported. Microsoft's implementation of getenv_s() does not claim to be thread-safe either, so this commit uses getenv_s() solely to mollify Visual Studio. New inline functions and macros (GETENV_S() and PUTENV_S) wrap getenv_s()/_putenv_s() when building for Visual Studio and getenv()/setenv() otherwise, but GETENV_S()/PUTENV_S() provide no advantages over getenv()/setenv() other than parameter validation. They are implemented solely for convenience. Technically speaking, strerror() is not thread-safe, because the returned pointer may be invalidated if another thread changes the locale and/or calls strerror() between the time that the first thread calls strerror() and the time that that thread uses the return value. In practice, however, this could only occur with libjpeg-turbo if a multithreaded calling application encountered a file I/O error in tjLoadImage() or tjSaveImage(). Since both of those functions immediately copy the string returned from strerror() into a thread-local buffer, the risk is minimal, and the worst case would involve an incorrect error string being reported to the calling application. Regardless, this commit uses strerror_s() in the TurboJPEG API library when building for Visual Studio. Note that strerror_r() could have been used on Un*x systems, but it would have been necessary to handle both the POSIX and GNU implementations of that function and perform widespread compatibility testing. Such is left as an exercise for another day. Fixes #568
DRC 1f55ae7b 2022-01-06T12:08:46 Fix -Wpedantic compiler warnings ... and test for those warnings (and others) when performing CI builds.
DRC 17297239 2022-01-06T09:17:30 Eliminate non-ANSI C compatibility macros libjpeg-turbo has never supported non-ANSI C compilers. Per the spec, ANSI C compilers must have locale.h, stddef.h, stdlib.h, memset(), memcpy(), unsigned char, and unsigned short. They must also handle undefined structures.
DRC 173900b1 2021-09-02T12:48:50 tjTrans: Allow 8x8 crop alignmnt w/odd 4:4:4 JPEGs Fixes #549
Alex Richardson a72816ed 2021-07-16T09:37:06 Use uintptr_t, if avail, for pointer-to-int casts Although sizeof(void *) == sizeof(size_t) for all architectures that are currently supported by libjpeg-turbo, such is not guaranteed by the C standard. Specifically, CHERI-enabled architectures (e.g. CHERI-RISC-V or Arm's Morello) use capability pointers that are twice the size of size_t (128 bits for Morello and RV64), so casting to size_t strips the upper bits of the pointer (including the validity bit) and makes it non-deferenceable, as indicated by the following compiler warning: warning: cast from provenance-free integer type to pointer type will give pointer that can not be dereferenced [-Werror,-Wcheri-capability-misuse] cvalue = values = (JCOEF *)PAD((size_t)values_unaligned, 16); Ignoring this warning results in a run-time crash. Casting pointers to uintptr_t, if it is available, avoids this problem, since uintptr_t is defined as an unsigned integer type that can hold a pointer value. Since C89 compatibility is still necessary in libjpeg-turbo, this commit introduces a new typedef for pointer-to-integer casts that uses a GNU-specific extension available in GCC 4.6+ and Clang 3.0+ and falls back to using size_t if the extension is unavailable. The only other options would require C99 or Clang-specific builtins. Closes #538
DRC e0606daf 2021-04-21T14:49:06 TurboJPEG: Update JPEG buf ptrs on comp/xform err When using the in-memory destination manager, it is necessary to explicitly call the destination manager's term_destination() method if an error occurs. That method is called by jpeg_finish_compress() but not by jpeg_abort_compress(). This fixes a potential double free() that could occur if tjCompress*() or tjTransform() returned an error and the calling application tried to clean up a JPEG buffer that was dynamically re-allocated by one of those functions.
DRC 55ec9b3b 2021-04-21T11:04:42 OSS-Fuzz: Code comment tweaks for compr. targets (oversight from 171b875b272f47f1ae42a5009c64f424db22a95b)
DRC 171b875b 2021-04-15T19:03:53 OSS-Fuzz: Check img size b4 readers allocate mem After the completion of the start_input() method, it's too late to check the image size, because the image readers may have already tried to allocate memory for the image. If the width and height are excessively large, then attempting to allocate memory for the image could slow performance or lead to out-of-memory errors prior to the fuzz target checking the image size. NOTE: Specifically, the aforementioned OOM errors and slow units were observed with the compression fuzz targets when using MSan.
DRC 47b66d1d 2021-04-09T11:26:34 OSS-Fuzz: Fix UBSan err caused by TJFLAG_FUZZING
DRC 34d264d6 2021-04-07T12:44:50 OSS-Fuzz: Private TurboJPEG API flag for fuzzing This limits the tjLoadImage() behavioral changes to the scope of the compress_fuzzer target. Otherwise, TJBench in fuzzer builds would refuse to load images larger than 1 Mpixel.
DRC d2d44655 2021-04-05T21:41:30 OSS-Fuzz: Compression fuzz target
DRC c81e91e8 2021-04-05T16:08:22 TurboJPEG: New flag for limiting prog JPEG scans This also fixes timeouts reported by OSS-Fuzz.
DRC fe5b6a1c 2020-09-13T16:58:08 TJPEG: Remove unnecessary setCompDefaults() retval setCompDefaults() hasn't thrown an error since aa7459050d7a50e1d8a99488902d41fbc118a50f was introduced in 2.0.x.
DRC ae87a958 2020-06-16T13:52:39 TurboJPEG: Make global error handling thread-safe ... on platforms that support thread-local storage. This currently includes all supported platforms except 32-bit macOS. Fixes #396
DRC fdf89033 2020-01-07T15:23:08 Eliminate unnecessary NULL checks before free() This programming practice (which exists in other code bases as well) is a by-product of having used early C compilers that did not properly handle free(NULL). All modern compilers should properly handle that. Fixes #398
DRC 6367924a 2019-12-31T00:32:30 tjTransform(): Use instance err. for bad crop spec Addresses a concern raised in #396
DRC c0b16e3d 2019-11-15T13:29:11 TurboJPEG: Fix erroneous subsampling detection ... that caused some JPEG images with unusual sampling factors to be misidentified as 4:4:4. This led to a buffer overflow when attempting to decompress some such images using tjDecompressToYUV*(). Regression introduced by 479501b07c0afd8912a0e0f5b4740cfce9a89a4c The correct behavior is for the TurboJPEG API to refuse to decompress such images, which it did prior to the aforementioned commit. Fixes #389
DRC bd20344b 2019-11-12T15:45:20 tjDecompressToYUV*(): Fix OOB write/double free ... when attempting to decompress grayscale JPEG images with sampling factors != 1. Fixes #387
DRC ded5a504 2019-08-15T13:24:25 tjDecodeYUV*: Fix err if TJ inst used for prog dec If the TurboJPEG instance passed to tjDecodeYUV[Planes]() was previously used to decompress a progressive JPEG image, then we need to disable the progressive decompression parameters in the underlying libjpeg instance before calling jinit_master_decompress(). This commit also modifies the build system so that the "tjtest" target will test for this issue, and it corrects a previous oversight in the build system whereby tjbenchtest did not test progressive compression/decompression unless WITH_JAVA was true.
DRC 2a9e3bd7 2019-07-11T15:30:04 TurboJPEG: Properly handle gigapixel images Prevent several integer overflow issues and subsequent segfaults that occurred when attempting to compress or decompress gigapixel images with the TurboJPEG API: - Modify tjBufSize(), tjBufSizeYUV2(), and tjPlaneSizeYUV() to avoid integer overflow when computing the return values and to return an error if such an overflow is unavoidable. - Modify tjunittest to validate the above. - Modify tjCompress2(), tjEncodeYUVPlanes(), tjDecompress2(), and tjDecodeYUVPlanes() to avoid integer overflow when computing the row pointers in the 64-bit TurboJPEG C API. - Modify TJBench (both C and Java versions) to avoid overflowing the size argument to malloc()/new and to fail gracefully if such an overflow is unavoidable. In general, this allows gigapixel images to be accommodated by the 64-bit TurboJPEG C API when using automatic JPEG buffer (re)allocation. Such images cannot currently be accommodated without automatic JPEG buffer (re)allocation, due to the fact that tjAlloc() accepts a 32-bit integer argument (oops.) Such images cannot be accommodated in the TurboJPEG Java API due to the fact that Java always uses a signed 32-bit integer as an array index. Fixes #361
DRC 6399d0a6 2019-04-23T14:10:04 Fix code formatting/style issues ... ... including, but not limited to: - unused macros - private functions not marked as static - unprototyped global functions - variable shadowing (detected by various non-default GCC 8 warning options)
DRC bce58f48 2019-04-12T07:49:35 Consistify formatting of macros in TurboJPEG code
DRC 500b5ece 2019-02-17T09:06:42 turbojpeg.c: Fix compiler warning w/ -DNO_GETENV
DRC 479501b0 2019-01-21T13:57:55 TurboJPEG: Decompress 4:4:4 JPEGs with unusual SFs Normally, 4:4:4 JPEGs have horizontal x vertical luminance & chrominance sampling factors of 1x1. However, it is technically legal to create 4:4:4 JPEGs with sampling factors of 2x1, 1x2, 3x1, or 1x3, since the sums of the products of those sampling factors are still <= 10. The libjpeg API correctly decodes such images, so the TurboJPEG API should as well. Fixes #323
DRC 3d9c64e9 2019-01-01T18:57:36 tjLoadImage(): Fix int overflow/segfault w/big BMP Fixes #304
DRC 696e754e 2018-06-12T18:49:37 TurboJPEG: Handle JERR_BMP*,JERR_PPM* error codes ... in tjLoadImage()/tjSaveImage(). These error codes require an add-on message table, and if it isn't initialized, then format_message() produces "Bogus message code XXXX" instead.
DRC 2401e4d1 2018-04-26T18:01:52 TurboJPEG: Handle CMYK JPEGs w/ subsampled M, Y Arguably it doesn't make much sense for non-chroma components to be subsampled (which is why this type of image was overlooked in cd7c3e6672cce3779450c6dd10d0d70b0c2278b2-- I didn't realize it was a thing), but certain Adobe applications apparently generate these images. Fixes #236
DRC 58cb10ee 2018-03-31T13:51:31 Eliminate compiler warnings w/ Solaris Studio
DRC 293263c3 2018-03-17T15:14:35 Format preprocessor macros more consistently Within the libjpeg API code, it seems to be more the convention than not to separate the macro name and value by two or more spaces, which improves general readability. Making this consistent across all of libjpeg-turbo is less about my individual preferences and more about making it easy to automatically detect variations from our chosen formatting convention. I intend to release the script I'm using to validate this stuff, once it matures and stabilizes a bit.
DRC 84fbd4f1 2018-03-17T00:27:49 Merge branch 'master' into dev
DRC bd96b30b 2018-03-17T00:06:10 Make all get/putenv() calls compile-time optional * Modify the SIMD dispatchers so they guard their usage of getenv() with the existing NO_GETENV preprocessor definition. * Introduce a new NO_PUTENV preprocessor definition to guard the usage of putenv() in the TurboJPEG API library. This at least puts Windows Store compatibility within the realm of possibility, although further steps are required.
DRC 29e453f7 2018-03-16T14:09:53 turbojpeg.c: Fix Windows build Broken by previous commit. Although turbojpeg.c no longer needs tjutil.h on Un*x, it still needs to include that file on Windows in order to use snprintf() and strcasecmp() (which, on Windows, are macros that wrap _snprintf_s() and stricmp().)
DRC 19c791cd 2018-03-08T10:55:20 Improve code formatting consistency With rare exceptions ... - Always separate line continuation characters by one space from preceding code. - Always use two-space indentation. Never use tabs. - Always use K&R-style conditional blocks. - Always surround operators with spaces, except in raw assembly code. - Always put a space after, but not before, a comma. - Never put a space between type casts and variables/function calls. - Never put a space between the function name and the argument list in function declarations and prototypes. - Always surround braces ('{' and '}') with spaces. - Always surround statements (if, for, else, catch, while, do, switch) with spaces. - Always attach pointer symbols ('*' and '**') to the variable or function name. - Always precede pointer symbols ('*' and '**') by a space in type casts. - Use the MIN() macro from jpegint.h within the libjpeg and TurboJPEG API libraries (using min() from tjutil.h is still necessary for TJBench.) - Where it makes sense (particularly in the TurboJPEG code), put a blank line after variable declaration blocks. - Always separate statements in one-liners by two spaces. The purpose of this was to ease maintenance on my part and also to make it easier for contributors to figure out how to format patch submissions. This was admittedly confusing (even to me sometimes) when we had 3 or 4 different style conventions in the same source tree. The new convention is more consistent with the formatting of other OSS code bases. This commit corrects deviations from the chosen formatting style in the libjpeg API code and reformats the TurboJPEG API code such that it conforms to the same standard. NOTES: - Although it is no longer necessary for the function name in function declarations to begin in Column 1 (this was historically necessary because of the ansi2knr utility, which allowed libjpeg to be built with non-ANSI compilers), we retain that formatting for the libjpeg code because it improves readability when using libjpeg's function attribute macros (GLOBAL(), etc.) - This reformatting project was accomplished with the help of AStyle and Uncrustify, although neither was completely up to the task, and thus a great deal of manual tweaking was required. Note to developers of code formatting utilities: the libjpeg-turbo code base is an excellent test bed, because AFAICT, it breaks every single one of the utilities that are currently available. - The legacy (MMX, SSE, 3DNow!) assembly code for i386 has been formatted to match the SSE2 code (refer to ff5685d5344273df321eb63a005eaae19d2496e3.) I hadn't intended to bother with this, but the Loongson MMI implementation demonstrated that there is still academic value to the MMX implementation, as an algorithmic model for other 64-bit vector implementations. Thus, it is desirable to improve its readability in the same manner as that of the SSE2 implementation.
DRC bd544e28 2017-12-16T09:34:28 Merge branch 'master' into dev
DRC bf6c7743 2017-12-07T19:29:42 Fix whitespace errors
DRC 9f1f86bf 2017-11-19T09:18:36 tjLoadImage(): Fix OOB array access w/TJPF_UNKNOWN Because the previous commit added a test for TJPF_UNKNOWN to tjunittest, the ASAN CI build detected this issue.
DRC 8c40ac8a 2017-11-16T18:46:01 Add TurboJPEG C example and clean up Java example Also rename example.c --> example.txt and add a disclaimer to that file so people will stop trying to compile it.
DRC aa745905 2017-11-16T18:09:07 TurboJPEG C API: Add BMP/PPM load/save functions The main justification for this is to provide new libjpeg-turbo users with a quick & easy way of developing a complete JPEG compression/decompression program without requiring them to build libjpeg-turbo from source (which was necessary in order to use the project-private bmp API) or to use external libraries. These new functions build upon significant enhancements to rdbmp.c, wrbmp.c, rdppm.c, and wrppm.c which allow those engines to convert directly between the native pixel format of the file and a pixel format ("colorspace" in libjpeg parlance) specified by the calling program. rdbmp.c and wrbmp.c have also been modified such that the calling program can choose to read or write image rows in the native (bottom-up) order of the file format, thus eliminating the need to use an inversion array. tjLoadImage() and tjSaveImage() leverage these new underlying features in order to significantly improve upon the performance of the old bmp API. Because these new functions cannot work without the libjpeg-turbo colorspace extensions, the libjpeg-compatible code in turbojpeg.c has been removed. That code was only there to serve as an example of how to use the TurboJPEG API on top of libjpeg, but more specific, buildable examples now exist in the https://github.com/libjpeg-turbo/ijg repository.
DRC 4893e5d8 2017-11-17T19:00:53 Merge branch 'master' into dev
DRC 94e152b1 2017-11-13T08:15:50 TurboJPEG C: Code formatting tweaks
DRC 616b4e2d 2017-09-20T19:55:54 TurboJPEG C: Compiler warnings Introduced in b9ab64d8dbee2db829e59357d335c151680f44f0.
DRC 9baef107 2017-06-29T12:08:02 TurboJPEG: Don't make STOPONWARNING persistent Due to an oversight in d4092f6b4dd94c64864662987b070d517c399490, the state of TJFLAG_STOPONWARNING persisted beyond the function it was passed to.
DRC dadebcd7 2017-06-28T11:43:08 TurboJPEG: Add "copy none", progressive xform opts Allow progressive entropy coding to be enabled on a transform-by-transform basis, and implement a new transform option for disabling the copying of markers. Closes #153
DRC aba6ae59 2017-06-27T13:24:08 TurboJPEG: Opt. enable progressive entropy coding Fulfills part of the feature request in #153. Also paves the way for SIMD-accelerated progressive Huffman coding (refer to #46.)
DRC d4092f6b 2017-06-27T10:54:21 TurboJPEG: Improve error handling - Provide a new C API function and TJException method that allows calling programs to query the severity of a compression/decompression/ transform error. - Provide a new flag that instructs the library to immediately stop compressing/decompressing/transforming if a warning is encountered. Fixes #151
DRC b9ab64d8 2017-05-11T21:02:29 TurboJPEG: Thread-safe error message retrieval Introduce a new C API function (tjGetErrorStr2()) that can be used to retrieve compression/decompression/transform error messages in a thread-safe (i.e. instance-specific) manner. Retrieving error messages from global functions is still thread-unsafe. Addresses a concern expressed in #151.
DRC 2ac4e9d9 2017-06-26T21:58:32 Merge branch 'master' into dev
DRC d4c41fe0 2017-03-18T12:56:36 TurboJPEG: Fix potential memory leaks Referring to https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=746, it seems that the values of local buffer pointers in TurboJPEG API functions aren't always preserved if longjmp() returns control to a point prior to the allocation of the local buffers. This is known to be an issue with GCC 4.x and clang with -O1 and higher optimization levels but not with GCC 5.x and later. It is unknown why GCC 5.x and 6.x do not suffer from the issue, but possibly the local buffer pointers are not allocated on the stack when using those more recent compilers. In any case, this commit modifies the TurboJPEG API library code such that the jump buffer is always updated after any local buffer pointers are allocated but before any subsequent libjpeg API functions are called.
DRC 6c365686 2016-09-20T18:09:15 Merge branch 'master' into dev
DRC 8ce2c911 2016-08-01T11:22:24 TurboJPEG: Decomp. 4:2:2/4:4:0 JPEGs w/unusual SFs Normally, 4:2:2 JPEGs have horizontal x vertical luminance,chrominance sampling factors of 2x1,1x1, and 4:4:0 JPEGs have horizontal x vertical luminance,chrominance sampling factors of 1x2,1x1. However, it is technically legal to create 4:2:2 JPEGs with sampling factors of 2x2,1x2 and 4:4:0 JPEGs with sampling factors of 2x2,2x1, since the sums of the products of those sampling factors (2x2 + 1x2 + 1x2 and 2x2 + 2x1 + 2x1) are still <= 10. The libjpeg API correctly decodes such images, so the TurboJPEG API should as well. Fixes #92
DRC db044351 2016-07-14T13:36:47 Silence pedantic GCC6 code formatting warnings Apparently it's "misleading" to put two self-contained if statements on a single line. Who knew?
DRC 7ee3ce9a 2016-07-05T16:19:26 Lay the groundwork for 32-bit AVX2 SIMD support
DRC 3c67d4f7 2016-04-20T11:27:42 Catch libjpeg errors in tjDecompressToYUV2() Even though tjDecompressToYUV2() is mostly just a wrapper for tjDecompressToYUVPlanes(), tjDecompressToYUV2() still calls jpeg_read_header(), so it needs to properly set up the libjpeg error handler prior to making this call. Otherwise, under very esoteric (and arguably incorrect) use cases, a program could call tjDecompressToYUV2() without first checking the JPEG header using tjDecompressHeader3(), and if the header was corrupt, then the libjpeg API would invoke my_error_exit(). my_error_exit() would in turn call longjmp() on the previous value of myerr->setjmp_buffer, which was probably set in a previous TurboJPEG function, such as tjInitDecompress(). Thus, when a libjpeg error was triggered within the body of tjDecompressToYUV2(), the PC would jump to the error handler of the previous TurboJPEG function, and this usually caused stack corruption in the calling program (because the signature and return type of the previous TurboJPEG function probably wasn't the same as that of tjDecompressToYUV2().)
DRC dec79952 2016-04-20T11:27:42 Catch libjpeg errors in tjDecompressToYUV2() Even though tjDecompressToYUV2() is mostly just a wrapper for tjDecompressToYUVPlanes(), tjDecompressToYUV2() still calls jpeg_read_header(), so it needs to properly set up the libjpeg error handler prior to making this call. Otherwise, under very esoteric (and arguably incorrect) use cases, a program can call tjDecompressToYUV2() without first checking the JPEG header using tjDecompressHeader3(), and if the header is corrupt, tjDecompressToYUV2() will abort without triggering an error. Fixes #72
DRC 55a18d40 2016-02-04T18:52:23 Merge branch '1.4.x'
DRC 6e053525 2016-02-04T09:20:41 TurboJPEG: Avoid dangling pointers This addresses a minor concern (LJT-01-002) expressed in a security audit by Cure53. _tjInitCompress() and _tjInitDecompress() call (respectively) jpeg_mem_dest_tj() and jpeg_mem_src_tj() with a pointer to a dummy buffer, in order to set up the destination/source manager. The dummy buffer should never be used, but it's still better to make it static so that the pointer in the destination/source manager always points to a valid region of memory.
DRC b6576319 2015-08-26T20:31:13 Merge branch '1.4.x'