Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tjDecompressHeader3: allow loading an abbreviated table specification datastream #605

Closed

Conversation

amyspark
Copy link

@amyspark amyspark commented Jun 15, 2022

This allows libjpeg-turbo to prime the decoder with an
abbreviated table specification datastream from a TIFFTAG_JPEGTABLES
field, a capability that was until now only available with raw libjpeg.

Fixes #604

… datastream

This allows libjpeg-turbo to prime the decoder with an
abbreviated table specification datastream from a TIFFTAG_JPEGTABLES
field, a capability that was until now only available with raw libjpeg.
@amyspark amyspark changed the title tjDecompressHeader3: allow loading an abbreviated table specification… tjDecompressHeader3: allow loading an abbreviated table specification datastream Jun 15, 2022
@dcommander
Copy link
Member

Sorry for the delay. A few further questions:

  1. Would it be OK to just return 0 for success, regardless of whether a full image or an abbreviated (tables-only) datastream is passed to the function? My concern is that some existing programs may lazily check the return value like so: if (tjDecompressHeader3(...)) { throw an error; }.
  2. How would this new API be used, in practice? Would a program call tjDecompressHeader3() once with a tables-only datastream and then again with the actual image?
  3. How are tables-only datastreams generated? I confess that I am not familiar with that aspect of the libjpeg API.

@amyspark
Copy link
Author

  1. That's OK with me.
  2. Indeed, that's how libtiff handles it at present. In my own case:
#ifdef HAVE_JPEG_TURBO
    uint32_t hasSplitTables = 0;
    uint8_t *tables = nullptr;
    uint32_t sz = 0;
    QVector<unsigned char> jpegBuf;

    auto handle = [&]() -> std::unique_ptr<void, decltype(&tjDestroy)> {
        if (planarconfig == PLANARCONFIG_CONTIG
            && color_type == PHOTOMETRIC_YCBCR
            && compression == COMPRESSION_JPEG) {
            return {tjInitDecompress(), &tjDestroy};
        } else {
            return {nullptr, &tjDestroy};
        }
    }();

    if (color_type == PHOTOMETRIC_YCBCR && compression == COMPRESSION_JPEG
        && hsubsampling != 1 && vsubsampling != 1) {
        dbgFile << "Setting up libjpeg-turbo for handling subsampled JPEG...";
        if (!TIFFGetFieldDefaulted(image,
                                   TIFFTAG_JPEGTABLESMODE,
                                   &hasSplitTables)) {
            errFile << "Error when detecting the JPEG coefficient "
                       "table mode";
            return ImportExportCodes::FileFormatIncorrect;
        }
        if (hasSplitTables) {
            if (!TIFFGetField(image, TIFFTAG_JPEGTABLES, &sz, &tables)) {
                errFile << "Unable to retrieve the JPEG abbreviated datastream";
                return ImportExportCodes::FileFormatIncorrect;
            }
        }

        {
            int width = 0;
            int height = 0;

            if (hasSplitTables
                && tjDecompressHeader(handle.get(), tables, sz, &width, &height)
                    != 1) {
                errFile << tjGetErrorStr2(handle.get());
                m_doc->setErrorMessage(
                    i18nc("TIFF errors",
                          "This TIFF file is compressed with JPEG, but "
                          "libjpeg-turbo could not load its coefficient "
                          "quantization and/or Huffman coding tables. "
                          "Please upgrade your version of libjpeg-turbo "
                          "and try again."));
                return ImportExportCodes::FileFormatIncorrect;
            }
        }
    }
#endif
  1. That's done by libtiff under the hood, it doesn't affect usage of YCbCr. If I understand the code correctly, on writing, it commands libjpeg to not output coefficient tables via jpeg_suppress_tables, then it redirects the writing of the tables to a separate buffer (TIFFjpeg_tables_dest) before calling jpeg_write_tables.

@dcommander
Copy link
Member

Implemented and pushed. Please test.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allow libjpeg-turbo to load JPEG coefficient tables from TIFF
2 participants