libjxl

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

blending.cc (6653B)


      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/blending.h"
      7 
      8 #include "lib/jxl/alpha.h"
      9 
     10 namespace jxl {
     11 
     12 bool NeedsBlending(const FrameHeader& frame_header) {
     13   if (!(frame_header.frame_type == FrameType::kRegularFrame ||
     14         frame_header.frame_type == FrameType::kSkipProgressive)) {
     15     return false;
     16   }
     17   const auto& info = frame_header.blending_info;
     18   bool replace_all = (info.mode == BlendMode::kReplace);
     19   for (const auto& ec_i : frame_header.extra_channel_blending_info) {
     20     if (ec_i.mode != BlendMode::kReplace) {
     21       replace_all = false;
     22     }
     23   }
     24   // Replace the full frame: nothing to do.
     25   if (!frame_header.custom_size_or_origin && replace_all) {
     26     return false;
     27   }
     28   return true;
     29 }
     30 
     31 Status PerformBlending(
     32     const float* const* bg, const float* const* fg, float* const* out,
     33     size_t x0, size_t xsize, const PatchBlending& color_blending,
     34     const PatchBlending* ec_blending,
     35     const std::vector<ExtraChannelInfo>& extra_channel_info) {
     36   bool has_alpha = false;
     37   size_t num_ec = extra_channel_info.size();
     38   for (size_t i = 0; i < num_ec; i++) {
     39     if (extra_channel_info[i].type == jxl::ExtraChannel::kAlpha) {
     40       has_alpha = true;
     41       break;
     42     }
     43   }
     44   JXL_ASSIGN_OR_RETURN(ImageF tmp, ImageF::Create(xsize, 3 + num_ec));
     45   // Blend extra channels first so that we use the pre-blending alpha.
     46   for (size_t i = 0; i < num_ec; i++) {
     47     if (ec_blending[i].mode == PatchBlendMode::kAdd) {
     48       for (size_t x = 0; x < xsize; x++) {
     49         tmp.Row(3 + i)[x] = bg[3 + i][x + x0] + fg[3 + i][x + x0];
     50       }
     51     } else if (ec_blending[i].mode == PatchBlendMode::kBlendAbove) {
     52       size_t alpha = ec_blending[i].alpha_channel;
     53       bool is_premultiplied = extra_channel_info[alpha].alpha_associated;
     54       PerformAlphaBlending(bg[3 + i] + x0, bg[3 + alpha] + x0, fg[3 + i] + x0,
     55                            fg[3 + alpha] + x0, tmp.Row(3 + i), xsize,
     56                            is_premultiplied, ec_blending[i].clamp);
     57     } else if (ec_blending[i].mode == PatchBlendMode::kBlendBelow) {
     58       size_t alpha = ec_blending[i].alpha_channel;
     59       bool is_premultiplied = extra_channel_info[alpha].alpha_associated;
     60       PerformAlphaBlending(fg[3 + i] + x0, fg[3 + alpha] + x0, bg[3 + i] + x0,
     61                            bg[3 + alpha] + x0, tmp.Row(3 + i), xsize,
     62                            is_premultiplied, ec_blending[i].clamp);
     63     } else if (ec_blending[i].mode == PatchBlendMode::kAlphaWeightedAddAbove) {
     64       size_t alpha = ec_blending[i].alpha_channel;
     65       PerformAlphaWeightedAdd(bg[3 + i] + x0, fg[3 + i] + x0,
     66                               fg[3 + alpha] + x0, tmp.Row(3 + i), xsize,
     67                               ec_blending[i].clamp);
     68     } else if (ec_blending[i].mode == PatchBlendMode::kAlphaWeightedAddBelow) {
     69       size_t alpha = ec_blending[i].alpha_channel;
     70       PerformAlphaWeightedAdd(fg[3 + i] + x0, bg[3 + i] + x0,
     71                               bg[3 + alpha] + x0, tmp.Row(3 + i), xsize,
     72                               ec_blending[i].clamp);
     73     } else if (ec_blending[i].mode == PatchBlendMode::kMul) {
     74       PerformMulBlending(bg[3 + i] + x0, fg[3 + i] + x0, tmp.Row(3 + i), xsize,
     75                          ec_blending[i].clamp);
     76     } else if (ec_blending[i].mode == PatchBlendMode::kReplace) {
     77       memcpy(tmp.Row(3 + i), fg[3 + i] + x0, xsize * sizeof(**fg));
     78     } else if (ec_blending[i].mode == PatchBlendMode::kNone) {
     79       if (xsize) memcpy(tmp.Row(3 + i), bg[3 + i] + x0, xsize * sizeof(**fg));
     80     } else {
     81       JXL_UNREACHABLE("new PatchBlendMode?");
     82     }
     83   }
     84   size_t alpha = color_blending.alpha_channel;
     85 
     86   if (color_blending.mode == PatchBlendMode::kAdd ||
     87       (color_blending.mode == PatchBlendMode::kAlphaWeightedAddAbove &&
     88        !has_alpha) ||
     89       (color_blending.mode == PatchBlendMode::kAlphaWeightedAddBelow &&
     90        !has_alpha)) {
     91     for (int p = 0; p < 3; p++) {
     92       float* out = tmp.Row(p);
     93       for (size_t x = 0; x < xsize; x++) {
     94         out[x] = bg[p][x + x0] + fg[p][x + x0];
     95       }
     96     }
     97   } else if (color_blending.mode == PatchBlendMode::kBlendAbove
     98              // blend without alpha is just replace
     99              && has_alpha) {
    100     bool is_premultiplied = extra_channel_info[alpha].alpha_associated;
    101     PerformAlphaBlending(
    102         {bg[0] + x0, bg[1] + x0, bg[2] + x0, bg[3 + alpha] + x0},
    103         {fg[0] + x0, fg[1] + x0, fg[2] + x0, fg[3 + alpha] + x0},
    104         {tmp.Row(0), tmp.Row(1), tmp.Row(2), tmp.Row(3 + alpha)}, xsize,
    105         is_premultiplied, color_blending.clamp);
    106   } else if (color_blending.mode == PatchBlendMode::kBlendBelow
    107              // blend without alpha is just replace
    108              && has_alpha) {
    109     bool is_premultiplied = extra_channel_info[alpha].alpha_associated;
    110     PerformAlphaBlending(
    111         {fg[0] + x0, fg[1] + x0, fg[2] + x0, fg[3 + alpha] + x0},
    112         {bg[0] + x0, bg[1] + x0, bg[2] + x0, bg[3 + alpha] + x0},
    113         {tmp.Row(0), tmp.Row(1), tmp.Row(2), tmp.Row(3 + alpha)}, xsize,
    114         is_premultiplied, color_blending.clamp);
    115   } else if (color_blending.mode == PatchBlendMode::kAlphaWeightedAddAbove) {
    116     JXL_DASSERT(has_alpha);
    117     for (size_t c = 0; c < 3; c++) {
    118       PerformAlphaWeightedAdd(bg[c] + x0, fg[c] + x0, fg[3 + alpha] + x0,
    119                               tmp.Row(c), xsize, color_blending.clamp);
    120     }
    121   } else if (color_blending.mode == PatchBlendMode::kAlphaWeightedAddBelow) {
    122     JXL_DASSERT(has_alpha);
    123     for (size_t c = 0; c < 3; c++) {
    124       PerformAlphaWeightedAdd(fg[c] + x0, bg[c] + x0, bg[3 + alpha] + x0,
    125                               tmp.Row(c), xsize, color_blending.clamp);
    126     }
    127   } else if (color_blending.mode == PatchBlendMode::kMul) {
    128     for (int p = 0; p < 3; p++) {
    129       PerformMulBlending(bg[p] + x0, fg[p] + x0, tmp.Row(p), xsize,
    130                          color_blending.clamp);
    131     }
    132   } else if (color_blending.mode == PatchBlendMode::kReplace ||
    133              color_blending.mode == PatchBlendMode::kBlendAbove ||
    134              color_blending.mode == PatchBlendMode::kBlendBelow) {  // kReplace
    135     for (size_t p = 0; p < 3; p++) {
    136       memcpy(tmp.Row(p), fg[p] + x0, xsize * sizeof(**fg));
    137     }
    138   } else if (color_blending.mode == PatchBlendMode::kNone) {
    139     for (size_t p = 0; p < 3; p++) {
    140       memcpy(tmp.Row(p), bg[p] + x0, xsize * sizeof(**fg));
    141     }
    142   } else {
    143     JXL_UNREACHABLE("new PatchBlendMode?");
    144   }
    145   for (size_t i = 0; i < 3 + num_ec; i++) {
    146     if (xsize != 0) memcpy(out[i] + x0, tmp.Row(i), xsize * sizeof(**out));
    147   }
    148   return true;
    149 }
    150 
    151 }  // namespace jxl