Imported Upstream version 0.9.0
[platform/upstream/libjxl.git] / lib / jxl / dec_cache.cc
index b819b51..d5e15bc 100644 (file)
@@ -6,8 +6,10 @@
 #include "lib/jxl/dec_cache.h"
 
 #include "lib/jxl/blending.h"
+#include "lib/jxl/common.h"  // JXL_HIGH_PRECISION
 #include "lib/jxl/render_pipeline/stage_blending.h"
 #include "lib/jxl/render_pipeline/stage_chroma_upsampling.h"
+#include "lib/jxl/render_pipeline/stage_cms.h"
 #include "lib/jxl/render_pipeline/stage_epf.h"
 #include "lib/jxl/render_pipeline/stage_from_linear.h"
 #include "lib/jxl/render_pipeline/stage_gaborish.h"
@@ -28,7 +30,7 @@ Status PassesDecoderState::PreparePipeline(ImageBundle* decoded,
                                            PipelineOptions options) {
   const FrameHeader& frame_header = shared->frame_header;
   size_t num_c = 3 + frame_header.nonserialized_metadata->m.num_extra_channels;
-  if ((frame_header.flags & FrameHeader::kNoise) != 0) {
+  if (options.render_noise && (frame_header.flags & FrameHeader::kNoise) != 0) {
     num_c += 3;
   }
 
@@ -110,8 +112,7 @@ Status PassesDecoderState::PreparePipeline(ImageBundle* decoded,
           CeilLog2Nonzero(frame_header.upsampling)));
     }
   }
-
-  if ((frame_header.flags & FrameHeader::kNoise) != 0) {
+  if (options.render_noise && (frame_header.flags & FrameHeader::kNoise) != 0) {
     builder.AddStage(GetConvolveNoiseStage(num_c - 3));
     builder.AddStage(GetAddNoiseStage(shared->image_features.noise_params,
                                       shared->cmap, num_c - 3));
@@ -138,29 +139,29 @@ Status PassesDecoderState::PreparePipeline(ImageBundle* decoded,
     }
   }
 
-  size_t width = options.coalescing
-                     ? frame_header.nonserialized_metadata->xsize()
-                     : shared->frame_dim.xsize_upsampled;
-  size_t height = options.coalescing
-                      ? frame_header.nonserialized_metadata->ysize()
-                      : shared->frame_dim.ysize_upsampled;
-
   if (fast_xyb_srgb8_conversion) {
+#if !JXL_HIGH_PRECISION
     JXL_ASSERT(!NeedsBlending(this));
     JXL_ASSERT(!frame_header.CanBeReferenced() ||
                frame_header.save_before_color_transform);
     JXL_ASSERT(!options.render_spotcolors ||
                !decoded->metadata()->Find(ExtraChannel::kSpotColor));
-    builder.AddStage(GetFastXYBTosRGB8Stage(rgb_output, rgb_stride, width,
-                                            height, rgb_output_is_rgba,
-                                            has_alpha, alpha_c));
+    bool is_rgba = (main_output.format.num_channels == 4);
+    uint8_t* rgb_output = reinterpret_cast<uint8_t*>(main_output.buffer);
+    builder.AddStage(GetFastXYBTosRGB8Stage(rgb_output, main_output.stride,
+                                            width, height, is_rgba, has_alpha,
+                                            alpha_c));
+#endif
   } else {
     bool linear = false;
     if (frame_header.color_transform == ColorTransform::kYCbCr) {
       builder.AddStage(GetYCbCrStage());
     } else if (frame_header.color_transform == ColorTransform::kXYB) {
-      builder.AddStage(GetXYBStage(output_encoding_info.opsin_params));
-      linear = true;
+      builder.AddStage(GetXYBStage(output_encoding_info));
+      if (output_encoding_info.color_encoding.GetColorSpace() !=
+          ColorSpace::kXYB) {
+        linear = true;
+      }
     }  // Nothing to do for kNone.
 
     if (options.coalescing && NeedsBlending(this)) {
@@ -200,29 +201,57 @@ Status PassesDecoderState::PreparePipeline(ImageBundle* decoded,
       if (!linear) {
         auto to_linear_stage = GetToLinearStage(output_encoding_info);
         if (!to_linear_stage) {
-          return JXL_FAILURE(
-              "attempting to perform tone mapping on colorspace not "
-              "convertible to linear");
+          if (!output_encoding_info.cms_set) {
+            return JXL_FAILURE("Cannot tonemap this colorspace without a CMS");
+          }
+          auto cms_stage = GetCmsStage(output_encoding_info);
+          if (cms_stage) {
+            builder.AddStage(std::move(cms_stage));
+          }
+        } else {
+          builder.AddStage(std::move(to_linear_stage));
         }
-        builder.AddStage(std::move(to_linear_stage));
         linear = true;
       }
       builder.AddStage(std::move(tone_mapping_stage));
     }
 
     if (linear) {
-      builder.AddStage(GetFromLinearStage(output_encoding_info));
+      const size_t channels_src =
+          (output_encoding_info.orig_color_encoding.IsCMYK()
+               ? 4
+               : output_encoding_info.orig_color_encoding.Channels());
+      const size_t channels_dst =
+          output_encoding_info.color_encoding.Channels();
+      bool mixing_color_and_grey = (channels_dst != channels_src);
+      if ((output_encoding_info.color_encoding_is_original) ||
+          (!output_encoding_info.cms_set) || mixing_color_and_grey) {
+        // in those cases we only need a linear stage in other cases we attempt
+        // to obtain an cms stage: the cases are
+        // - output_encoding_info.color_encoding_is_original: no cms stage
+        // needed because it would be a no-op
+        // - !output_encoding_info.cms_set: can't use the cms, so no point in
+        // trying to add a cms stage
+        // - mixing_color_and_grey: cms stage can't handle that
+        // TODO(firsching): remove "mixing_color_and_grey" condition after
+        // adding support for greyscale to cms stage.
+        builder.AddStage(GetFromLinearStage(output_encoding_info));
+      } else {
+        if (!output_encoding_info.linear_color_encoding.CreateICC()) {
+          return JXL_FAILURE("Failed to create ICC");
+        }
+        auto cms_stage = GetCmsStage(output_encoding_info);
+        if (cms_stage) {
+          builder.AddStage(std::move(cms_stage));
+        }
+      }
       linear = false;
     }
 
-    if (pixel_callback.IsPresent()) {
-      builder.AddStage(GetWriteToPixelCallbackStage(
-          pixel_callback, width, height, rgb_output_is_rgba, has_alpha,
-          unpremul_alpha, alpha_c));
-    } else if (rgb_output) {
-      builder.AddStage(GetWriteToU8Stage(rgb_output, rgb_stride, height,
-                                         rgb_output_is_rgba, has_alpha,
-                                         alpha_c));
+    if (main_output.callback.IsPresent() || main_output.buffer) {
+      builder.AddStage(GetWriteToOutputStage(main_output, width, height,
+                                             has_alpha, unpremul_alpha, alpha_c,
+                                             undo_orientation, extra_output));
     } else {
       builder.AddStage(GetWriteToImageBundleStage(
           decoded, output_encoding_info.color_encoding));