changeset 362:fbd67cad13b6

Handle 16 bit images better (by Eugeniy Mikhailov)
author hauberg
date Fri, 20 Mar 2009 06:38:31 +0000
parents f98f6c57bd17
children 7fda62a0897b
files src/pngread.cc
diffstat 1 files changed, 64 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/src/pngread.cc
+++ b/src/pngread.cc
@@ -84,13 +84,14 @@
        ((pic->color_type == PNG_COLOR_TYPE_PALETTE) && (pic->bit_depth == 1)) )
       dim(2) = 1;
 
-  if (pic->bit_depth > 1 && pic->bit_depth < 8)
-      pic->bit_depth = 8;
+  if (pic->bit_depth > 1 && pic->bit_depth < 8) 
+      pic->bit_depth = 8; //this should never happen according to load_canvas code
 
   int isAlfaChannelPresent = 0;
   if ( pic->color_type & PNG_COLOR_MASK_ALPHA) 
  	isAlfaChannelPresent=1; 
 
+
   NDArray out(dim);
   
   dim.resize(2);
@@ -98,6 +99,8 @@
    
   Array<int> coord = Array<int> (3);
   
+  int major_byte, minor_byte,row_pxl_position;
+  /* calculate the number of color channels (including alpha) per pixel */
   int ElementsPerPixel=out.dims()(2)+isAlfaChannelPresent;
   for (unsigned long j=0; j < pic->height; j++) {
       coord(0) = j;
@@ -106,13 +109,42 @@
 
 	  for (int c = 0; c < out.dims()(2); c++) {
 	      coord(2) = c;
-	      out(coord) = pic->row_pointers[j][i*ElementsPerPixel+c];
+	      switch(pic->bit_depth) {
+		      case 8:
+				  row_pxl_position=(i*ElementsPerPixel+c);
+			      out(coord) = pic->row_pointers[j][row_pxl_position];
+			      break;
+		      case 16:
+			      // converting big endian
+				  row_pxl_position=2*(i*ElementsPerPixel+c);
+			      major_byte=pic->row_pointers[j][row_pxl_position];
+			      minor_byte=pic->row_pointers[j][row_pxl_position+1] ;
+			      out(coord) = major_byte*256+minor_byte;
+			      break;      
+		      default:
+			      printf("do not know how to handle bit depth of %d\n",pic->bit_depth);
+	      }
 	  }
-	  if (isAlfaChannelPresent)
-	      alpha(j,i) = pic->row_pointers[j][i*ElementsPerPixel+(ElementsPerPixel-1)];
-	  else
-	      alpha(j,i) = 1;
-      }
+	  if (isAlfaChannelPresent) { // it always should according to load canvas code
+		  switch(pic->bit_depth) {
+			  case 8:
+				  row_pxl_position=(i*ElementsPerPixel+ElementsPerPixel-1);
+				  alpha(j,i) = pic->row_pointers[j][row_pxl_position];
+				  break;
+			  case 16:
+				  // converting big endian
+				  row_pxl_position=2*(i*ElementsPerPixel+ElementsPerPixel-1);
+				  major_byte = pic->row_pointers[j][row_pxl_position];
+				  minor_byte = pic->row_pointers[j][row_pxl_position+1];
+				  alpha(j,i) = major_byte*256+minor_byte;
+				  break;      
+			  default:
+				  printf("do not know how to handle bit depth of %d\n",pic->bit_depth);
+		  }
+	  } else {
+		  alpha(j,i) = 255;
+	  }
+	  }
   }
   out = out.squeeze();
 
@@ -197,7 +229,9 @@
       png_set_palette_to_rgb(png_ptr);
   }
   if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
-      png_set_gray_1_2_4_to_8(png_ptr);
+      png_set_gray_1_2_4_to_8(png_ptr); // this function deprecated need to be redone
+      bit_depth=8;
+      info_ptr->bit_depth=bit_depth;
   }
   if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { //add alpha
       png_set_tRNS_to_alpha(png_ptr);
@@ -206,21 +240,35 @@
   // Always transform image to RGB
   if (color_type == PNG_COLOR_TYPE_GRAY 
       || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) 
+  {
       png_set_gray_to_rgb(png_ptr);
+      color_type= (color_type | PNG_COLOR_MASK_COLOR);
+      info_ptr->color_type=color_type;
+  }
    
   // If no alpha layer is present, create one
-  if (color_type == PNG_COLOR_TYPE_GRAY
-      || color_type == PNG_COLOR_TYPE_RGB)
-     png_set_add_alpha(png_ptr, 0xff, PNG_FILLER_AFTER);
+  if (!(color_type & PNG_COLOR_MASK_ALPHA)) 
+  {
+      png_set_add_alpha(png_ptr, 0xff, PNG_FILLER_AFTER);
+      color_type= (color_type | PNG_COLOR_MASK_ALPHA);
+      info_ptr->color_type=color_type;
+  }
 
   if (bit_depth < 8) {
       png_set_packing(png_ptr);
+      bit_depth=8;
+      info_ptr->bit_depth=bit_depth;
   }
-  
+ 
+  // Hey! Our signal could be small and in the lower bits, 
+  // leave our data alone and do not decrease accuracy
+  // 16 -> 8 bits commented out
   // For now, use 8-bit only
-  if (bit_depth == 16) {
-      png_set_strip_16(png_ptr);
-  }
+  //if (bit_depth == 16) {
+      //png_set_strip_16(png_ptr);
+      //bit_depth=8;
+      //info_ptr->bit_depth=bit_depth;
+  //}
    
   png_read_update_info(png_ptr,info_ptr);