Viktor Sokolov 2 mesi fa
parent
commit
071ef4a12d
1 ha cambiato i file con 18 aggiunte e 7 eliminazioni
  1. 18 7
      vips/bmpload.c

+ 18 - 7
vips/bmpload.c

@@ -29,7 +29,8 @@ typedef struct _VipsForeignLoadBmp {
 
   uint32_t num_colors;
 
-  int bands;
+  int bands;           // target image bands
+  int bytes_per_pixel; // source image bytes per pixel (not used when bpp<8)
 
   bool top_down; // true if image is vertically reversed
   bool rle;      // true if image is compressed with RLE
@@ -210,7 +211,8 @@ vips_foreign_load_bmp_header(VipsForeignLoad *load)
   // Let's determine if the image has an alpha channel
   bool has_alpha = FALSE;
 
-  // If the info header is V4 or V5, check for alpha channel explicitly
+  // If the info header is V4 or V5, check for alpha channel mask explicitly.
+  // If it's non-zero, then the target image should have an alpha channel.
   if (info_header_len > BMP_BITMAP_INFO_HEADER_LEN) {
     has_alpha = GUINT32_FROM_LE(*(uint32_t *) (info_header + 48)) != 0;
   }
@@ -222,6 +224,9 @@ vips_foreign_load_bmp_header(VipsForeignLoad *load)
     bands = 4;
   }
 
+  // Source image bytes per pixel. It does not depend on the alpha mask, just on the bpp.
+  int bytes_per_pixel = bpp >= 8 ? bpp / 8 : 1; // bytes per pixel in the source image
+
   if (height < 0) {
     height = -height;
     top_down = TRUE;
@@ -339,6 +344,7 @@ vips_foreign_load_bmp_header(VipsForeignLoad *load)
   bmp->bmask = bmask;
   bmp->amask = amask;
 
+  bmp->bytes_per_pixel = bytes_per_pixel;
   bmp->y_pos = 0;
 
   bmp->dx = 0; // In sequential access this indicates that we need to skip n lines
@@ -367,7 +373,7 @@ static int
 vips_foreign_load_bmp_24_32_generate_strip(VipsRect *r, VipsRegion *out_region, VipsForeignLoadBmp *bmp)
 {
   // Align the row size to 4 bytes, as BMP rows are 4-byte aligned.
-  int row_size = (bmp->bands * r->width + 3) & (~3);
+  int row_size = (bmp->bytes_per_pixel * r->width + 3) & (~3);
 
   VipsPel *src;
   VipsPel *dest;
@@ -388,11 +394,16 @@ vips_foreign_load_bmp_24_32_generate_strip(VipsRect *r, VipsRegion *out_region,
 
       // if the image has alpha channel, copy it too
       if (bmp->bands == 4) {
-        dest[3] = src[3]; // A
+        if (bmp->bytes_per_pixel == 4) {
+          dest[3] = src[3]; // A
+        }
+        else {
+          dest[3] = 0xFF;
+        }
       }
 
       dest += bmp->bands;
-      src += bmp->bands;
+      src += bmp->bytes_per_pixel;
     }
 
     bmp->y_pos += 1;
@@ -408,7 +419,7 @@ static int
 vips_foreign_load_bmp_16_generate_strip(VipsRect *r, VipsRegion *out_region, VipsForeignLoadBmp *bmp)
 {
   // Align the row size to 4 bytes, as BMP rows are 4-byte aligned, 16 bpp = 2 bytes per pixel
-  int row_size = (2 * r->width + 3) & (~3);
+  int row_size = (bmp->bytes_per_pixel * r->width + 3) & (~3);
 
   VipsPel *src;
   VipsPel *dest;
@@ -431,7 +442,7 @@ vips_foreign_load_bmp_16_generate_strip(VipsRect *r, VipsRegion *out_region, Vip
       dest[2] = (uint8_t) (pixel & bmp->bmask) << 3;
 
       dest += bmp->bands;
-      src += 2; // 2 bytes per pixel for 16 bpp
+      src += bmp->bytes_per_pixel; // 2 bytes per pixel for 16 bpp
     }
 
     bmp->y_pos += 1;