libjxl

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

packed_image.h (8375B)


      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 #ifndef LIB_EXTRAS_PACKED_IMAGE_H_
      7 #define LIB_EXTRAS_PACKED_IMAGE_H_
      8 
      9 // Helper class for storing external (int or float, interleaved) images. This is
     10 // the common format used by other libraries and in the libjxl API.
     11 
     12 #include <jxl/codestream_header.h>
     13 #include <jxl/encode.h>
     14 #include <jxl/types.h>
     15 #include <stddef.h>
     16 #include <stdint.h>
     17 #include <stdlib.h>
     18 #include <string.h>
     19 
     20 #include <algorithm>
     21 #include <cmath>
     22 #include <functional>
     23 #include <memory>
     24 #include <mutex>
     25 #include <set>
     26 #include <string>
     27 #include <vector>
     28 
     29 #include "lib/jxl/base/byte_order.h"
     30 #include "lib/jxl/base/c_callback_support.h"
     31 #include "lib/jxl/base/common.h"
     32 #include "lib/jxl/base/status.h"
     33 
     34 namespace jxl {
     35 namespace extras {
     36 
     37 // Class representing an interleaved image with a bunch of channels.
     38 class PackedImage {
     39  public:
     40   PackedImage(size_t xsize, size_t ysize, const JxlPixelFormat& format)
     41       : PackedImage(xsize, ysize, format, CalcStride(format, xsize)) {}
     42 
     43   PackedImage Copy() const {
     44     PackedImage copy(xsize, ysize, format);
     45     memcpy(reinterpret_cast<uint8_t*>(copy.pixels()),
     46            reinterpret_cast<const uint8_t*>(pixels()), pixels_size);
     47     return copy;
     48   }
     49 
     50   // The interleaved pixels as defined in the storage format.
     51   void* pixels() const { return pixels_.get(); }
     52 
     53   uint8_t* pixels(size_t y, size_t x, size_t c) const {
     54     return (reinterpret_cast<uint8_t*>(pixels_.get()) + y * stride +
     55             x * pixel_stride_ + c * bytes_per_channel_);
     56   }
     57 
     58   const uint8_t* const_pixels(size_t y, size_t x, size_t c) const {
     59     return (reinterpret_cast<const uint8_t*>(pixels_.get()) + y * stride +
     60             x * pixel_stride_ + c * bytes_per_channel_);
     61   }
     62 
     63   // The image size in pixels.
     64   size_t xsize;
     65   size_t ysize;
     66 
     67   // The number of bytes per row.
     68   size_t stride;
     69 
     70   // Pixel storage format and buffer size of the pixels_ pointer.
     71   JxlPixelFormat format;
     72   size_t pixels_size;
     73 
     74   size_t pixel_stride() const { return pixel_stride_; }
     75 
     76   static size_t BitsPerChannel(JxlDataType data_type) {
     77     switch (data_type) {
     78       case JXL_TYPE_UINT8:
     79         return 8;
     80       case JXL_TYPE_UINT16:
     81         return 16;
     82       case JXL_TYPE_FLOAT:
     83         return 32;
     84       case JXL_TYPE_FLOAT16:
     85         return 16;
     86       default:
     87         JXL_ABORT("Unhandled JxlDataType");
     88     }
     89   }
     90 
     91   float GetPixelValue(size_t y, size_t x, size_t c) const {
     92     const uint8_t* data = const_pixels(y, x, c);
     93     switch (format.data_type) {
     94       case JXL_TYPE_UINT8:
     95         return data[0] * (1.0f / 255);
     96       case JXL_TYPE_UINT16: {
     97         uint16_t val;
     98         memcpy(&val, data, 2);
     99         return (swap_endianness_ ? JXL_BSWAP16(val) : val) * (1.0f / 65535);
    100       }
    101       case JXL_TYPE_FLOAT: {
    102         float val;
    103         memcpy(&val, data, 4);
    104         return swap_endianness_ ? BSwapFloat(val) : val;
    105       }
    106       default:
    107         JXL_ABORT("Unhandled JxlDataType");
    108     }
    109   }
    110 
    111   void SetPixelValue(size_t y, size_t x, size_t c, float val) const {
    112     uint8_t* data = pixels(y, x, c);
    113     switch (format.data_type) {
    114       case JXL_TYPE_UINT8:
    115         data[0] = Clamp1(std::round(val * 255), 0.0f, 255.0f);
    116         break;
    117       case JXL_TYPE_UINT16: {
    118         uint16_t val16 = Clamp1(std::round(val * 65535), 0.0f, 65535.0f);
    119         if (swap_endianness_) {
    120           val16 = JXL_BSWAP16(val16);
    121         }
    122         memcpy(data, &val16, 2);
    123         break;
    124       }
    125       case JXL_TYPE_FLOAT: {
    126         if (swap_endianness_) {
    127           val = BSwapFloat(val);
    128         }
    129         memcpy(data, &val, 4);
    130         break;
    131       }
    132       default:
    133         JXL_ABORT("Unhandled JxlDataType");
    134     }
    135   }
    136 
    137  private:
    138   PackedImage(size_t xsize, size_t ysize, const JxlPixelFormat& format,
    139               size_t stride)
    140       : xsize(xsize),
    141         ysize(ysize),
    142         stride(stride),
    143         format(format),
    144         pixels_size(ysize * stride),
    145         pixels_(malloc(std::max<size_t>(1, pixels_size)), free) {
    146     bytes_per_channel_ = BitsPerChannel(format.data_type) / jxl::kBitsPerByte;
    147     pixel_stride_ = format.num_channels * bytes_per_channel_;
    148     swap_endianness_ = SwapEndianness(format.endianness);
    149   }
    150 
    151   static size_t CalcStride(const JxlPixelFormat& format, size_t xsize) {
    152     size_t stride = xsize * (BitsPerChannel(format.data_type) *
    153                              format.num_channels / jxl::kBitsPerByte);
    154     if (format.align > 1) {
    155       stride = jxl::DivCeil(stride, format.align) * format.align;
    156     }
    157     return stride;
    158   }
    159 
    160   size_t bytes_per_channel_;
    161   size_t pixel_stride_;
    162   bool swap_endianness_;
    163   std::unique_ptr<void, decltype(free)*> pixels_;
    164 };
    165 
    166 // Helper class representing a frame, as seen from the API. Animations will have
    167 // multiple frames, but a single frame can have a color/grayscale channel and
    168 // multiple extra channels. The order of the extra channels should be the same
    169 // as all other frames in the same image.
    170 class PackedFrame {
    171  public:
    172   template <typename... Args>
    173   explicit PackedFrame(Args&&... args) : color(std::forward<Args>(args)...) {}
    174 
    175   PackedFrame Copy() const {
    176     PackedFrame copy(color.xsize, color.ysize, color.format);
    177     copy.frame_info = frame_info;
    178     copy.name = name;
    179     copy.color = color.Copy();
    180     for (const auto& ec : extra_channels) {
    181       copy.extra_channels.emplace_back(ec.Copy());
    182     }
    183     return copy;
    184   }
    185 
    186   // The Frame metadata.
    187   JxlFrameHeader frame_info = {};
    188   std::string name;
    189 
    190   // The pixel data for the color (or grayscale) channels.
    191   PackedImage color;
    192   // Extra channel image data.
    193   std::vector<PackedImage> extra_channels;
    194 };
    195 
    196 class ChunkedPackedFrame {
    197  public:
    198   ChunkedPackedFrame(
    199       size_t xsize, size_t ysize,
    200       std::function<JxlChunkedFrameInputSource()> get_input_source)
    201       : xsize(xsize),
    202         ysize(ysize),
    203         get_input_source_(std::move(get_input_source)) {
    204     const auto input_source = get_input_source_();
    205     input_source.get_color_channels_pixel_format(input_source.opaque, &format);
    206   }
    207 
    208   JxlChunkedFrameInputSource GetInputSource() { return get_input_source_(); }
    209 
    210   // The Frame metadata.
    211   JxlFrameHeader frame_info = {};
    212   std::string name;
    213 
    214   size_t xsize;
    215   size_t ysize;
    216   JxlPixelFormat format;
    217 
    218  private:
    219   std::function<JxlChunkedFrameInputSource()> get_input_source_;
    220 };
    221 
    222 // Optional metadata associated with a file
    223 class PackedMetadata {
    224  public:
    225   std::vector<uint8_t> exif;
    226   std::vector<uint8_t> iptc;
    227   std::vector<uint8_t> jumbf;
    228   std::vector<uint8_t> xmp;
    229 };
    230 
    231 // The extra channel metadata information.
    232 struct PackedExtraChannel {
    233   JxlExtraChannelInfo ec_info;
    234   size_t index;
    235   std::string name;
    236 };
    237 
    238 // Helper class representing a JXL image file as decoded to pixels from the API.
    239 class PackedPixelFile {
    240  public:
    241   JxlBasicInfo info = {};
    242 
    243   std::vector<PackedExtraChannel> extra_channels_info;
    244 
    245   // Color information of the decoded pixels.
    246   // `primary_color_representation` indicates whether `color_encoding` or `icc`
    247   // is the “authoritative” encoding of the colorspace, as opposed to a fallback
    248   // encoding. For example, if `color_encoding` is the primary one, as would
    249   // occur when decoding a jxl file with such a representation, then `enc/jxl`
    250   // will use it and ignore the ICC profile, whereas `enc/png` will include the
    251   // ICC profile for compatibility.
    252   // If `icc` is the primary representation, `enc/jxl` will preserve it when
    253   // compressing losslessly, but *may* encode it as a color_encoding when
    254   // compressing lossily.
    255   enum {
    256     kColorEncodingIsPrimary,
    257     kIccIsPrimary
    258   } primary_color_representation = kColorEncodingIsPrimary;
    259   JxlColorEncoding color_encoding = {};
    260   std::vector<uint8_t> icc;
    261   // The icc profile of the original image.
    262   std::vector<uint8_t> orig_icc;
    263 
    264   std::unique_ptr<PackedFrame> preview_frame;
    265   std::vector<PackedFrame> frames;
    266   mutable std::vector<ChunkedPackedFrame> chunked_frames;
    267 
    268   PackedMetadata metadata;
    269   PackedPixelFile() { JxlEncoderInitBasicInfo(&info); };
    270 
    271   size_t num_frames() const {
    272     return chunked_frames.empty() ? frames.size() : chunked_frames.size();
    273   }
    274   size_t xsize() const { return info.xsize; }
    275   size_t ysize() const { return info.ysize; }
    276 };
    277 
    278 }  // namespace extras
    279 }  // namespace jxl
    280 
    281 #endif  // LIB_EXTRAS_PACKED_IMAGE_H_