libjxl

FORK: libjxl patches used on blog
git clone https://git.neptards.moe/blog/libjxl.git
Log | Files | Refs | Submodules | README | LICENSE

jpeg_data.cc (18312B)


      1 // Copyright (c) the JPEG XL Project Authors. All rights reserved.
      2 //
      3 // Use of this source code is governed by a BSD-style
      4 // license that can be found in the LICENSE file.
      5 
      6 #include "lib/jxl/jpeg/jpeg_data.h"
      7 
      8 #include <jxl/types.h>
      9 
     10 #include "lib/jxl/base/printf_macros.h"
     11 #include "lib/jxl/base/status.h"
     12 #include "lib/jxl/common.h"  // kMaxNumPasses, JPEGXL_ENABLE_TRANSCODE_JPEG
     13 
     14 namespace jxl {
     15 namespace jpeg {
     16 
     17 #if JPEGXL_ENABLE_TRANSCODE_JPEG
     18 
     19 namespace {
     20 enum JPEGComponentType : uint32_t {
     21   kGray = 0,
     22   kYCbCr = 1,
     23   kRGB = 2,
     24   kCustom = 3,
     25 };
     26 
     27 struct JPEGInfo {
     28   size_t num_app_markers = 0;
     29   size_t num_com_markers = 0;
     30   size_t num_scans = 0;
     31   size_t num_intermarker = 0;
     32   bool has_dri = false;
     33 };
     34 
     35 Status VisitMarker(uint8_t* marker, Visitor* visitor, JPEGInfo* info) {
     36   uint32_t marker32 = *marker - 0xc0;
     37   JXL_RETURN_IF_ERROR(visitor->Bits(6, 0x00, &marker32));
     38   *marker = marker32 + 0xc0;
     39   if ((*marker & 0xf0) == 0xe0) {
     40     info->num_app_markers++;
     41   }
     42   if (*marker == 0xfe) {
     43     info->num_com_markers++;
     44   }
     45   if (*marker == 0xda) {
     46     info->num_scans++;
     47   }
     48   // We use a fake 0xff marker to signal intermarker data.
     49   if (*marker == 0xff) {
     50     info->num_intermarker++;
     51   }
     52   if (*marker == 0xdd) {
     53     info->has_dri = true;
     54   }
     55   return true;
     56 }
     57 
     58 }  // namespace
     59 
     60 Status JPEGData::VisitFields(Visitor* visitor) {
     61   bool is_gray = components.size() == 1;
     62   JXL_RETURN_IF_ERROR(visitor->Bool(false, &is_gray));
     63   if (visitor->IsReading()) {
     64     components.resize(is_gray ? 1 : 3);
     65   }
     66   JPEGInfo info;
     67   if (visitor->IsReading()) {
     68     uint8_t marker = 0xc0;
     69     do {
     70       JXL_RETURN_IF_ERROR(VisitMarker(&marker, visitor, &info));
     71       marker_order.push_back(marker);
     72       if (marker_order.size() > 16384) {
     73         return JXL_FAILURE("Too many markers: %" PRIuS "\n",
     74                            marker_order.size());
     75       }
     76     } while (marker != 0xd9);
     77   } else {
     78     if (marker_order.size() > 16384) {
     79       return JXL_FAILURE("Too many markers: %" PRIuS "\n", marker_order.size());
     80     }
     81     for (size_t i = 0; i < marker_order.size(); i++) {
     82       JXL_RETURN_IF_ERROR(VisitMarker(&marker_order[i], visitor, &info));
     83     }
     84     if (!marker_order.empty()) {
     85       // Last marker should always be EOI marker.
     86       JXL_CHECK(marker_order.back() == 0xd9);
     87     }
     88   }
     89 
     90   // Size of the APP and COM markers.
     91   if (visitor->IsReading()) {
     92     app_data.resize(info.num_app_markers);
     93     app_marker_type.resize(info.num_app_markers);
     94     com_data.resize(info.num_com_markers);
     95     scan_info.resize(info.num_scans);
     96   }
     97   JXL_ASSERT(app_data.size() == info.num_app_markers);
     98   JXL_ASSERT(app_marker_type.size() == info.num_app_markers);
     99   JXL_ASSERT(com_data.size() == info.num_com_markers);
    100   JXL_ASSERT(scan_info.size() == info.num_scans);
    101   for (size_t i = 0; i < app_data.size(); i++) {
    102     auto& app = app_data[i];
    103     // Encodes up to 8 different values.
    104     JXL_RETURN_IF_ERROR(
    105         visitor->U32(Val(0), Val(1), BitsOffset(1, 2), BitsOffset(2, 4), 0,
    106                      reinterpret_cast<uint32_t*>(&app_marker_type[i])));
    107     if (app_marker_type[i] != AppMarkerType::kUnknown &&
    108         app_marker_type[i] != AppMarkerType::kICC &&
    109         app_marker_type[i] != AppMarkerType::kExif &&
    110         app_marker_type[i] != AppMarkerType::kXMP) {
    111       return JXL_FAILURE("Unknown app marker type %u",
    112                          static_cast<uint32_t>(app_marker_type[i]));
    113     }
    114     uint32_t len = app.size() - 1;
    115     JXL_RETURN_IF_ERROR(visitor->Bits(16, 0, &len));
    116     if (visitor->IsReading()) app.resize(len + 1);
    117     if (app.size() < 3) {
    118       return JXL_FAILURE("Invalid marker size: %" PRIuS "\n", app.size());
    119     }
    120   }
    121   for (auto& com : com_data) {
    122     uint32_t len = com.size() - 1;
    123     JXL_RETURN_IF_ERROR(visitor->Bits(16, 0, &len));
    124     if (visitor->IsReading()) com.resize(len + 1);
    125     if (com.size() < 3) {
    126       return JXL_FAILURE("Invalid marker size: %" PRIuS "\n", com.size());
    127     }
    128   }
    129 
    130   uint32_t num_quant_tables = quant.size();
    131   JXL_RETURN_IF_ERROR(
    132       visitor->U32(Val(1), Val(2), Val(3), Val(4), 2, &num_quant_tables));
    133   if (num_quant_tables == 4) {
    134     return JXL_FAILURE("Invalid number of quant tables");
    135   }
    136   if (visitor->IsReading()) {
    137     quant.resize(num_quant_tables);
    138   }
    139   for (size_t i = 0; i < num_quant_tables; i++) {
    140     if (quant[i].precision > 1) {
    141       return JXL_FAILURE(
    142           "Quant tables with more than 16 bits are not supported");
    143     }
    144     JXL_RETURN_IF_ERROR(visitor->Bits(1, 0, &quant[i].precision));
    145     JXL_RETURN_IF_ERROR(visitor->Bits(2, i, &quant[i].index));
    146     JXL_RETURN_IF_ERROR(visitor->Bool(true, &quant[i].is_last));
    147   }
    148 
    149   JPEGComponentType component_type =
    150       components.size() == 1 && components[0].id == 1 ? JPEGComponentType::kGray
    151       : components.size() == 3 && components[0].id == 1 &&
    152               components[1].id == 2 && components[2].id == 3
    153           ? JPEGComponentType::kYCbCr
    154       : components.size() == 3 && components[0].id == 'R' &&
    155               components[1].id == 'G' && components[2].id == 'B'
    156           ? JPEGComponentType::kRGB
    157           : JPEGComponentType::kCustom;
    158   JXL_RETURN_IF_ERROR(
    159       visitor->Bits(2, JPEGComponentType::kYCbCr,
    160                     reinterpret_cast<uint32_t*>(&component_type)));
    161   uint32_t num_components;
    162   if (component_type == JPEGComponentType::kGray) {
    163     num_components = 1;
    164   } else if (component_type != JPEGComponentType::kCustom) {
    165     num_components = 3;
    166   } else {
    167     num_components = components.size();
    168     JXL_RETURN_IF_ERROR(
    169         visitor->U32(Val(1), Val(2), Val(3), Val(4), 3, &num_components));
    170     if (num_components != 1 && num_components != 3) {
    171       return JXL_FAILURE("Invalid number of components: %u", num_components);
    172     }
    173   }
    174   if (visitor->IsReading()) {
    175     components.resize(num_components);
    176   }
    177   if (component_type == JPEGComponentType::kCustom) {
    178     for (size_t i = 0; i < components.size(); i++) {
    179       JXL_RETURN_IF_ERROR(visitor->Bits(8, 0, &components[i].id));
    180     }
    181   } else if (component_type == JPEGComponentType::kGray) {
    182     components[0].id = 1;
    183   } else if (component_type == JPEGComponentType::kRGB) {
    184     components[0].id = 'R';
    185     components[1].id = 'G';
    186     components[2].id = 'B';
    187   } else {
    188     components[0].id = 1;
    189     components[1].id = 2;
    190     components[2].id = 3;
    191   }
    192   size_t used_tables = 0;
    193   for (size_t i = 0; i < components.size(); i++) {
    194     JXL_RETURN_IF_ERROR(visitor->Bits(2, 0, &components[i].quant_idx));
    195     if (components[i].quant_idx >= quant.size()) {
    196       return JXL_FAILURE("Invalid quant table for component %" PRIuS ": %u\n",
    197                          i, components[i].quant_idx);
    198     }
    199     used_tables |= 1U << components[i].quant_idx;
    200   }
    201   for (size_t i = 0; i < quant.size(); i++) {
    202     if (used_tables & (1 << i)) continue;
    203     if (i == 0) return JXL_FAILURE("First quant table unused.");
    204     // Unused quant table has to be set to copy of previous quant table
    205     for (size_t j = 0; j < 64; j++) {
    206       if (quant[i].values[j] != quant[i - 1].values[j]) {
    207         return JXL_FAILURE("Non-trivial unused quant table");
    208       }
    209     }
    210   }
    211 
    212   uint32_t num_huff = huffman_code.size();
    213   JXL_RETURN_IF_ERROR(visitor->U32(Val(4), BitsOffset(3, 2), BitsOffset(4, 10),
    214                                    BitsOffset(6, 26), 4, &num_huff));
    215   if (visitor->IsReading()) {
    216     huffman_code.resize(num_huff);
    217   }
    218   for (JPEGHuffmanCode& hc : huffman_code) {
    219     bool is_ac = ((hc.slot_id >> 4) != 0);
    220     uint32_t id = hc.slot_id & 0xF;
    221     JXL_RETURN_IF_ERROR(visitor->Bool(false, &is_ac));
    222     JXL_RETURN_IF_ERROR(visitor->Bits(2, 0, &id));
    223     hc.slot_id = (static_cast<uint32_t>(is_ac) << 4) | id;
    224     JXL_RETURN_IF_ERROR(visitor->Bool(true, &hc.is_last));
    225     size_t num_symbols = 0;
    226     for (size_t i = 0; i <= 16; i++) {
    227       JXL_RETURN_IF_ERROR(visitor->U32(Val(0), Val(1), BitsOffset(3, 2),
    228                                        Bits(8), 0, &hc.counts[i]));
    229       num_symbols += hc.counts[i];
    230     }
    231     if (num_symbols < 1) {
    232       // Actually, at least 2 symbols are required, since one of them is EOI.
    233       return JXL_FAILURE("Empty Huffman table");
    234     }
    235     if (num_symbols > hc.values.size()) {
    236       return JXL_FAILURE("Huffman code too large (%" PRIuS ")", num_symbols);
    237     }
    238     // Presence flags for 4 * 64 + 1 values.
    239     uint64_t value_slots[5] = {};
    240     for (size_t i = 0; i < num_symbols; i++) {
    241       // Goes up to 256, included. Might have the same symbol appear twice...
    242       JXL_RETURN_IF_ERROR(visitor->U32(Bits(2), BitsOffset(2, 4),
    243                                        BitsOffset(4, 8), BitsOffset(8, 1), 0,
    244                                        &hc.values[i]));
    245       value_slots[hc.values[i] >> 6] |= static_cast<uint64_t>(1)
    246                                         << (hc.values[i] & 0x3F);
    247     }
    248     if (hc.values[num_symbols - 1] != kJpegHuffmanAlphabetSize) {
    249       return JXL_FAILURE("Missing EOI symbol");
    250     }
    251     // Last element, denoting EOI, have to be 1 after the loop.
    252     JXL_ASSERT(value_slots[4] == 1);
    253     size_t num_values = 1;
    254     for (size_t i = 0; i < 4; ++i) num_values += hwy::PopCount(value_slots[i]);
    255     if (num_values != num_symbols) {
    256       return JXL_FAILURE("Duplicate Huffman symbols");
    257     }
    258     if (!is_ac) {
    259       bool only_dc = ((value_slots[0] >> kJpegDCAlphabetSize) | value_slots[1] |
    260                       value_slots[2] | value_slots[3]) == 0;
    261       if (!only_dc) return JXL_FAILURE("Huffman symbols out of DC range");
    262     }
    263   }
    264 
    265   for (auto& scan : scan_info) {
    266     JXL_RETURN_IF_ERROR(
    267         visitor->U32(Val(1), Val(2), Val(3), Val(4), 1, &scan.num_components));
    268     if (scan.num_components >= 4) {
    269       return JXL_FAILURE("Invalid number of components in SOS marker");
    270     }
    271     JXL_RETURN_IF_ERROR(visitor->Bits(6, 0, &scan.Ss));
    272     JXL_RETURN_IF_ERROR(visitor->Bits(6, 63, &scan.Se));
    273     JXL_RETURN_IF_ERROR(visitor->Bits(4, 0, &scan.Al));
    274     JXL_RETURN_IF_ERROR(visitor->Bits(4, 0, &scan.Ah));
    275     for (size_t i = 0; i < scan.num_components; i++) {
    276       JXL_RETURN_IF_ERROR(visitor->Bits(2, 0, &scan.components[i].comp_idx));
    277       if (scan.components[i].comp_idx >= components.size()) {
    278         return JXL_FAILURE("Invalid component idx in SOS marker");
    279       }
    280       JXL_RETURN_IF_ERROR(visitor->Bits(2, 0, &scan.components[i].ac_tbl_idx));
    281       JXL_RETURN_IF_ERROR(visitor->Bits(2, 0, &scan.components[i].dc_tbl_idx));
    282     }
    283     // TODO(veluca): actually set and use this value.
    284     JXL_RETURN_IF_ERROR(visitor->U32(Val(0), Val(1), Val(2), BitsOffset(3, 3),
    285                                      kMaxNumPasses - 1,
    286                                      &scan.last_needed_pass));
    287   }
    288 
    289   // From here on, this is data that is not strictly necessary to get a valid
    290   // JPEG, but necessary for bit-exact JPEG reconstruction.
    291   if (info.has_dri) {
    292     JXL_RETURN_IF_ERROR(visitor->Bits(16, 0, &restart_interval));
    293   }
    294 
    295   for (auto& scan : scan_info) {
    296     uint32_t num_reset_points = scan.reset_points.size();
    297     JXL_RETURN_IF_ERROR(visitor->U32(Val(0), BitsOffset(2, 1), BitsOffset(4, 4),
    298                                      BitsOffset(16, 20), 0, &num_reset_points));
    299     if (visitor->IsReading()) {
    300       scan.reset_points.resize(num_reset_points);
    301     }
    302     int last_block_idx = -1;
    303     for (auto& block_idx : scan.reset_points) {
    304       block_idx -= last_block_idx + 1;
    305       JXL_RETURN_IF_ERROR(visitor->U32(Val(0), BitsOffset(3, 1),
    306                                        BitsOffset(5, 9), BitsOffset(28, 41), 0,
    307                                        &block_idx));
    308       block_idx += last_block_idx + 1;
    309       if (block_idx >= (3u << 26)) {
    310         // At most 8K x 8K x num_channels blocks are possible in a JPEG.
    311         // So valid block indices are below 3 * 2^26.
    312         return JXL_FAILURE("Invalid block ID: %u", block_idx);
    313       }
    314       last_block_idx = block_idx;
    315     }
    316 
    317     uint32_t num_extra_zero_runs = scan.extra_zero_runs.size();
    318     JXL_RETURN_IF_ERROR(visitor->U32(Val(0), BitsOffset(2, 1), BitsOffset(4, 4),
    319                                      BitsOffset(16, 20), 0,
    320                                      &num_extra_zero_runs));
    321     if (visitor->IsReading()) {
    322       scan.extra_zero_runs.resize(num_extra_zero_runs);
    323     }
    324     last_block_idx = -1;
    325     for (size_t i = 0; i < scan.extra_zero_runs.size(); ++i) {
    326       uint32_t& block_idx = scan.extra_zero_runs[i].block_idx;
    327       JXL_RETURN_IF_ERROR(visitor->U32(
    328           Val(1), BitsOffset(2, 2), BitsOffset(4, 5), BitsOffset(8, 20), 1,
    329           &scan.extra_zero_runs[i].num_extra_zero_runs));
    330       block_idx -= last_block_idx + 1;
    331       JXL_RETURN_IF_ERROR(visitor->U32(Val(0), BitsOffset(3, 1),
    332                                        BitsOffset(5, 9), BitsOffset(28, 41), 0,
    333                                        &block_idx));
    334       block_idx += last_block_idx + 1;
    335       if (block_idx > (3u << 26)) {
    336         return JXL_FAILURE("Invalid block ID: %u", block_idx);
    337       }
    338       last_block_idx = block_idx;
    339     }
    340   }
    341   std::vector<uint32_t> inter_marker_data_sizes;
    342   inter_marker_data_sizes.reserve(info.num_intermarker);
    343   for (size_t i = 0; i < info.num_intermarker; ++i) {
    344     uint32_t len = visitor->IsReading() ? 0 : inter_marker_data[i].size();
    345     JXL_RETURN_IF_ERROR(visitor->Bits(16, 0, &len));
    346     if (visitor->IsReading()) inter_marker_data_sizes.emplace_back(len);
    347   }
    348   uint32_t tail_data_len = tail_data.size();
    349   if (!visitor->IsReading() && tail_data_len > 4260096) {
    350     return JXL_FAILURE("Tail data too large (max size = 4260096, size = %u)",
    351                        tail_data_len);
    352   }
    353   JXL_RETURN_IF_ERROR(visitor->U32(Val(0), BitsOffset(8, 1),
    354                                    BitsOffset(16, 257), BitsOffset(22, 65793),
    355                                    0, &tail_data_len));
    356 
    357   JXL_RETURN_IF_ERROR(visitor->Bool(false, &has_zero_padding_bit));
    358   if (has_zero_padding_bit) {
    359     uint32_t nbit = padding_bits.size();
    360     JXL_RETURN_IF_ERROR(visitor->Bits(24, 0, &nbit));
    361     if (visitor->IsReading()) {
    362       JXL_RETURN_IF_ERROR(CheckHasEnoughBits(visitor, nbit));
    363       padding_bits.reserve(std::min<uint32_t>(1024u, nbit));
    364       for (uint32_t i = 0; i < nbit; i++) {
    365         bool bbit = false;
    366         JXL_RETURN_IF_ERROR(visitor->Bool(false, &bbit));
    367         padding_bits.push_back(TO_JXL_BOOL(bbit));
    368       }
    369     } else {
    370       for (uint8_t& bit : padding_bits) {
    371         bool bbit = FROM_JXL_BOOL(bit);
    372         JXL_RETURN_IF_ERROR(visitor->Bool(false, &bbit));
    373         bit = TO_JXL_BOOL(bbit);
    374       }
    375     }
    376   }
    377 
    378   {
    379     size_t dht_index = 0;
    380     size_t scan_index = 0;
    381     bool is_progressive = false;
    382     bool ac_ok[kMaxHuffmanTables] = {false};
    383     bool dc_ok[kMaxHuffmanTables] = {false};
    384     for (uint8_t marker : marker_order) {
    385       if (marker == 0xC2) {
    386         is_progressive = true;
    387       } else if (marker == 0xC4) {
    388         for (; dht_index < huffman_code.size();) {
    389           const JPEGHuffmanCode& huff = huffman_code[dht_index++];
    390           size_t index = huff.slot_id;
    391           if (index & 0x10) {
    392             index -= 0x10;
    393             ac_ok[index] = true;
    394           } else {
    395             dc_ok[index] = true;
    396           }
    397           if (huff.is_last) break;
    398         }
    399       } else if (marker == 0xDA) {
    400         const JPEGScanInfo& si = scan_info[scan_index++];
    401         for (size_t i = 0; i < si.num_components; ++i) {
    402           const JPEGComponentScanInfo& csi = si.components[i];
    403           size_t dc_tbl_idx = csi.dc_tbl_idx;
    404           size_t ac_tbl_idx = csi.ac_tbl_idx;
    405           bool want_dc = !is_progressive || (si.Ss == 0);
    406           if (want_dc && !dc_ok[dc_tbl_idx]) {
    407             return JXL_FAILURE("DC Huffman table used before defined");
    408           }
    409           bool want_ac = !is_progressive || (si.Ss != 0) || (si.Se != 0);
    410           if (want_ac && !ac_ok[ac_tbl_idx]) {
    411             return JXL_FAILURE("AC Huffman table used before defined");
    412           }
    413         }
    414       }
    415     }
    416   }
    417 
    418   // Apply postponed actions.
    419   if (visitor->IsReading()) {
    420     tail_data.resize(tail_data_len);
    421     JXL_ASSERT(inter_marker_data_sizes.size() == info.num_intermarker);
    422     inter_marker_data.reserve(info.num_intermarker);
    423     for (size_t i = 0; i < info.num_intermarker; ++i) {
    424       inter_marker_data.emplace_back(inter_marker_data_sizes[i]);
    425     }
    426   }
    427 
    428   return true;
    429 }
    430 
    431 #endif  // JPEGXL_ENABLE_TRANSCODE_JPEG
    432 
    433 void JPEGData::CalculateMcuSize(const JPEGScanInfo& scan, int* MCUs_per_row,
    434                                 int* MCU_rows) const {
    435   const bool is_interleaved = (scan.num_components > 1);
    436   const JPEGComponent& base_component = components[scan.components[0].comp_idx];
    437   // h_group / v_group act as numerators for converting number of blocks to
    438   // number of MCU. In interleaved mode it is 1, so MCU is represented with
    439   // max_*_samp_factor blocks. In non-interleaved mode we choose numerator to
    440   // be the samping factor, consequently MCU is always represented with single
    441   // block.
    442   const int h_group = is_interleaved ? 1 : base_component.h_samp_factor;
    443   const int v_group = is_interleaved ? 1 : base_component.v_samp_factor;
    444   int max_h_samp_factor = 1;
    445   int max_v_samp_factor = 1;
    446   for (const auto& c : components) {
    447     max_h_samp_factor = std::max(c.h_samp_factor, max_h_samp_factor);
    448     max_v_samp_factor = std::max(c.v_samp_factor, max_v_samp_factor);
    449   }
    450   *MCUs_per_row = DivCeil(width * h_group, 8 * max_h_samp_factor);
    451   *MCU_rows = DivCeil(height * v_group, 8 * max_v_samp_factor);
    452 }
    453 
    454 #if JPEGXL_ENABLE_TRANSCODE_JPEG
    455 
    456 Status SetJPEGDataFromICC(const std::vector<uint8_t>& icc,
    457                           jpeg::JPEGData* jpeg_data) {
    458   size_t icc_pos = 0;
    459   for (size_t i = 0; i < jpeg_data->app_data.size(); i++) {
    460     if (jpeg_data->app_marker_type[i] != jpeg::AppMarkerType::kICC) {
    461       continue;
    462     }
    463     size_t len = jpeg_data->app_data[i].size() - 17;
    464     if (icc_pos + len > icc.size()) {
    465       return JXL_FAILURE(
    466           "ICC length is less than APP markers: requested %" PRIuS
    467           " more bytes, "
    468           "%" PRIuS " available",
    469           len, icc.size() - icc_pos);
    470     }
    471     memcpy(&jpeg_data->app_data[i][17], icc.data() + icc_pos, len);
    472     icc_pos += len;
    473   }
    474   if (icc_pos != icc.size() && icc_pos != 0) {
    475     return JXL_FAILURE("ICC length is more than APP markers");
    476   }
    477   return true;
    478 }
    479 
    480 #endif  // JPEGXL_ENABLE_TRANSCODE_JPEG
    481 
    482 }  // namespace jpeg
    483 }  // namespace jxl