[Bf-blender-cvs] [8960c6e0601] master: IMBUF: Faster JPEG Thumbnails

Harley Acheson noreply at git.blender.org
Thu May 5 01:57:31 CEST 2022


Commit: 8960c6e06017a3c3fc90c5745433009c00e64c1b
Author: Harley Acheson
Date:   Wed May 4 16:55:59 2022 -0700
Branches: master
https://developer.blender.org/rB8960c6e06017a3c3fc90c5745433009c00e64c1b

IMBUF: Faster JPEG Thumbnails

Make preview thumbnails of JPEG files in less time and with less RAM.

See D14727 for more details.

Differential Revision: https://developer.blender.org/D14727

Reviewed by Brecht Van Lommel

===================================================================

M	source/blender/imbuf/IMB_imbuf.h
M	source/blender/imbuf/intern/IMB_filetype.h
M	source/blender/imbuf/intern/filetype.c
M	source/blender/imbuf/intern/jpeg.c
M	source/blender/imbuf/intern/readimage.c
M	source/blender/imbuf/intern/thumbs.c

===================================================================

diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index 0390df06052..8796c99629e 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -107,6 +107,14 @@ struct ImBuf *IMB_testiffname(const char *filepath, int flags);
  */
 struct ImBuf *IMB_loadiffname(const char *filepath, int flags, char colorspace[IM_MAX_SPACE]);
 
+/**
+ *
+ * \attention Defined in readimage.c
+ */
+struct ImBuf *IMB_thumb_load_image(const char *filepath,
+                                   const size_t max_thumb_size,
+                                   char colorspace[IM_MAX_SPACE]);
+
 /**
  *
  * \attention Defined in allocimbuf.c
diff --git a/source/blender/imbuf/intern/IMB_filetype.h b/source/blender/imbuf/intern/IMB_filetype.h
index 31f8b3a9505..bcca6f9fd85 100644
--- a/source/blender/imbuf/intern/IMB_filetype.h
+++ b/source/blender/imbuf/intern/IMB_filetype.h
@@ -36,6 +36,15 @@ typedef struct ImFileType {
                         char colorspace[IM_MAX_SPACE]);
   /** Load an image from a file. */
   struct ImBuf *(*load_filepath)(const char *filepath, int flags, char colorspace[IM_MAX_SPACE]);
+  /** Load/Create a thumbnail image from a filepath. `max_thumb_size` is maximum size of either
+   * dimension, so can return less on either or both. Should, if possible and performant, return
+   * dimensions of the full-size image in width_r & height_r. */
+  struct ImBuf *(*load_filepath_thumbnail)(const char *filepath,
+                                           const int flags,
+                                           const size_t max_thumb_size,
+                                           size_t *width_r,
+                                           size_t *height_r,
+                                           char colorspace[IM_MAX_SPACE]);
   /** Save to a file (or memory if #IB_mem is set in `flags` and the format supports it). */
   bool (*save)(struct ImBuf *ibuf, const char *filepath, int flags);
   void (*load_tile)(struct ImBuf *ibuf,
@@ -143,6 +152,12 @@ struct ImBuf *imb_load_jpeg(const unsigned char *buffer,
                             size_t size,
                             int flags,
                             char colorspace[IM_MAX_SPACE]);
+struct ImBuf *imb_thumbnail_jpeg(const char *filepath,
+                                 const int flags,
+                                 const size_t max_thumb_size,
+                                 size_t *width_r,
+                                 size_t *height_r,
+                                 char colorspace[IM_MAX_SPACE]);
 
 /** \} */
 
diff --git a/source/blender/imbuf/intern/filetype.c b/source/blender/imbuf/intern/filetype.c
index 548bc9e120c..74042ef75be 100644
--- a/source/blender/imbuf/intern/filetype.c
+++ b/source/blender/imbuf/intern/filetype.c
@@ -33,6 +33,7 @@ const ImFileType IMB_FILE_TYPES[] = {
         .is_a = imb_is_a_jpeg,
         .load = imb_load_jpeg,
         .load_filepath = NULL,
+        .load_filepath_thumbnail = imb_thumbnail_jpeg,
         .save = imb_savejpeg,
         .load_tile = NULL,
         .flag = 0,
@@ -45,6 +46,7 @@ const ImFileType IMB_FILE_TYPES[] = {
         .is_a = imb_is_a_png,
         .load = imb_loadpng,
         .load_filepath = NULL,
+        .load_filepath_thumbnail = NULL,
         .save = imb_savepng,
         .load_tile = NULL,
         .flag = 0,
@@ -57,6 +59,7 @@ const ImFileType IMB_FILE_TYPES[] = {
         .is_a = imb_is_a_bmp,
         .load = imb_bmp_decode,
         .load_filepath = NULL,
+        .load_filepath_thumbnail = NULL,
         .save = imb_savebmp,
         .load_tile = NULL,
         .flag = 0,
@@ -69,6 +72,7 @@ const ImFileType IMB_FILE_TYPES[] = {
         .is_a = imb_is_a_targa,
         .load = imb_loadtarga,
         .load_filepath = NULL,
+        .load_filepath_thumbnail = NULL,
         .save = imb_savetarga,
         .load_tile = NULL,
         .flag = 0,
@@ -81,6 +85,7 @@ const ImFileType IMB_FILE_TYPES[] = {
         .is_a = imb_is_a_iris,
         .load = imb_loadiris,
         .load_filepath = NULL,
+        .load_filepath_thumbnail = NULL,
         .save = imb_saveiris,
         .load_tile = NULL,
         .flag = 0,
@@ -94,6 +99,7 @@ const ImFileType IMB_FILE_TYPES[] = {
         .is_a = imb_is_a_dpx,
         .load = imb_load_dpx,
         .load_filepath = NULL,
+        .load_filepath_thumbnail = NULL,
         .save = imb_save_dpx,
         .load_tile = NULL,
         .flag = IM_FTYPE_FLOAT,
@@ -106,6 +112,7 @@ const ImFileType IMB_FILE_TYPES[] = {
         .is_a = imb_is_a_cineon,
         .load = imb_load_cineon,
         .load_filepath = NULL,
+        .load_filepath_thumbnail = NULL,
         .save = imb_save_cineon,
         .load_tile = NULL,
         .flag = IM_FTYPE_FLOAT,
@@ -120,6 +127,7 @@ const ImFileType IMB_FILE_TYPES[] = {
         .is_a = imb_is_a_tiff,
         .load = imb_loadtiff,
         .load_filepath = NULL,
+        .load_filepath_thumbnail = NULL,
         .save = imb_savetiff,
         .load_tile = imb_loadtiletiff,
         .flag = 0,
@@ -134,6 +142,7 @@ const ImFileType IMB_FILE_TYPES[] = {
         .is_a = imb_is_a_hdr,
         .load = imb_loadhdr,
         .load_filepath = NULL,
+        .load_filepath_thumbnail = NULL,
         .save = imb_savehdr,
         .load_tile = NULL,
         .flag = IM_FTYPE_FLOAT,
@@ -148,6 +157,7 @@ const ImFileType IMB_FILE_TYPES[] = {
         .is_a = imb_is_a_openexr,
         .load = imb_load_openexr,
         .load_filepath = NULL,
+        .load_filepath_thumbnail = NULL,
         .save = imb_save_openexr,
         .load_tile = NULL,
         .flag = IM_FTYPE_FLOAT,
@@ -162,6 +172,7 @@ const ImFileType IMB_FILE_TYPES[] = {
         .is_a = imb_is_a_jp2,
         .load = imb_load_jp2,
         .load_filepath = NULL,
+        .load_filepath_thumbnail = NULL,
         .save = imb_save_jp2,
         .load_tile = NULL,
         .flag = IM_FTYPE_FLOAT,
@@ -176,6 +187,7 @@ const ImFileType IMB_FILE_TYPES[] = {
         .is_a = imb_is_a_dds,
         .load = imb_load_dds,
         .load_filepath = NULL,
+        .load_filepath_thumbnail = NULL,
         .save = NULL,
         .load_tile = NULL,
         .flag = 0,
@@ -190,6 +202,7 @@ const ImFileType IMB_FILE_TYPES[] = {
         .is_a = imb_is_a_photoshop,
         .load = NULL,
         .load_filepath = imb_load_photoshop,
+        .load_filepath_thumbnail = NULL,
         .save = NULL,
         .load_tile = NULL,
         .flag = IM_FTYPE_FLOAT,
@@ -204,6 +217,7 @@ const ImFileType IMB_FILE_TYPES[] = {
         .is_a = imb_is_a_webp,
         .load = imb_loadwebp,
         .load_filepath = NULL,
+        .load_filepath_thumbnail = NULL,
         .save = imb_savewebp,
         .load_tile = NULL,
         .flag = 0,
@@ -211,7 +225,7 @@ const ImFileType IMB_FILE_TYPES[] = {
         .default_save_role = COLOR_ROLE_DEFAULT_BYTE,
     },
 #endif
-    {NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0},
+    {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0},
 };
 
 const ImFileType *IMB_FILE_TYPES_LAST = &IMB_FILE_TYPES[ARRAY_SIZE(IMB_FILE_TYPES) - 1];
diff --git a/source/blender/imbuf/intern/jpeg.c b/source/blender/imbuf/intern/jpeg.c
index 6fb1fb52153..0ec4e5a3ba8 100644
--- a/source/blender/imbuf/intern/jpeg.c
+++ b/source/blender/imbuf/intern/jpeg.c
@@ -39,7 +39,11 @@ static void skip_input_data(j_decompress_ptr cinfo, long num_bytes);
 static void term_source(j_decompress_ptr cinfo);
 static void memory_source(j_decompress_ptr cinfo, const unsigned char *buffer, size_t size);
 static boolean handle_app1(j_decompress_ptr cinfo);
-static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int flags);
+static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo,
+                                   int flags,
+                                   int max_size,
+                                   size_t *width_r,
+                                   size_t *height_r);
 
 static const uchar jpeg_default_quality = 75;
 static uchar ibuf_quality;
@@ -246,7 +250,11 @@ static boolean handle_app1(j_decompress_ptr cinfo)
   return true;
 }
 
-static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int flags)
+static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo,
+                                   int flags,
+                                   int max_size,
+                                   size_t *width_r,
+                                   size_t *height_r)
 {
   JSAMPARRAY row_pointer;
   JSAMPLE *buffer = NULL;
@@ -264,16 +272,34 @@ static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int fla
   jpeg_save_markers(cinfo, JPEG_COM, 0xffff);
 
   if (jpeg_read_header(cinfo, false) == JPEG_HEADER_OK) {
-    x = cinfo->image_width;
-    y = cinfo->image_height;
     depth = cinfo->num_components;
 
     if (cinfo->jpeg_color_space == JCS_YCCK) {
       cinfo->out_color_space = JCS_CMYK;
     }
 
+    if (width_r) {
+      *width_r = cinfo->image_width;
+    }
+    if (height_r) {
+      *height_r = cinfo->image_height;
+    }
+
+    if (max_size > 0) {
+      /* libjpeg can more quickly decompress while scaling down to 1/2, 1/4, 1/8,
+       * while libjpeg-turbo can also do 3/8, 5/8, etc. But max is 1/8. */
+      float scale = (float)max_size / MAX2(cinfo->image_width, cinfo->image_height);
+      cinfo->scale_denom = 8;
+      cinfo->scale_num = MAX2(1, MIN2(8, ceill(scale * (float)cinfo->scale_denom)));
+      cinfo->dct_method = JDCT_FASTEST;
+      cinfo->dither_mode = JDITHER_ORDERED;
+    }
+
     jpeg_start_decompress(cinfo);
 
+    x = cinfo->output_width;
+    y = cinfo->output_height;
+
     if (flags & IB_test) {
       jpeg_abort_decompress(cinfo);
       ibuf = IMB_allocImBuf(x, y, 8 * depth, 0);
@@ -449,11 +475,92 @@ ImBuf *imb_load_jpeg(const unsigned char *buffer,
   jpeg_create_decompress(cinfo);
   memory_source(cinfo, buffer, size);
 
-  ibuf = ibJpegImageFromCinfo(cinfo, flags);
+  ibuf = ibJpegImageFromCinfo(cinfo, flags, -1, NULL, NULL);
+
+  return ibuf;
+}
+
+/* Defines for JPEG Header markers and segment size. */
+#define JPEG_MARKER_MSB (0xFF)
+#define JPEG_MARKER_SOI (0xD8)
+#define JPEG_MARKER_APP1 (0xE1)
+#define JPEG_APP1_MAX (1 <

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list