libjxl

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

icc_codec_common.cc (5747B)


      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/icc_codec_common.h"
      7 
      8 #include <stdint.h>
      9 
     10 #include <map>
     11 #include <string>
     12 #include <vector>
     13 
     14 #include "lib/jxl/base/byte_order.h"
     15 #include "lib/jxl/fields.h"
     16 #include "lib/jxl/padded_bytes.h"
     17 
     18 namespace jxl {
     19 namespace {
     20 uint8_t ByteKind1(uint8_t b) {
     21   if ('a' <= b && b <= 'z') return 0;
     22   if ('A' <= b && b <= 'Z') return 0;
     23   if ('0' <= b && b <= '9') return 1;
     24   if (b == '.' || b == ',') return 1;
     25   if (b == 0) return 2;
     26   if (b == 1) return 3;
     27   if (b < 16) return 4;
     28   if (b == 255) return 6;
     29   if (b > 240) return 5;
     30   return 7;
     31 }
     32 
     33 uint8_t ByteKind2(uint8_t b) {
     34   if ('a' <= b && b <= 'z') return 0;
     35   if ('A' <= b && b <= 'Z') return 0;
     36   if ('0' <= b && b <= '9') return 1;
     37   if (b == '.' || b == ',') return 1;
     38   if (b < 16) return 2;
     39   if (b > 240) return 3;
     40   return 4;
     41 }
     42 
     43 template <typename T>
     44 T PredictValue(T p1, T p2, T p3, int order) {
     45   if (order == 0) return p1;
     46   if (order == 1) return 2 * p1 - p2;
     47   if (order == 2) return 3 * p1 - 3 * p2 + p3;
     48   return 0;
     49 }
     50 }  // namespace
     51 
     52 uint32_t DecodeUint32(const uint8_t* data, size_t size, size_t pos) {
     53   return pos + 4 > size ? 0 : LoadBE32(data + pos);
     54 }
     55 
     56 void EncodeUint32(size_t pos, uint32_t value, PaddedBytes* data) {
     57   if (pos + 4 > data->size()) return;
     58   StoreBE32(value, data->data() + pos);
     59 }
     60 
     61 void AppendUint32(uint32_t value, PaddedBytes* data) {
     62   data->resize(data->size() + 4);
     63   EncodeUint32(data->size() - 4, value, data);
     64 }
     65 
     66 typedef std::array<uint8_t, 4> Tag;
     67 
     68 Tag DecodeKeyword(const uint8_t* data, size_t size, size_t pos) {
     69   if (pos + 4 > size) return {{' ', ' ', ' ', ' '}};
     70   return {{data[pos], data[pos + 1], data[pos + 2], data[pos + 3]}};
     71 }
     72 
     73 void EncodeKeyword(const Tag& keyword, uint8_t* data, size_t size, size_t pos) {
     74   if (keyword.size() != 4 || pos + 3 >= size) return;
     75   for (size_t i = 0; i < 4; ++i) data[pos + i] = keyword[i];
     76 }
     77 
     78 void AppendKeyword(const Tag& keyword, PaddedBytes* data) {
     79   JXL_ASSERT(keyword.size() == 4);
     80   data->append(keyword);
     81 }
     82 
     83 // Checks if a + b > size, taking possible integer overflow into account.
     84 Status CheckOutOfBounds(uint64_t a, uint64_t b, uint64_t size) {
     85   uint64_t pos = a + b;
     86   if (pos > size) return JXL_FAILURE("Out of bounds");
     87   if (pos < a) return JXL_FAILURE("Out of bounds");  // overflow happened
     88   return true;
     89 }
     90 
     91 Status CheckIs32Bit(uint64_t v) {
     92   static constexpr const uint64_t kUpper32 = ~static_cast<uint64_t>(0xFFFFFFFF);
     93   if ((v & kUpper32) != 0) return JXL_FAILURE("32-bit value expected");
     94   return true;
     95 }
     96 
     97 const uint8_t kIccInitialHeaderPrediction[kICCHeaderSize] = {
     98     0,   0,   0,   0,   0,   0,   0,   0,   4, 0, 0, 0, 'm', 'n', 't', 'r',
     99     'R', 'G', 'B', ' ', 'X', 'Y', 'Z', ' ', 0, 0, 0, 0, 0,   0,   0,   0,
    100     0,   0,   0,   0,   'a', 'c', 's', 'p', 0, 0, 0, 0, 0,   0,   0,   0,
    101     0,   0,   0,   0,   0,   0,   0,   0,   0, 0, 0, 0, 0,   0,   0,   0,
    102     0,   0,   0,   0,   0,   0,   246, 214, 0, 1, 0, 0, 0,   0,   211, 45,
    103     0,   0,   0,   0,   0,   0,   0,   0,   0, 0, 0, 0, 0,   0,   0,   0,
    104     0,   0,   0,   0,   0,   0,   0,   0,   0, 0, 0, 0, 0,   0,   0,   0,
    105     0,   0,   0,   0,   0,   0,   0,   0,   0, 0, 0, 0, 0,   0,   0,   0,
    106 };
    107 
    108 Span<const uint8_t> ICCInitialHeaderPrediction() {
    109   return Bytes(kIccInitialHeaderPrediction);
    110 }
    111 
    112 void ICCPredictHeader(const uint8_t* icc, size_t size, uint8_t* header,
    113                       size_t pos) {
    114   if (pos == 8 && size >= 8) {
    115     header[80] = icc[4];
    116     header[81] = icc[5];
    117     header[82] = icc[6];
    118     header[83] = icc[7];
    119   }
    120   if (pos == 41 && size >= 41) {
    121     if (icc[40] == 'A') {
    122       header[41] = 'P';
    123       header[42] = 'P';
    124       header[43] = 'L';
    125     }
    126     if (icc[40] == 'M') {
    127       header[41] = 'S';
    128       header[42] = 'F';
    129       header[43] = 'T';
    130     }
    131   }
    132   if (pos == 42 && size >= 42) {
    133     if (icc[40] == 'S' && icc[41] == 'G') {
    134       header[42] = 'I';
    135       header[43] = ' ';
    136     }
    137     if (icc[40] == 'S' && icc[41] == 'U') {
    138       header[42] = 'N';
    139       header[43] = 'W';
    140     }
    141   }
    142 }
    143 
    144 // Predicts a value with linear prediction of given order (0-2), for integers
    145 // with width bytes and given stride in bytes between values.
    146 // The start position is at start + i, and the relevant modulus of i describes
    147 // which byte of the multi-byte integer is being handled.
    148 // The value start + i must be at least stride * 4.
    149 uint8_t LinearPredictICCValue(const uint8_t* data, size_t start, size_t i,
    150                               size_t stride, size_t width, int order) {
    151   size_t pos = start + i;
    152   if (width == 1) {
    153     uint8_t p1 = data[pos - stride];
    154     uint8_t p2 = data[pos - stride * 2];
    155     uint8_t p3 = data[pos - stride * 3];
    156     return PredictValue(p1, p2, p3, order);
    157   } else if (width == 2) {
    158     size_t p = start + (i & ~1);
    159     uint16_t p1 = (data[p - stride * 1] << 8) + data[p - stride * 1 + 1];
    160     uint16_t p2 = (data[p - stride * 2] << 8) + data[p - stride * 2 + 1];
    161     uint16_t p3 = (data[p - stride * 3] << 8) + data[p - stride * 3 + 1];
    162     uint16_t pred = PredictValue(p1, p2, p3, order);
    163     return (i & 1) ? (pred & 255) : ((pred >> 8) & 255);
    164   } else {
    165     size_t p = start + (i & ~3);
    166     uint32_t p1 = DecodeUint32(data, pos, p - stride);
    167     uint32_t p2 = DecodeUint32(data, pos, p - stride * 2);
    168     uint32_t p3 = DecodeUint32(data, pos, p - stride * 3);
    169     uint32_t pred = PredictValue(p1, p2, p3, order);
    170     unsigned shiftbytes = 3 - (i & 3);
    171     return (pred >> (shiftbytes * 8)) & 255;
    172   }
    173 }
    174 
    175 size_t ICCANSContext(size_t i, size_t b1, size_t b2) {
    176   if (i <= 128) return 0;
    177   return 1 + ByteKind1(b1) + ByteKind2(b2) * 8;
    178 }
    179 
    180 }  // namespace jxl