tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

palette.cc (7795B)


      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/modular/transform/palette.h"
      7 
      8 #include <jxl/memory_manager.h>
      9 
     10 #include "lib/jxl/base/status.h"
     11 #include "lib/jxl/modular/transform/transform.h"  // CheckEqualChannels
     12 
     13 namespace jxl {
     14 
     15 Status InvPalette(Image &input, uint32_t begin_c, uint32_t nb_colors,
     16                  uint32_t nb_deltas, Predictor predictor,
     17                  const weighted::Header &wp_header, ThreadPool *pool) {
     18  JxlMemoryManager *memory_manager = input.memory_manager();
     19  if (input.nb_meta_channels < 1) {
     20    return JXL_FAILURE("Error: Palette transform without palette.");
     21  }
     22  int nb = input.channel[0].h;
     23  uint32_t c0 = begin_c + 1;
     24  if (c0 >= input.channel.size()) {
     25    return JXL_FAILURE("Channel is out of range.");
     26  }
     27  size_t w = input.channel[c0].w;
     28  size_t h = input.channel[c0].h;
     29  if (nb < 1) return JXL_FAILURE("Corrupted transforms");
     30  for (int i = 1; i < nb; i++) {
     31    JXL_ASSIGN_OR_RETURN(Channel c, Channel::Create(memory_manager, w, h,
     32                                                    input.channel[c0].hshift,
     33                                                    input.channel[c0].vshift));
     34    input.channel.insert(input.channel.begin() + c0 + 1, std::move(c));
     35  }
     36  const Channel &palette = input.channel[0];
     37  const pixel_type *JXL_RESTRICT p_palette = input.channel[0].Row(0);
     38  intptr_t onerow = input.channel[0].plane.PixelsPerRow();
     39  intptr_t onerow_image = input.channel[c0].plane.PixelsPerRow();
     40  const int bit_depth = std::min(input.bitdepth, 24);
     41 
     42  if (w == 0) {
     43    // Nothing to do.
     44    // Avoid touching "empty" channels with non-zero height.
     45  } else if (nb_deltas == 0 && predictor == Predictor::Zero) {
     46    if (nb == 1) {
     47      const auto process_row = [&](const uint32_t task,
     48                                   size_t /* thread */) -> Status {
     49        const size_t y = task;
     50        pixel_type *p = input.channel[c0].Row(y);
     51        for (size_t x = 0; x < w; x++) {
     52          const int index =
     53              Clamp1<int>(p[x], 0, static_cast<pixel_type>(palette.w) - 1);
     54          p[x] = palette_internal::GetPaletteValue(p_palette, index, /*c=*/0,
     55                                                   /*palette_size=*/palette.w,
     56                                                   /*onerow=*/onerow,
     57                                                   /*bit_depth=*/bit_depth);
     58        }
     59        return true;
     60      };
     61      JXL_RETURN_IF_ERROR(RunOnPool(pool, 0, h, ThreadPool::NoInit, process_row,
     62                                    "UndoChannelPalette"));
     63    } else {
     64      const auto process_row = [&](const uint32_t task,
     65                                   size_t /* thread */) -> Status {
     66        const size_t y = task;
     67        std::vector<pixel_type *> p_out(nb);
     68        const pixel_type *p_index = input.channel[c0].Row(y);
     69        for (int c = 0; c < nb; c++) p_out[c] = input.channel[c0 + c].Row(y);
     70        for (size_t x = 0; x < w; x++) {
     71          const int index = p_index[x];
     72          for (int c = 0; c < nb; c++) {
     73            p_out[c][x] = palette_internal::GetPaletteValue(
     74                p_palette, index, /*c=*/c,
     75                /*palette_size=*/palette.w,
     76                /*onerow=*/onerow, /*bit_depth=*/bit_depth);
     77          }
     78        }
     79        return true;
     80      };
     81      JXL_RETURN_IF_ERROR(RunOnPool(pool, 0, h, ThreadPool::NoInit, process_row,
     82                                    "UndoPalette"));
     83    }
     84  } else {
     85    // Parallelized per channel.
     86    ImageI indices;
     87    ImageI &plane = input.channel[c0].plane;
     88    JXL_ASSIGN_OR_RETURN(
     89        indices, ImageI::Create(memory_manager, plane.xsize(), plane.ysize()));
     90    plane.Swap(indices);
     91    if (predictor == Predictor::Weighted) {
     92      const auto process_row = [&](const uint32_t c,
     93                                   size_t /* thread */) -> Status {
     94        Channel &channel = input.channel[c0 + c];
     95        weighted::State wp_state(wp_header, channel.w, channel.h);
     96        for (size_t y = 0; y < channel.h; y++) {
     97          pixel_type *JXL_RESTRICT p = channel.Row(y);
     98          const pixel_type *JXL_RESTRICT idx = indices.Row(y);
     99          for (size_t x = 0; x < channel.w; x++) {
    100            int index = idx[x];
    101            pixel_type_w val = 0;
    102            const pixel_type palette_entry = palette_internal::GetPaletteValue(
    103                p_palette, index, /*c=*/c,
    104                /*palette_size=*/palette.w, /*onerow=*/onerow,
    105                /*bit_depth=*/bit_depth);
    106            if (index < static_cast<int32_t>(nb_deltas)) {
    107              PredictionResult pred = PredictNoTreeWP(
    108                  channel.w, p + x, onerow_image, x, y, predictor, &wp_state);
    109              val = pred.guess + palette_entry;
    110            } else {
    111              val = palette_entry;
    112            }
    113            p[x] = val;
    114            wp_state.UpdateErrors(p[x], x, y, channel.w);
    115          }
    116        }
    117        return true;
    118      };
    119      JXL_RETURN_IF_ERROR(RunOnPool(pool, 0, nb, ThreadPool::NoInit,
    120                                    process_row, "UndoDeltaPaletteWP"));
    121    } else {
    122      const auto process_row = [&](const uint32_t c,
    123                                   size_t /* thread */) -> Status {
    124        Channel &channel = input.channel[c0 + c];
    125        for (size_t y = 0; y < channel.h; y++) {
    126          pixel_type *JXL_RESTRICT p = channel.Row(y);
    127          const pixel_type *JXL_RESTRICT idx = indices.Row(y);
    128          for (size_t x = 0; x < channel.w; x++) {
    129            int index = idx[x];
    130            pixel_type_w val = 0;
    131            const pixel_type palette_entry = palette_internal::GetPaletteValue(
    132                p_palette, index, /*c=*/c,
    133                /*palette_size=*/palette.w,
    134                /*onerow=*/onerow, /*bit_depth=*/bit_depth);
    135            if (index < static_cast<int32_t>(nb_deltas)) {
    136              PredictionResult pred = PredictNoTreeNoWP(
    137                  channel.w, p + x, onerow_image, x, y, predictor);
    138              val = pred.guess + palette_entry;
    139            } else {
    140              val = palette_entry;
    141            }
    142            p[x] = val;
    143          }
    144        }
    145        return true;
    146      };
    147      JXL_RETURN_IF_ERROR(RunOnPool(pool, 0, nb, ThreadPool::NoInit,
    148                                    process_row, "UndoDeltaPaletteNoWP"));
    149    }
    150  }
    151  if (c0 >= input.nb_meta_channels) {
    152    // Palette was done on normal channels
    153    input.nb_meta_channels--;
    154  } else {
    155    // Palette was done on metachannels
    156    JXL_ENSURE(static_cast<int>(input.nb_meta_channels) >= 2 - nb);
    157    input.nb_meta_channels -= 2 - nb;
    158    JXL_ENSURE(begin_c + nb - 1 < input.nb_meta_channels);
    159  }
    160  input.channel.erase(input.channel.begin(), input.channel.begin() + 1);
    161  return true;
    162 }
    163 
    164 Status MetaPalette(Image &input, uint32_t begin_c, uint32_t end_c,
    165                   uint32_t nb_colors, uint32_t nb_deltas, bool lossy) {
    166  JXL_RETURN_IF_ERROR(CheckEqualChannels(input, begin_c, end_c));
    167  JxlMemoryManager *memory_manager = input.memory_manager();
    168 
    169  size_t nb = end_c - begin_c + 1;
    170  if (begin_c >= input.nb_meta_channels) {
    171    // Palette was done on normal channels
    172    input.nb_meta_channels++;
    173  } else {
    174    // Palette was done on metachannels
    175    JXL_ENSURE(end_c < input.nb_meta_channels);
    176    // we remove nb-1 metachannels and add one
    177    input.nb_meta_channels += 2 - nb;
    178  }
    179  input.channel.erase(input.channel.begin() + begin_c + 1,
    180                      input.channel.begin() + end_c + 1);
    181  JXL_ASSIGN_OR_RETURN(
    182      Channel pch, Channel::Create(memory_manager, nb_colors + nb_deltas, nb));
    183  pch.hshift = -1;
    184  pch.vshift = -1;
    185  input.channel.insert(input.channel.begin(), std::move(pch));
    186  return true;
    187 }
    188 
    189 }  // namespace jxl