[gimp] plug-ins: fix #5960 Gimp loads 16 bit DDS images with luminosity as 8 bit.



commit fe228a6f6f6b4b1fef1dc1fb5e5cf409fa6a36be
Author: Jacob Boerema <jgboerema gmail com>
Date:   Mon Apr 26 17:34:18 2021 -0400

    plug-ins: fix #5960 Gimp loads 16 bit DDS images with luminosity as 8 bit.
    
    So far all dds images were loaded as 8 bit per channel which makes
    sense for most but not all dds formats.
    
    This commit implements loading in 16 bit for "L16" - a 16 bit
    luminance channel.
    
    In addition to that we improve security a bit  by not assuming
    that L16 is the only left over case but instead explicitly
    checking the correct value of rmask for L16.
    
    For other cases we now set an error with enough details
    to identify the type of DDS image that needs extra
    handling.

 plug-ins/file-dds/ddsread.c | 41 ++++++++++++++++++++++++++++++++++-------
 1 file changed, 34 insertions(+), 7 deletions(-)
---
diff --git a/plug-ins/file-dds/ddsread.c b/plug-ins/file-dds/ddsread.c
index 2cd07d9d71..8acf616ee7 100644
--- a/plug-ins/file-dds/ddsread.c
+++ b/plug-ins/file-dds/ddsread.c
@@ -57,6 +57,7 @@ typedef struct
   guchar  rbits, gbits, bbits, abits;
   guint   rmask, gmask, bmask, amask;
   guint   bpp, gimp_bpp;
+  guint   gimp_bps;         /* bytes per sample */
   gint    tile_height;
   guchar *palette;
 } dds_load_info_t;
@@ -129,6 +130,7 @@ read_dds (GFile          *file,
   dds_load_info_t    d;
   GList             *layers;
   GimpImageBaseType  type;
+  GimpPrecision      precision;
   gboolean           read_mipmaps;
   gboolean           decode_images;
   gint               i, j;
@@ -215,6 +217,7 @@ read_dds (GFile          *file,
         hdr.pixelfmt.flags |= DDPF_ALPHAPIXELS;
     }
 
+  d.gimp_bps = 1; /* Most formats will be converted to 1 byte per sample */
   if (hdr.pixelfmt.flags & DDPF_FOURCC)
     {
       switch (GETL32 (hdr.pixelfmt.fourcc))
@@ -262,11 +265,22 @@ read_dds (GFile          *file,
 
               type = GIMP_RGB;
             }
-          else /* L16 */
+          else if (hdr.pixelfmt.rmask == 0xffff) /* L16 */
             {
-              d.gimp_bpp = 1;
+              d.gimp_bpp = 2;
+              d.gimp_bps = 2;
               type = GIMP_GRAY;
             }
+          else
+            {
+              g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+                           "Unsupported uncompressed dds format: "
+                           "bpp: %d, Rmask: %x, Gmask: %x, Bmask: %x, Amask: %x",
+                           hdr.pixelfmt.bpp,
+                           hdr.pixelfmt.rmask, hdr.pixelfmt.gmask,
+                           hdr.pixelfmt.bmask, hdr.pixelfmt.amask);
+              return GIMP_PDB_EXECUTION_ERROR;
+            }
         }
       else
         {
@@ -297,7 +311,16 @@ read_dds (GFile          *file,
         }
     }
 
-  image = gimp_image_new (hdr.width, hdr.height, type);
+  if (d.gimp_bps == 2)
+    {
+      precision = GIMP_PRECISION_U16_NON_LINEAR;
+    }
+  else
+    {
+      precision = GIMP_PRECISION_U8_NON_LINEAR;
+    }
+
+  image = gimp_image_new_with_precision (hdr.width, hdr.height, type, precision);
 
   if (! image)
     {
@@ -1009,10 +1032,10 @@ load_layer (FILE             *fp,
           type = (hdr->pixelfmt.amask == 0x8000) ? GIMP_RGBA_IMAGE : GIMP_RGB_IMAGE;
           bablfmt = (hdr->pixelfmt.amask == 0x8000) ? babl_format ("R'G'B'A u8") : babl_format ("R'G'B' u8");
         }
-      else /* L16 */
+      else if (hdr->pixelfmt.rmask == 0xffff) /* L16 */
         {
           type = GIMP_GRAY_IMAGE;
-          bablfmt = babl_format ("Y' u8");
+          bablfmt = babl_format ("Y' u16");
         }
       break;
     case 3: type = GIMP_RGB_IMAGE;  bablfmt = babl_format ("R'G'B' u8");  break;
@@ -1179,8 +1202,12 @@ load_layer (FILE             *fp,
                             (pixel >> d->ashift << (8 - d->abits) & d->amask) * 255 / d->amask;
                         }
                     }
-                  else /* L16 */
-                    pixels[pos] = (guchar) (255 * ((float)(pixel & 0xffff) / 65535.0f));
+                  else if (hdr->pixelfmt.rmask == 0xffff) /* L16 */
+                    {
+                      guint16 *pixels16 = (guint16 *) &pixels[pos];
+
+                      *pixels16 = (guint16) (pixel & 0xffff);
+                    }
                 }
               else
                 {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]