Exemplo n.º 1
0
Arquivo: png.cpp Projeto: 2asoft/xray
/* Read an PNG file, returning the storage where it's located */
BitmapStorage *
BitmapIO_PNG::ReadPNGFile(BitmapInfo *fbi, BitmapManager *manager) 
{
    BitmapStorage *storage = NULL;
	unsigned char magic_numbers[8];
    
    if((istream=_tfopen(fbi->Name(), _T("rb")))==NULL)
		return NULL;

	// grab the first 8 bytes for testing
	if (fread(magic_numbers, 1, 8, istream) != 8) {
		fclose(istream);
		return NULL;
	} else 
		rewind(istream);

	// Make sure we're a png file
	if (!png_check_sig(magic_numbers, 8)) {
		fclose(istream);
		return NULL;
	}

    png = png_create_read_struct (PNG_VERSION, (void *) this, error_func, warning_func);
    if (setjmp(png->jmpbuf)) {
        if (info)
		    for (png_uint_32 i = 0; i < info->height; i++)
    			if (row_pointers[i]) free(row_pointers[i]);
		if (row_pointers) {
			free(row_pointers);
			row_pointers = NULL;
		}

		if (storage) {
			delete storage;
			storage = NULL;
		}

        fclose(istream);
        png_destroy_read_struct (&png, &info, NULL);
        return NULL;
    }
    info = png_create_info_struct(png);

    png_init_io(png, istream);
	png_read_info(png, info);

    fbi->SetWidth((WORD)info->width);
    fbi->SetHeight((WORD)info->height);
	if (info->valid & PNG_INFO_gAMA)
		fbi->SetGamma(info->gamma);
//	else
//		fbi->SetGamma (1.0f);
	if (info->valid & PNG_INFO_pHYs)
		fbi->SetAspect((float)info->x_pixels_per_unit / (float)info->y_pixels_per_unit);
	else
		fbi->SetAspect(1.0f);
    fbi->SetFlags(0);

	/* expand grayscale images to the full 8 bits */
	/* expand images with transparency to full alpha channels */
	/* I'm going to ignore lineart and just expand it to 8 bits */
	if ((info->color_type == PNG_COLOR_TYPE_PALETTE && info->bit_depth < 8) ||
		(info->color_type == PNG_COLOR_TYPE_GRAY && info->bit_depth < 8) ||
		(info->valid & PNG_INFO_tRNS))
		png_set_expand(png);

	int number_passes = 1;

	if (info->interlace_type)
		number_passes = png_set_interlace_handling(png);

	if (info->bit_depth == 16)
		png_set_swap(png);

	png_read_update_info(png, info);
   
	int bmtype = BMM_NO_TYPE;

	if (info->bit_depth == 1) {
			bmtype = BMM_LINE_ART;
	} else {
		switch(info->color_type) {
		case PNG_COLOR_TYPE_PALETTE:
			bmtype = BMM_PALETTED;
			break;
		case PNG_COLOR_TYPE_RGB:
		case PNG_COLOR_TYPE_RGB_ALPHA:
			switch(info->bit_depth) {
			case 2:
			case 4:
				// Not allowed
				break;
			case 8:
				bmtype = BMM_TRUE_32;  // zero alpha for those that don't have it
				break;
			case 16:
				bmtype = BMM_TRUE_64;
				break;
			}
			break;
		case PNG_COLOR_TYPE_GRAY_ALPHA:
		case PNG_COLOR_TYPE_GRAY:
			switch(info->bit_depth) {
			case 2:
			case 4:
				// we should never get here because of the expand code so drop through
				break;
			case 8:
				bmtype = BMM_GRAY_8;
				break;
			case 16:
				bmtype = BMM_GRAY_16;
				break;
			}
			break;
		}
	}

	if (bmtype == BMM_NO_TYPE) {
		fclose(istream);
        png_destroy_read_struct (&png, &info, NULL);
		return NULL;
	}

    // Create a storage for this bitmap...
	// (we may need to special case GRAY since it has a problem with alpha)
	if(info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
		if (info->bit_depth == 16) {
			storage = BMMCreateStorage(manager, BMM_TRUE_64);
			fbi->SetType(BMM_TRUE_64);
		} else {
			storage = BMMCreateStorage(manager, BMM_TRUE_32);
			fbi->SetType(BMM_TRUE_32);
		}
	} else {
		storage = BMMCreateStorage(manager, bmtype);
		fbi->SetType(bmtype);
	}

	if (info->channels == 2 || info->channels == 4)
		fbi->SetFlags(MAP_HAS_ALPHA);


    if(storage == NULL) {
		fclose(istream);
        png_destroy_read_struct (&png, &info, NULL);
		return NULL;
	}

    if(storage->Allocate(fbi, manager, BMM_OPEN_R)==0) {
		delete storage;
		storage = NULL;
		fclose(istream);
        png_destroy_read_struct (&png, &info, NULL);
		return NULL;
	}

	row_pointers = (png_bytep *)malloc(info->height * sizeof(png_bytep));

	for (png_uint_32 i = 0; i < info->height; i++)
		row_pointers[i] = (png_bytep)malloc(info->rowbytes);

	// now read the image
	png_read_image(png, row_pointers);

	switch(bmtype) {
	case BMM_LINE_ART: {
		BMM_Color_64 *line64 = (BMM_Color_64 *) calloc(info->width, sizeof(BMM_Color_64));
		for (png_uint_32 iy = 0; iy < info->height; iy++) {
			BMM_Color_64 *l64 = line64;
			for (png_uint_32 ix = 0; ix < info->width; ix++,l64++) {
				png_uint_32 abyte = ix / 8;
				png_uint_32 abit = ix % 8;
				unsigned char tbyte = row_pointers[iy][abyte];
				unsigned char c = tbyte & (0x80 >> abit);
				l64->r = l64->g = l64->b = c ? 0xffff : 0;
				l64->a = 0;
			}
			storage->PutPixels(0, iy, info->width, line64);
		}
		free(line64);
		}
		break;
	case BMM_PALETTED: {
		if (info->bit_depth == 8) {
			for (png_uint_32 iy = 0; iy < info->height; iy++)
				storage->PutIndexPixels(0, iy, info->width, row_pointers[iy]);
		} else {
			unsigned char *pixels = (unsigned char *)calloc(info->width, sizeof(unsigned char));
			for (png_uint_32 iy = 0; iy < info->height; iy++) {
				// now fill a row of pixels
				unsigned char *inbyte = row_pointers[iy];
				for (png_uint_32 ix = 0; ix < info->width; inbyte++) {
					switch(info->bit_depth) {
					case 2:
						pixels[ix] = (*inbyte & 0xc0) >> 6;
						ix++; if (ix >= info->width) break;
						pixels[ix] = (*inbyte & 0x30) >> 4;
						ix++; if (ix >= info->width) break;
						pixels[ix] = (*inbyte & 0x0c) >> 2;
						ix++; if (ix >= info->width) break;
						pixels[ix] = *inbyte & 0x03;
						ix++;
						break;
					case 4:
						pixels[ix] = (*inbyte & 0xf0) >> 4;
						ix++; if (ix >= info->width) break;
						pixels[ix] = *inbyte & 0x0f;
						ix++;
						break;
					}
				}
				storage->PutIndexPixels(0, iy, info->width, pixels);
			}
			free(pixels);
		}
		// Now the palette
		PixelBuf48 palette(256);
		BMM_Color_48 *palout = palette.Ptr();
		for(int i = 0; i < png->num_palette; ++i,++palout) {
			palout->r = (USHORT)png->palette[i].red << 8;
			palout->g = (USHORT)png->palette[i].green << 8;
			palout->b = (USHORT)png->palette[i].blue << 8;
		}
		storage->SetPalette(0, png->num_palette, palette.Ptr());
		}
		break;
	case BMM_TRUE_32: {
		BMM_Color_64 *line64 = (BMM_Color_64 *) calloc(info->width, sizeof(BMM_Color_64));
		for (png_uint_32 iy = 0; iy < info->height; iy++) {
			BMM_Color_64 *l64 = line64;
			for (png_uint_32 ix = 0; ix < info->rowbytes; l64++) {
				l64->r = (unsigned short) (row_pointers[iy][ix++]) << 8;
				l64->g = (unsigned short) (row_pointers[iy][ix++]) << 8;
				l64->b = (unsigned short) (row_pointers[iy][ix++]) << 8;
				if (info->channels == 4) {
					l64->a = (unsigned short) (row_pointers[iy][ix++]) << 8;
				} else
					l64->a = 0;
			}
			storage->PutPixels(0, iy, info->width, line64);
		}
		free(line64);
		}
		break;
	case BMM_TRUE_64: {
		BMM_Color_64 *line64 = (BMM_Color_64 *) calloc(info->width, sizeof(BMM_Color_64));
		for (png_uint_32 iy = 0; iy < info->height; iy++) {
			BMM_Color_64 *l64 = line64;
			unsigned short *row = (unsigned short *) row_pointers[iy];
			for (png_uint_32 ix = 0; ix < info->width; ix++, l64++) {
				l64->r = *row++;
				l64->g = *row++;
				l64->b = *row++;
				if (info->channels == 4) {
					l64->a = *row++;
				} else
					l64->a = 0;
			}
			storage->PutPixels(0, iy, info->width, line64);
		}
		free(line64);
		}
		break;
	case BMM_GRAY_8: {
		BMM_Color_64 *line64 = (BMM_Color_64 *) calloc(info->width, sizeof(BMM_Color_64));
		for (png_uint_32 iy = 0; iy < info->height; iy++) {
			BMM_Color_64 *l64 = line64;
			for (png_uint_32 ix = 0; ix < info->rowbytes; l64++) {
				l64->r = l64->g = l64->b = (unsigned short) (row_pointers[iy][ix++]) << 8;
				if (info->channels == 2)
					l64->a = (unsigned short) (row_pointers[iy][ix++]) << 8;
				else
					l64->a = 0;
			}
			storage->PutPixels(0, iy, info->width, line64);
		}
		free(line64);
		}
		break;
	case BMM_GRAY_16: {
		BMM_Color_64 *line64 = (BMM_Color_64 *) calloc(info->width, sizeof(BMM_Color_64));
		for (png_uint_32 iy = 0; iy < info->height; iy++) {
			BMM_Color_64 *l64 = line64;
			unsigned short *row = (unsigned short *) row_pointers[iy];
			for (png_uint_32 ix = 0; ix < info->width; ix++, l64++) {
				l64->r = l64->g = l64->b = *row++;
				if (info->channels == 2) {
					l64->a = *row++;
				} else
					l64->a = 0;
			}
			storage->PutPixels(0, iy, info->width, line64);
		}
		free(line64);
		}
		break;
	}

	png_read_end(png, info);

	for (i = 0; i < info->height; i++)
		free(row_pointers[i]);

	free(row_pointers);

	fclose(istream);
    png_destroy_read_struct (&png, &info, NULL);

    return storage;
}
Exemplo n.º 2
0
BitmapStorage *BitmapIO_BMP::Load(BitmapInfo *fbi, Bitmap *map, BMMRES *status) 
{

   RGBQUAD      *rgb = NULL;
   BMM_Color_48 *pal = NULL;
   BitmapStorage  *s = NULL;
   BMM_Color_64   *b = NULL;
   BYTE           *p = NULL;
   BYTE       *b8 = NULL;
   BYTE       *b4 = NULL;


   INT_PTR pixels = 0;
   int rows   = 0;
   int w      = 0;
   int wb     = 0;
   int h      = 0;
   int   j;

   //-- Initialize Status Optimistically

   *status = BMMRES_SUCCESS;

   //-- Make sure nothing weird is going on

   if(openMode != BMM_NOT_OPEN) {
      *status = ProcessImageIOError(fbi,BMMRES_INTERNALERROR);
      return NULL;
   }

   //-- Open BMP File -----------------------------------
   
   File file(fbi->Name(), _T("rb"));

   if (!file.stream) {
      *status = ProcessImageIOError(fbi);
      return(NULL);
   }

   //-- Read File Header --------------------------------
   
   if (!ReadBimpHeader(file.stream)) {
      *status = ProcessImageIOError(fbi,BMMRES_BADFILEHEADER);
      return (NULL);
   }
   
   //-- Update Bitmap Info ------------------------------
   
   fbi->SetWidth( (WORD)bmi.biWidth );
   fbi->SetHeight((WORD)bmi.biHeight);
   
   if ((bmi.biBitCount != 32 && bmi.biBitCount != 24 && bmi.biBitCount != 8 && bmi.biBitCount != 4) ||
      bmi.biCompression != BI_RGB) {
      *status = ProcessImageIOError(fbi,GetString(IDS_UNSUPPORTED));
      return(NULL);
   }

// fbi->SetGamma(1.0f);
   fbi->SetAspect(1.0f);

   switch(bmi.biBitCount)
   {
      case 32:
         fbi->SetType(BMM_TRUE_32);
		 // [Kai@8/19/2008] We need to set this flag so that the alpha storage will be created in BMMCreateStorage
		 fbi->SetFlags(MAP_HAS_ALPHA);
         break;

      case 24:
         fbi->SetType(BMM_TRUE_24);
         break;
      
      case 8:
      case 4:

         //-- We don't have a 4 bit bitmap storage anyway. 
         //-- So force 4 bit to 8 bit

         fbi->SetType(BMM_PALETTED);
         break;
   }

   fbi->SetFirstFrame(0);
   fbi->SetLastFrame(0);
   
   //-- Create Image Storage ---------------------------- 
   
   switch(bmi.biBitCount)
   {
      case 32:
         s = BMMCreateStorage(map->Manager(), BMM_TRUE_32);
         break;

      case 24:
         s = BMMCreateStorage(map->Manager(),BMM_TRUE_32);
         break;

      case 8:
      case 4:

         //-- We don't have a 4 bit bitmap storage anyway. 
         //-- So force 4 bit storage to 8 bit storage

         s = BMMCreateStorage(map->Manager(),BMM_PALETTED);
         break;
   }

   if(!s) {
      *status = ProcessImageIOError(fbi,BMMRES_CANTSTORAGE);
      return NULL;
   }

   //-- Allocate Image Storage --------------------------
   
   if (s->Allocate(fbi,map->Manager(),BMM_OPEN_R)==0) {
      
      memory_error_out:
      *status = ProcessImageIOError(fbi,BMMRES_MEMORYERROR);
      goto bail_out;
   
      io_error_out:
      *status = ProcessImageIOError(fbi);
      bail_out:

      if (s) delete s;
      if (b) free(b);
      if (p) free(p);
      if (rgb) free(rgb);
      if (pal) free(pal);

      return NULL;

   }

   
   switch(bmi.biBitCount) 
   {
      case 4:  
         
         //-- Read 4 bit Palette ------------------------------------

         if (!bmi.biClrUsed) 
            bmi.biClrUsed = 16;
         rgb = (RGBQUAD *)malloc(bmi.biClrUsed * sizeof(RGBQUAD));
         if (!rgb)
            goto memory_error_out;
         pal = (BMM_Color_48 *)malloc(bmi.biClrUsed * sizeof(BMM_Color_48));
         if (!pal)
            goto memory_error_out;
         if (fread(rgb,sizeof(RGBQUAD),bmi.biClrUsed,file.stream) != bmi.biClrUsed)   
            goto io_error_out;
         for (j = 0; j < (int)bmi.biClrUsed; j++) 
         {
            pal[j].r = rgb[j].rgbRed   << 8;
            pal[j].g = rgb[j].rgbGreen << 8;
            pal[j].b = rgb[j].rgbBlue  << 8;
         }
    
         s->SetPalette(0,bmi.biClrUsed,pal);
    
         free(pal);
         free(rgb);
         pal = NULL;
         rgb = NULL;

         //-- Read Image (4 Bits) -----------------------------

         w  = fbi->Width();
         wb  = ( ((fbi->Width()+1)/2)+ 3) & ~3; // width must be multiple of 4
         h   = fbi->Height() - 1;

         
         p   = (BYTE *)malloc(wb);
         b4  = (BYTE *)malloc(w);
         if (!p || !b4)
            goto memory_error_out;

         do 
         {
            pixels = fread(p,1,wb,file.stream);
   
            if (pixels != wb && pixels != 0)
               goto io_error_out;
            
            if (pixels)  
            {
               // -- the 4bit buffer p has two pixels per byte.
               // -- convert it to 8 bit buffer b8 that has one pixel per byte
               for(j=0;j<w;j++)
               {
                  b4[j] = (j%2) ?  (p[j/2] & 0x0f) : (p[j/2] >> 4);
               }
               s->PutIndexPixels(0,(h - rows),w,b4);
               rows++;
               if (rows>h) break;
            }

            //-- Progress Report
         
            if (fbi->GetUpdateWindow())
               SendMessage(fbi->GetUpdateWindow(),BMM_PROGRESS,rows,h);

         } while (pixels);
         break;
      
      case 8:  
         
         //-- Read 8 bitPalette ------------------------------------

         if (!bmi.biClrUsed) 
            bmi.biClrUsed = 256;
         rgb = (RGBQUAD *)malloc(bmi.biClrUsed * sizeof(RGBQUAD));
         if (!rgb)
            goto memory_error_out;
         pal = (BMM_Color_48 *)malloc(bmi.biClrUsed * sizeof(BMM_Color_48));
         if (!pal)
            goto memory_error_out;
         if (fread(rgb,sizeof(RGBQUAD),bmi.biClrUsed,file.stream) != bmi.biClrUsed)   
            goto io_error_out;
         for ( j = 0; j < (int)bmi.biClrUsed; j++) 
         {
            pal[j].r = rgb[j].rgbRed   << 8;
            pal[j].g = rgb[j].rgbGreen << 8;
            pal[j].b = rgb[j].rgbBlue  << 8;
         }
    
         s->SetPalette(0,bmi.biClrUsed,pal);
    
         free(pal);
         free(rgb);
         pal = NULL;
         rgb = NULL;

         //-- Read Image (8 Bits) -----------------------------

         w    = (fbi->Width() + 3) & ~3;  // width must be multiple of 4
         h    = fbi->Height() - 1;
   
         p = (BYTE *)malloc(w);

         if (!p)
            goto memory_error_out;

         do 
         {
            pixels = fread(p,1,w,file.stream);
   
            if (pixels != w && pixels != 0)
               goto io_error_out;
            
            if (pixels)  
            {
               s->PutIndexPixels(0,(h - rows),fbi->Width(),p);
               rows++;
               if (rows>h) break;
            }

            //-- Progress Report
         
            if (fbi->GetUpdateWindow())
               SendMessage(fbi->GetUpdateWindow(),BMM_PROGRESS,rows,h);

         } while (pixels);
         break;

      case 24:
      case 32:
         {
      
            //-- Read Image (24/32 Bits) ----------------------------
            bool hasAlpha = (bmi.biBitCount == 32);

            w    = fbi->Width();
            if(!hasAlpha) {
               wb   = (fbi->Width() * 3 + 3) & ~3; // width bytes must be multiple of 4
            }
            else {
               wb   = (fbi->Width() * 4);
            }
            h    = fbi->Height() - 1;
      
            b = (BMM_Color_64  *)malloc(fbi->Width()*sizeof(BMM_Color_64));
            p = (BYTE          *)malloc(wb);

            if(!b || !p)
               goto memory_error_out;

            BYTE *ptr;
      
            do 
            {

               pixels = fread(p,1,wb,file.stream);

               if (pixels != wb && pixels != 0)
                  goto io_error_out;
                  
               if (pixels)  
               {
                  ptr = p;
                  for (int x = 0; x < w; x++) 
                  {
                     b[x].b = (WORD)((*ptr++) << 8);
                     b[x].g = (WORD)((*ptr++) << 8);
                     b[x].r = (WORD)((*ptr++) << 8);
                     if(hasAlpha) {
                        b[x].a = (WORD)((*ptr++) << 8);
                     }
                  }
                  if (s->PutPixels(0,(h - rows),w,b)!=1)
                     goto io_error_out;
                  rows++;
                  if (rows>h) break;
               }

               //-- Progress Report
            
               if (fbi->GetUpdateWindow())
                  SendMessage(fbi->GetUpdateWindow(),BMM_PROGRESS,rows,h);

            } while (pixels);
         }
         break;
   }
   
   //-- Clean Up ----------------------------------------
   
   if (b) free(b);
   if (p) free(p);
   if (b8)free(b8);
   if (b4)free(b4);

   //-- Set the storage's BitmapInfo

   s->bi.CopyImageInfo(fbi);

   return  s;
   
}