tor-browser

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

enc_comparator.cc (5147B)


      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/enc_comparator.h"
      7 
      8 #include <jxl/memory_manager.h>
      9 
     10 #include <algorithm>
     11 #include <cstddef>
     12 
     13 #include "lib/jxl/base/compiler_specific.h"
     14 #include "lib/jxl/base/status.h"
     15 #include "lib/jxl/enc_gamma_correct.h"
     16 #include "lib/jxl/enc_image_bundle.h"
     17 
     18 namespace jxl {
     19 namespace {
     20 
     21 // color is linear, but blending happens in gamma-compressed space using
     22 // (gamma-compressed) grayscale background color, alpha image represents
     23 // weights of the sRGB colors in the [0 .. (1 << bit_depth) - 1] interval,
     24 // output image is in linear space.
     25 void AlphaBlend(const Image3F& in, const size_t c, float background_linear,
     26                const ImageF& alpha, Image3F* out) {
     27  const float background = LinearToSrgb8Direct(background_linear);
     28 
     29  for (size_t y = 0; y < out->ysize(); ++y) {
     30    const float* JXL_RESTRICT row_a = alpha.ConstRow(y);
     31    const float* JXL_RESTRICT row_i = in.ConstPlaneRow(c, y);
     32    float* JXL_RESTRICT row_o = out->PlaneRow(c, y);
     33    for (size_t x = 0; x < out->xsize(); ++x) {
     34      const float a = row_a[x];
     35      if (a <= 0.f) {
     36        row_o[x] = background_linear;
     37      } else if (a >= 1.f) {
     38        row_o[x] = row_i[x];
     39      } else {
     40        const float w_fg = a;
     41        const float w_bg = 1.0f - w_fg;
     42        const float fg = w_fg * LinearToSrgb8Direct(row_i[x]);
     43        const float bg = w_bg * background;
     44        row_o[x] = Srgb8ToLinearDirect(fg + bg);
     45      }
     46    }
     47  }
     48 }
     49 
     50 void AlphaBlend(float background_linear, ImageBundle* io_linear_srgb) {
     51  // No alpha => all opaque.
     52  if (!io_linear_srgb->HasAlpha()) return;
     53 
     54  for (size_t c = 0; c < 3; ++c) {
     55    AlphaBlend(*io_linear_srgb->color(), c, background_linear,
     56               *io_linear_srgb->alpha(), io_linear_srgb->color());
     57  }
     58 }
     59 
     60 Status ComputeScoreImpl(const ImageBundle& rgb0, const ImageBundle& rgb1,
     61                        Comparator* comparator, ImageF* distmap, float& score) {
     62  JXL_RETURN_IF_ERROR(comparator->SetReferenceImage(rgb0));
     63  JXL_RETURN_IF_ERROR(comparator->CompareWith(rgb1, distmap, &score));
     64  return true;
     65 }
     66 
     67 }  // namespace
     68 
     69 Status ComputeScore(const ImageBundle& rgb0, const ImageBundle& rgb1,
     70                    Comparator* comparator, const JxlCmsInterface& cms,
     71                    float* score, ImageF* diffmap, ThreadPool* pool,
     72                    bool ignore_alpha) {
     73  JxlMemoryManager* memory_manager = rgb0.memory_manager();
     74  // Convert to linear sRGB (unless already in that space)
     75  ImageMetadata metadata0 = *rgb0.metadata();
     76  ImageBundle store0(memory_manager, &metadata0);
     77  const ImageBundle* linear_srgb0;
     78  JXL_RETURN_IF_ERROR(
     79      TransformIfNeeded(rgb0, ColorEncoding::LinearSRGB(rgb0.IsGray()), cms,
     80                        pool, &store0, &linear_srgb0));
     81  ImageMetadata metadata1 = *rgb1.metadata();
     82  ImageBundle store1(memory_manager, &metadata1);
     83  const ImageBundle* linear_srgb1;
     84  JXL_RETURN_IF_ERROR(
     85      TransformIfNeeded(rgb1, ColorEncoding::LinearSRGB(rgb1.IsGray()), cms,
     86                        pool, &store1, &linear_srgb1));
     87 
     88  // No alpha: skip blending, only need a single call to Butteraugli.
     89  if (ignore_alpha || (!rgb0.HasAlpha() && !rgb1.HasAlpha())) {
     90    JXL_RETURN_IF_ERROR(ComputeScoreImpl(*linear_srgb0, *linear_srgb1,
     91                                         comparator, diffmap, *score));
     92    return true;
     93  }
     94 
     95  // Blend on black and white backgrounds
     96 
     97  const float black = 0.0f;
     98  JXL_ASSIGN_OR_RETURN(ImageBundle blended_black0, linear_srgb0->Copy());
     99  JXL_ASSIGN_OR_RETURN(ImageBundle blended_black1, linear_srgb1->Copy());
    100  AlphaBlend(black, &blended_black0);
    101  AlphaBlend(black, &blended_black1);
    102 
    103  const float white = 1.0f;
    104  JXL_ASSIGN_OR_RETURN(ImageBundle blended_white0, linear_srgb0->Copy());
    105  JXL_ASSIGN_OR_RETURN(ImageBundle blended_white1, linear_srgb1->Copy());
    106 
    107  AlphaBlend(white, &blended_white0);
    108  AlphaBlend(white, &blended_white1);
    109 
    110  ImageF diffmap_black;
    111  ImageF diffmap_white;
    112  float dist_black;
    113  JXL_RETURN_IF_ERROR(ComputeScoreImpl(blended_black0, blended_black1,
    114                                       comparator, &diffmap_black, dist_black));
    115  float dist_white;
    116  JXL_RETURN_IF_ERROR(ComputeScoreImpl(blended_white0, blended_white1,
    117                                       comparator, &diffmap_white, dist_white));
    118 
    119  // diffmap and return values are the max of diffmap_black/white.
    120  if (diffmap != nullptr) {
    121    const size_t xsize = rgb0.xsize();
    122    const size_t ysize = rgb0.ysize();
    123    JXL_ASSIGN_OR_RETURN(*diffmap,
    124                         ImageF::Create(memory_manager, xsize, ysize));
    125    for (size_t y = 0; y < ysize; ++y) {
    126      const float* JXL_RESTRICT row_black = diffmap_black.ConstRow(y);
    127      const float* JXL_RESTRICT row_white = diffmap_white.ConstRow(y);
    128      float* JXL_RESTRICT row_out = diffmap->Row(y);
    129      for (size_t x = 0; x < xsize; ++x) {
    130        row_out[x] = std::max(row_black[x], row_white[x]);
    131      }
    132    }
    133  }
    134  *score = std::max(dist_black, dist_white);
    135  return true;
    136 }
    137 
    138 }  // namespace jxl