diff options
author | Jiyong <jiyong.min@samsung.com> | 2023-12-26 17:33:03 +0900 |
---|---|---|
committer | Jiyong <jiyong.min@samsung.com> | 2023-12-27 08:25:11 +0900 |
commit | a6d06c38e46e552195648836052eb909925fe5ff (patch) | |
tree | 5b34f3947c8331dc618a5166974e4d9757f8e782 /plugins/gimp | |
parent | f3e519be675ef7922a6c1c3a682232302b55496d (diff) | |
parent | 3b773d382e34fcfc7c8995d8bd681a6ef0529b02 (diff) | |
download | libjxl-accepted/tizen_unified_riscv.tar.gz libjxl-accepted/tizen_unified_riscv.tar.bz2 libjxl-accepted/tizen_unified_riscv.zip |
Merge branch 'upstream' into tizenaccepted/tizen/unified/riscv/20240103.054630accepted/tizen/unified/20231228.165749accepted/tizen_unified_riscv
Change-Id: I13b4d2c94ada4853484630800e2a8a5ae90d34c1
Diffstat (limited to 'plugins/gimp')
-rw-r--r-- | plugins/gimp/common.h | 4 | ||||
-rw-r--r-- | plugins/gimp/file-jxl-load.cc | 180 | ||||
-rw-r--r-- | plugins/gimp/file-jxl-load.h | 2 | ||||
-rw-r--r-- | plugins/gimp/file-jxl-save.cc | 55 | ||||
-rw-r--r-- | plugins/gimp/file-jxl-save.h | 2 |
5 files changed, 169 insertions, 74 deletions
diff --git a/plugins/gimp/common.h b/plugins/gimp/common.h index 95c51bf..3fe63c1 100644 --- a/plugins/gimp/common.h +++ b/plugins/gimp/common.h @@ -23,8 +23,8 @@ #undef MIN #undef CLAMP -#include "jxl/resizable_parallel_runner.h" -#include "jxl/resizable_parallel_runner_cxx.h" +#include <jxl/resizable_parallel_runner.h> +#include <jxl/resizable_parallel_runner_cxx.h> namespace jxl { diff --git a/plugins/gimp/file-jxl-load.cc b/plugins/gimp/file-jxl-load.cc index b1d1f15..4796c17 100644 --- a/plugins/gimp/file-jxl-load.cc +++ b/plugins/gimp/file-jxl-load.cc @@ -5,17 +5,45 @@ #include "plugins/gimp/file-jxl-load.h" +#include <jxl/decode.h> +#include <jxl/decode_cxx.h> + #define _PROFILE_ORIGIN_ JXL_COLOR_PROFILE_TARGET_ORIGINAL #define _PROFILE_TARGET_ JXL_COLOR_PROFILE_TARGET_DATA #define LOAD_PROC "file-jxl-load" namespace jxl { +bool SetJpegXlOutBuffer( + std::unique_ptr<JxlDecoderStruct, JxlDecoderDestroyStruct> *dec, + JxlPixelFormat *format, size_t *buffer_size, gpointer *pixels_buffer_1) { + if (JXL_DEC_SUCCESS != + JxlDecoderImageOutBufferSize(dec->get(), format, buffer_size)) { + g_printerr(LOAD_PROC " Error: JxlDecoderImageOutBufferSize failed\n"); + return false; + } + *pixels_buffer_1 = g_malloc(*buffer_size); + if (JXL_DEC_SUCCESS != JxlDecoderSetImageOutBuffer(dec->get(), format, + *pixels_buffer_1, + *buffer_size)) { + g_printerr(LOAD_PROC " Error: JxlDecoderSetImageOutBuffer failed\n"); + return false; + } + return true; +} + bool LoadJpegXlImage(const gchar *const filename, gint32 *const image_id) { + bool stop_processing = false; + JxlDecoderStatus status = JXL_DEC_NEED_MORE_INPUT; std::vector<uint8_t> icc_profile; GimpColorProfile *profile_icc = nullptr; GimpColorProfile *profile_int = nullptr; bool is_linear = false; + unsigned long xsize = 0, ysize = 0; + long crop_x0 = 0, crop_y0 = 0; + size_t layer_idx = 0; + uint32_t frame_duration = 0; + double tps_denom = 1.f, tps_numer = 1.f; gint32 layer; @@ -28,6 +56,10 @@ bool LoadJpegXlImage(const gchar *const filename, gint32 *const image_id) { GimpPrecision precision = GIMP_PRECISION_U16_GAMMA; JxlBasicInfo info = {}; JxlPixelFormat format = {}; + JxlAnimationHeader animation = {}; + JxlBlendMode blend_mode = JXL_BLEND_BLEND; + char *frame_name = nullptr; // will be realloced + size_t frame_name_len = 0; format.num_channels = 4; format.data_type = JXL_TYPE_FLOAT; @@ -53,9 +85,10 @@ bool LoadJpegXlImage(const gchar *const filename, gint32 *const image_id) { auto dec = JxlDecoderMake(nullptr); if (JXL_DEC_SUCCESS != - JxlDecoderSubscribeEvents(dec.get(), JXL_DEC_BASIC_INFO | - JXL_DEC_COLOR_ENCODING | - JXL_DEC_FULL_IMAGE)) { + JxlDecoderSubscribeEvents( + dec.get(), JXL_DEC_BASIC_INFO | JXL_DEC_COLOR_ENCODING | + JXL_DEC_FULL_IMAGE | JXL_DEC_FRAME_PROGRESSION | + JXL_DEC_FRAME)) { g_printerr(LOAD_PROC " Error: JxlDecoderSubscribeEvents failed\n"); return false; } @@ -66,14 +99,26 @@ bool LoadJpegXlImage(const gchar *const filename, gint32 *const image_id) { g_printerr(LOAD_PROC " Error: JxlDecoderSetParallelRunner failed\n"); return false; } + // TODO(user): make this work with coalescing set to false, while handling + // frames with duration 0 and references to earlier frames correctly. + if (JXL_DEC_SUCCESS != JxlDecoderSetCoalescing(dec.get(), JXL_TRUE)) { + g_printerr(LOAD_PROC " Error: JxlDecoderSetCoalescing failed\n"); + return false; + } // grand decode loop... JxlDecoderSetInput(dec.get(), compressed.data(), compressed.size()); + if (JXL_DEC_SUCCESS != JxlDecoderSetProgressiveDetail( + dec.get(), JxlProgressiveDetail::kPasses)) { + g_printerr(LOAD_PROC " Error: JxlDecoderSetProgressiveDetail failed\n"); + return false; + } + while (true) { gimp_load_progress.update(); - JxlDecoderStatus status = JxlDecoderProcessInput(dec.get()); + if (!stop_processing) status = JxlDecoderProcessInput(dec.get()); if (status == JXL_DEC_BASIC_INFO) { if (JXL_DEC_SUCCESS != JxlDecoderGetBasicInfo(dec.get(), &info)) { @@ -81,20 +126,26 @@ bool LoadJpegXlImage(const gchar *const filename, gint32 *const image_id) { return false; } + xsize = info.xsize; + ysize = info.ysize; + if (info.have_animation) { + animation = info.animation; + tps_denom = animation.tps_denominator; + tps_numer = animation.tps_numerator; + } + JxlResizableParallelRunnerSetThreads( - runner.get(), - JxlResizableParallelRunnerSuggestThreads(info.xsize, info.ysize)); + runner.get(), JxlResizableParallelRunnerSuggestThreads(xsize, ysize)); } else if (status == JXL_DEC_COLOR_ENCODING) { // check for ICC profile size_t icc_size = 0; JxlColorEncoding color_encoding; if (JXL_DEC_SUCCESS != - JxlDecoderGetColorAsEncodedProfile( - dec.get(), &format, _PROFILE_ORIGIN_, &color_encoding)) { + JxlDecoderGetColorAsEncodedProfile(dec.get(), _PROFILE_ORIGIN_, + &color_encoding)) { // Attempt to load ICC profile when no internal color encoding - if (JXL_DEC_SUCCESS != JxlDecoderGetICCProfileSize(dec.get(), &format, - _PROFILE_ORIGIN_, - &icc_size)) { + if (JXL_DEC_SUCCESS != JxlDecoderGetICCProfileSize( + dec.get(), _PROFILE_ORIGIN_, &icc_size)) { g_printerr(LOAD_PROC " Warning: JxlDecoderGetICCProfileSize failed\n"); } @@ -102,7 +153,7 @@ bool LoadJpegXlImage(const gchar *const filename, gint32 *const image_id) { if (icc_size > 0) { icc_profile.resize(icc_size); if (JXL_DEC_SUCCESS != JxlDecoderGetColorAsICCProfile( - dec.get(), &format, _PROFILE_ORIGIN_, + dec.get(), _PROFILE_ORIGIN_, icc_profile.data(), icc_profile.size())) { g_printerr(LOAD_PROC " Warning: JxlDecoderGetColorAsICCProfile failed\n"); @@ -125,8 +176,8 @@ bool LoadJpegXlImage(const gchar *const filename, gint32 *const image_id) { // Internal color profile detection... if (JXL_DEC_SUCCESS == - JxlDecoderGetColorAsEncodedProfile( - dec.get(), &format, _PROFILE_TARGET_, &color_encoding)) { + JxlDecoderGetColorAsEncodedProfile(dec.get(), _PROFILE_TARGET_, + &color_encoding)) { g_printerr(LOAD_PROC " Info: Internal color encoding detected.\n"); // figure out linearity of internal profile @@ -279,11 +330,11 @@ bool LoadJpegXlImage(const gchar *const filename, gint32 *const image_id) { // create new image if (is_linear) { - *image_id = gimp_image_new_with_precision( - info.xsize, info.ysize, image_type, GIMP_PRECISION_FLOAT_LINEAR); + *image_id = gimp_image_new_with_precision(xsize, ysize, image_type, + GIMP_PRECISION_FLOAT_LINEAR); } else { - *image_id = gimp_image_new_with_precision( - info.xsize, info.ysize, image_type, GIMP_PRECISION_FLOAT_GAMMA); + *image_id = gimp_image_new_with_precision(xsize, ysize, image_type, + GIMP_PRECISION_FLOAT_GAMMA); } if (profile_int) { @@ -294,22 +345,40 @@ bool LoadJpegXlImage(const gchar *const filename, gint32 *const image_id) { } else if (status == JXL_DEC_NEED_IMAGE_OUT_BUFFER) { // get image from decoder in FLOAT format.data_type = JXL_TYPE_FLOAT; - if (JXL_DEC_SUCCESS != - JxlDecoderImageOutBufferSize(dec.get(), &format, &buffer_size)) { - g_printerr(LOAD_PROC " Error: JxlDecoderImageOutBufferSize failed\n"); + if (!SetJpegXlOutBuffer(&dec, &format, &buffer_size, &pixels_buffer_1)) return false; - } - pixels_buffer_1 = g_malloc(buffer_size); - if (JXL_DEC_SUCCESS != JxlDecoderSetImageOutBuffer(dec.get(), &format, - pixels_buffer_1, - buffer_size)) { - g_printerr(LOAD_PROC " Error: JxlDecoderSetImageOutBuffer failed\n"); - return false; - } - } else if (status == JXL_DEC_FULL_IMAGE || status == JXL_DEC_FRAME) { + } else if (status == JXL_DEC_FULL_IMAGE) { // create and insert layer - layer = gimp_layer_new(*image_id, "Background", info.xsize, info.ysize, - layer_type, /*opacity=*/100, + gchar *layer_name; + if (layer_idx == 0 && !info.have_animation) { + layer_name = g_strdup_printf("Background"); + } else { + const GString *blend_null_flag = g_string_new(""); + const GString *blend_replace_flag = g_string_new(" (replace)"); + const GString *blend_combine_flag = g_string_new(" (combine)"); + GString *blend; + if (blend_mode == JXL_BLEND_REPLACE) { + blend = (GString *)blend_replace_flag; + } else if (blend_mode == JXL_BLEND_BLEND) { + blend = (GString *)blend_combine_flag; + } else { + blend = (GString *)blend_null_flag; + } + char *temp_frame_name = nullptr; + bool must_free_frame_name = false; + if (frame_name_len == 0) { + temp_frame_name = g_strdup_printf("Frame %lu", layer_idx + 1); + must_free_frame_name = true; + } else { + temp_frame_name = frame_name; + } + double fduration = frame_duration * 1000.f * tps_denom / tps_numer; + layer_name = g_strdup_printf("%s (%.15gms)%s", temp_frame_name, + fduration, blend->str); + if (must_free_frame_name) free(temp_frame_name); + } + layer = gimp_layer_new(*image_id, layer_name, xsize, ysize, layer_type, + /*opacity=*/100, gimp_image_get_default_new_layer_mode(*image_id)); gimp_image_insert_layer(*image_id, layer, /*parent_id=*/-1, @@ -333,18 +402,57 @@ bool LoadJpegXlImage(const gchar *const filename, gint32 *const image_id) { const Babl *source_format = babl_format(babl_format_str.c_str()); babl_process(babl_fish(source_format, destination_format), - pixels_buffer_1, pixels_buffer_2, info.xsize * info.ysize); + pixels_buffer_1, pixels_buffer_2, xsize * ysize); - gegl_buffer_set(buffer, GEGL_RECTANGLE(0, 0, info.xsize, info.ysize), 0, - nullptr, pixels_buffer_2, GEGL_AUTO_ROWSTRIDE); + gegl_buffer_set(buffer, GEGL_RECTANGLE(0, 0, xsize, ysize), 0, nullptr, + pixels_buffer_2, GEGL_AUTO_ROWSTRIDE); + gimp_item_transform_translate(layer, crop_x0, crop_y0); g_clear_object(&buffer); + g_free(pixels_buffer_1); + g_free(pixels_buffer_2); + if (stop_processing) status = JXL_DEC_SUCCESS; + g_free(layer_name); + layer_idx++; + } else if (status == JXL_DEC_FRAME) { + JxlFrameHeader frame_header; + if (JxlDecoderGetFrameHeader(dec.get(), &frame_header) != + JXL_DEC_SUCCESS) { + g_printerr(LOAD_PROC " Error: JxlDecoderSetImageOutBuffer failed\n"); + return false; + } + xsize = frame_header.layer_info.xsize; + ysize = frame_header.layer_info.ysize; + crop_x0 = frame_header.layer_info.crop_x0; + crop_y0 = frame_header.layer_info.crop_y0; + frame_duration = frame_header.duration; + blend_mode = frame_header.layer_info.blend_info.blendmode; + if (blend_mode != JXL_BLEND_BLEND && blend_mode != JXL_BLEND_REPLACE) { + g_printerr( + LOAD_PROC + " Warning: JxlDecoderGetFrameHeader: Unhandled blend mode: %d\n", + blend_mode); + } + if ((frame_name_len = frame_header.name_length) > 0) { + frame_name = (char *)realloc(frame_name, frame_name_len); + if (JXL_DEC_SUCCESS != + JxlDecoderGetFrameName(dec.get(), frame_name, frame_name_len)) { + g_printerr(LOAD_PROC "Error: JxlDecoderGetFrameName failed"); + return false; + }; + } } else if (status == JXL_DEC_SUCCESS) { // All decoding successfully finished. // It's not required to call JxlDecoderReleaseInput(dec.get()) // since the decoder will be destroyed. break; - } else if (status == JXL_DEC_NEED_MORE_INPUT) { + } else if (status == JXL_DEC_NEED_MORE_INPUT || + status == JXL_DEC_FRAME_PROGRESSION) { + stop_processing = status != JXL_DEC_FRAME_PROGRESSION; + if (JxlDecoderFlushImage(dec.get()) == JXL_DEC_SUCCESS) { + status = JXL_DEC_FULL_IMAGE; + continue; + } g_printerr(LOAD_PROC " Error: Already provided all input\n"); return false; } else if (status == JXL_DEC_ERROR) { diff --git a/plugins/gimp/file-jxl-load.h b/plugins/gimp/file-jxl-load.h index c9ca6d9..ef5b92f 100644 --- a/plugins/gimp/file-jxl-load.h +++ b/plugins/gimp/file-jxl-load.h @@ -6,8 +6,6 @@ #ifndef PLUGINS_GIMP_FILE_JXL_LOAD_H_ #define PLUGINS_GIMP_FILE_JXL_LOAD_H_ -#include "jxl/decode.h" -#include "jxl/decode_cxx.h" #include "plugins/gimp/common.h" namespace jxl { diff --git a/plugins/gimp/file-jxl-save.cc b/plugins/gimp/file-jxl-save.cc index 5eb1412..45aaa1f 100644 --- a/plugins/gimp/file-jxl-save.cc +++ b/plugins/gimp/file-jxl-save.cc @@ -5,7 +5,11 @@ #include "plugins/gimp/file-jxl-save.h" +#include <jxl/encode.h> +#include <jxl/encode_cxx.h> + #include <cmath> +#include <utility> #include "gobject/gsignal.h" @@ -116,8 +120,7 @@ bool JpegXlSaveGui::GuiOnChangeQuality(GtkAdjustment* adj_qual, g_clear_signal_handler(&self->handle_toggle_lossless, self->toggle_lossless); GtkAdjustment* adj_dist = self->entry_distance; - jxl_save_opts.quality = gtk_adjustment_get_value(adj_qual); - jxl_save_opts.UpdateDistance(); + jxl_save_opts.SetQuality(gtk_adjustment_get_value(adj_qual)); gtk_adjustment_set_value(adj_dist, jxl_save_opts.distance); self->handle_toggle_lossless = g_signal_connect( @@ -140,8 +143,7 @@ bool JpegXlSaveGui::GuiOnChangeDistance(GtkAdjustment* adj_dist, g_clear_signal_handler(&self->handle_entry_quality, self->entry_quality); g_clear_signal_handler(&self->handle_toggle_lossless, self->toggle_lossless); - jxl_save_opts.distance = gtk_adjustment_get_value(adj_dist); - jxl_save_opts.UpdateQuality(); + jxl_save_opts.SetDistance(gtk_adjustment_get_value(adj_dist)); gtk_adjustment_set_value(adj_qual, jxl_save_opts.quality); if (!(jxl_save_opts.distance < 0.001)) { @@ -356,8 +358,6 @@ bool JpegXlSaveGui::SaveDialog() { gtk_widget_show(separator); // Advanced Settings Frame - std::vector<GtkWidget*> advanced_opts; - frame_advanced = gtk_frame_new("Advanced Settings"); gimp_help_set_help_data(frame_advanced, "Some advanced settings may produce malformed files.", @@ -519,8 +519,8 @@ bool JpegXlSaveOpts::UpdateQuality() { if (distance < 0.1) { qual = 100; - } else if (distance > 6.56) { - qual = 30 - 5 * log(abs(6.25 * distance - 40)) / log(2.5); + } else if (distance > 6.4) { + qual = -5.0 / 53.0 * sqrt(6360.0 * distance - 39975.0) + 1725.0 / 53.0; lossless = false; } else { qual = 100 - (distance - 0.1) / 0.09; @@ -539,15 +539,10 @@ bool JpegXlSaveOpts::UpdateQuality() { } bool JpegXlSaveOpts::UpdateDistance() { - float dist; - if (quality >= 30) { - dist = 0.1 + (100 - quality) * 0.09; - } else { - dist = 6.4 + pow(2.5, (30 - quality) / 5.0) / 6.25; - } + float dist = JxlEncoderDistanceFromQuality(quality); - if (dist > 15) { - distance = 15; + if (dist > 25) { + distance = 25; } else { distance = dist; } @@ -602,12 +597,12 @@ bool JpegXlSaveOpts::UpdateBablFormat() { } bool JpegXlSaveOpts::SetBablModel(std::string model) { - babl_model_str = model; + babl_model_str = std::move(model); return UpdateBablFormat(); } bool JpegXlSaveOpts::SetBablType(std::string type) { - babl_type_str = type; + babl_type_str = std::move(type); return UpdateBablFormat(); } @@ -727,6 +722,15 @@ bool SaveJpegXlImage(const gint32 image_id, const gint32 drawable_id, return false; } + // this sets some basic_info properties + jxl_save_opts.SetModel(jxl_save_opts.is_linear); + + if (JXL_ENC_SUCCESS != + JxlEncoderSetBasicInfo(enc.get(), &jxl_save_opts.basic_info)) { + g_printerr(SAVE_PROC " Error: JxlEncoderSetBasicInfo failed\n"); + return false; + } + // try to use ICC profile if (!icc.empty() && !jxl_save_opts.is_gray) { if (JXL_ENC_SUCCESS == @@ -785,15 +789,6 @@ bool SaveJpegXlImage(const gint32 image_id, const gint32 drawable_id, JxlEncoderSetFrameDistance(frame_settings, jxl_save_opts.distance); } - // this sets some basic_info properties - jxl_save_opts.SetModel(jxl_save_opts.is_linear); - - if (JXL_ENC_SUCCESS != - JxlEncoderSetBasicInfo(enc.get(), &jxl_save_opts.basic_info)) { - g_printerr(SAVE_PROC " Error: JxlEncoderSetBasicInfo failed\n"); - return false; - } - // convert precision and colorspace if (jxl_save_opts.is_linear && jxl_save_opts.basic_info.bits_per_sample < 32) { @@ -832,11 +827,7 @@ bool SaveJpegXlImage(const gint32 image_id, const gint32 drawable_id, g_clear_object(&buffer); // use babl to fix gamma mismatch issues - if (jxl_save_opts.icc_attached) { - jxl_save_opts.SetModel(jxl_save_opts.is_linear); - } else { - jxl_save_opts.SetModel(!jxl_save_opts.is_linear); - } + jxl_save_opts.SetModel(jxl_save_opts.is_linear); jxl_save_opts.pixel_format.data_type = JXL_TYPE_FLOAT; jxl_save_opts.SetBablType("float"); const Babl* destination_format = diff --git a/plugins/gimp/file-jxl-save.h b/plugins/gimp/file-jxl-save.h index 9dfa45c..c9d0e80 100644 --- a/plugins/gimp/file-jxl-save.h +++ b/plugins/gimp/file-jxl-save.h @@ -6,8 +6,6 @@ #ifndef PLUGINS_GIMP_FILE_JXL_SAVE_H_ #define PLUGINS_GIMP_FILE_JXL_SAVE_H_ -#include "jxl/encode.h" -#include "jxl/encode_cxx.h" #include "plugins/gimp/common.h" namespace jxl { |