Esempio n. 1
0
File: png.cpp Progetto: 2asoft/xray
BMMRES
BitmapIO_PNG::Save(const TCHAR *filename, Bitmap *map) 
{
    if(!map)
		return(ProcessImageIOError(&bi,BMMRES_INTERNALERROR));
    
    openMode = BMM_OPEN_W;
    
    if((ostream = _tfopen(filename,_T("wb"))) == NULL)
		return (ProcessImageIOError(&bi));

	BitmapStorage *palettedStorage = NULL;

    png = png_create_write_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 (palettedStorage) delete palettedStorage;
        fclose(ostream);
		_tremove(filename);
        png_destroy_write_struct (&png, &info);
        return BMMRES_IOERROR;
    }
    info = png_create_info_struct(png);

    png_init_io(png, ostream);

	switch(cfg.color_type) {
	case PngPalette:
		info->color_type = PNG_COLOR_TYPE_PALETTE;
		info->pixel_depth = 8;
		info->valid |= PNG_INFO_PLTE;
		info->num_palette = 256;
		break;
	case PngRGB:
		info->color_type = PNG_COLOR_TYPE_RGB;
		break;
	case PngRGBA:
		info->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
		break;
	case PngGray:
		info->color_type = PNG_COLOR_TYPE_GRAY;
		break;
	case PngGrayA:
		info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
		break;
	}
	info->width = map->Width();
	info->height = map->Height();
	if (OutputGamma() != 1.0f) {
		info->valid |= PNG_INFO_gAMA;
		info->gamma = OutputGamma();
	} else info->gamma = 1.0f;

	if (map->Aspect() != 1.0f) {
		info->valid |= PNG_INFO_pHYs;
		info->x_pixels_per_unit = (png_uint_32)(1024.0f * map->Aspect());
		info->y_pixels_per_unit = 1024;
		info->phys_unit_type = 0;
	}

	if (cfg.interlaced)
		info->interlace_type = 1;
	else
		info->interlace_type = 0;

	switch( info->color_type) {
	case PNG_COLOR_TYPE_PALETTE:
	case PNG_COLOR_TYPE_GRAY:
		info->channels = 1;
		break;
	case PNG_COLOR_TYPE_GRAY_ALPHA:
		info->channels = 2;
		break;
	case PNG_COLOR_TYPE_RGB:
		info->channels = 3;
		break;
	case PNG_COLOR_TYPE_RGB_ALPHA:
		info->channels = 4;
		break;
	}

	info->bit_depth = cfg.bitdepth;
	info->rowbytes = info->width * info->channels * info->bit_depth / 8;

	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);

	switch (info->bit_depth) {
	case 16:  // this is only RGB/RGBA/Gray/GrayA
		switch(info->color_type) {
		case PNG_COLOR_TYPE_RGB:
		case PNG_COLOR_TYPE_RGB_ALPHA:
			{
			BMM_Color_64 *line64 = (BMM_Color_64 *) calloc(info->width,sizeof(BMM_Color_64));
			for (png_uint_32 iy = 0; iy < info->height; ++iy) {
				if (GetOutputPixels(0, iy, info->width, line64) != 1) {
					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;
					}

					fclose(ostream);
					_tremove(filename);
					free(line64);
                    png_destroy_write_struct (&png, &info);
					return BMMRES_IOERROR;
				}
				BMM_Color_64 *l64=line64;
				unsigned short *oshort = (unsigned short *)row_pointers[iy];
				for (png_uint_32 ix = 0; ix < info->width; ++l64, ix++) {
					*oshort = (unsigned short)l64->r; oshort++;
					*oshort = (unsigned short)l64->g; oshort++;
					*oshort = (unsigned short)l64->b; oshort++;
					if (info->channels == 4) {
						*oshort = (unsigned short)l64->a; oshort++;
					}
				}
			}
			free(line64);
			}
			break;
		case PNG_COLOR_TYPE_GRAY:
			{
			for (png_uint_32 iy = 0; iy < info->height; ++iy)
				if (map->Get16Gray(0, iy, info->width, (unsigned short *)row_pointers[iy]) != 1) {
					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;
					}

					fclose(ostream);
					_tremove(filename);
                    png_destroy_write_struct (&png, &info);
					return BMMRES_IOERROR;
				}
			}
			break;
		case PNG_COLOR_TYPE_GRAY_ALPHA:
			{
			BMM_Color_64 *line64 = (BMM_Color_64 *) calloc(info->width, sizeof(BMM_Color_64));
			unsigned short *line = (unsigned short *) calloc(info->width, sizeof(unsigned short));
			for (png_uint_32 iy = 0; iy < info->height; ++iy) {
				if (GetOutputPixels(0, iy, info->width, line64) != 1 ||
					map->Get16Gray(0, iy, info->width, line) != 1) {
					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;
					}
					free(line64);
					free(line);
					fclose(ostream);
					_tremove(filename);
                    png_destroy_write_struct (&png, &info);
					return BMMRES_IOERROR;
				}
				BMM_Color_64 *l64 = line64;
				unsigned short *l=line;
				unsigned short *oshort = (unsigned short *)row_pointers[iy];
				for (png_uint_32 ix = 0; ix < info->width; ix++, l64++) {
					*oshort++ = *l++;
					*oshort++ = (unsigned short)l64->a;
				}
			}
			free(line64);
			free(line);
			}
			break;
		}
		break;

	case 8: // this can be any type
		switch(info->color_type) {
		case PNG_COLOR_TYPE_PALETTE: {
			// Set up a palette buffer
			PixelBuf48 palettebuf(info->num_palette);
			BMM_Color_48 *pal = palettebuf.Ptr();
			// Must compute a color palette, and reduce the image to 256 colors!
			// this calculates a palette based on the gamma corrected values, which
			// corresponds to what GetOutputPixels returns.
			if(CalcOutputPalette(256, pal) == 0) {
				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;
				}
				fclose(ostream);
				_tremove(filename);
                png_destroy_write_struct (&png, &info);
				return BMMRES_IOERROR;
			}
			info->palette = (png_color *)malloc(info->num_palette * sizeof(png_color));
			for (int i = 0; i < info->num_palette; i++) {
				info->palette[i].red = (unsigned char)(pal[i].r >> 8);
				info->palette[i].green = (unsigned char)(pal[i].g >> 8);
				info->palette[i].blue = (unsigned char)(pal[i].b >> 8);
			}
			PixelBuf64 line(info->width);
			ColorPacker* cpack = BMMNewColorPacker(info->width, pal, info->num_palette);
			for (png_uint_32 iy=0; iy < info->height; ++iy) {
				if(!GetOutputPixels(0, iy, info->width, line.Ptr())) {
					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;
					}
					fclose(ostream);
					_tremove(filename);
                    png_destroy_write_struct (&png, &info);
					return BMMRES_IOERROR;
				}
				cpack->PackLine(line.Ptr(), row_pointers[iy], info->width);
			}
			cpack->DeleteThis();
			}
			break;
		case PNG_COLOR_TYPE_RGB:
		case PNG_COLOR_TYPE_RGB_ALPHA:
			{
			BMM_Color_32 *line32 = (BMM_Color_32 *) calloc(info->width,sizeof(BMM_Color_32));
			for (png_uint_32 iy = 0; iy < info->height; ++iy) {
				if (GetDitheredOutputPixels(0, iy, info->width, line32) != 1) {
					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;
					}

					fclose(ostream);
					_tremove(filename);
					free(line32);
                    png_destroy_write_struct (&png, &info);
					return BMMRES_IOERROR;
				}
				BMM_Color_32 *l32=line32;
				unsigned char *obyte = (unsigned char *)row_pointers[iy];
				for (png_uint_32 ix = 0; ix < info->width; ++l32, ix++) {
					*obyte = (unsigned char)l32->r; obyte++;
					*obyte = (unsigned char)l32->g; obyte++;
					*obyte = (unsigned char)l32->b; obyte++;
					if (info->channels == 4) {
						*obyte = (unsigned char)l32->a; obyte++;
					}
				}
			}
			free(line32);
			}
			break;
		case PNG_COLOR_TYPE_GRAY:
			{
			unsigned short *line = (unsigned short *) calloc(info->width * info->channels, sizeof(unsigned short));
			for (png_uint_32 iy = 0; iy < info->height; ++iy) {
				if (map->Get16Gray(0, iy, info->width, line) != 1) {
					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;
					}

					fclose(ostream);
					_tremove(filename);
					free(line);
                    png_destroy_write_struct (&png, &info);
					return BMMRES_IOERROR;
				}
				unsigned short *l=line;
				unsigned char *obyte = (unsigned char *)row_pointers[iy];
				for (png_uint_32 ix = 0; ix < info->width; ix++) {
					*obyte++ = (unsigned char)(*l >> 8); l++;
				}
			}
			free(line);
			}
			break;
		case PNG_COLOR_TYPE_GRAY_ALPHA:
			{
			BMM_Color_64 *line64 = (BMM_Color_64 *) calloc(info->width,sizeof(BMM_Color_64));
			unsigned short *line = (unsigned short *) calloc(info->width, sizeof(unsigned short));
			for (png_uint_32 iy = 0; iy < info->height; ++iy) {
				if (GetOutputPixels(0, iy, info->width, line64) != 1 ||
					map->Get16Gray(0, iy, info->width, line) != 1) {
					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;
					}

					fclose(ostream);
					_tremove(filename);
					free(line);
					free(line64);
                    png_destroy_write_struct (&png, &info);
					return BMMRES_IOERROR;
				}
				unsigned short *l=line;
				BMM_Color_64 *l64 = line64;
				unsigned char *obyte = (unsigned char *)row_pointers[iy];
				for (png_uint_32 ix = 0; ix < info->width; ix++, l64++) {
					*obyte++ = (unsigned char)(*l >> 8); l++;
					*obyte++ = (unsigned char)(l64->a >> 8);
				}
			}
			free(line);
			free(line64);
			}
			break;
		}
		break;
#ifdef OUTPUT_1_2_4
	case 4: { // Paletted only
		}
		break;
	case 2: { // Paletted only
		}
		break;
	case 1: { // Paletted only
		}
#endif
		break;
	}

	png_write_info(png, info);

	png_set_swap(png);

	png_write_image(png, row_pointers);

	png_write_end(png, info);
	fclose(ostream);

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

	free(row_pointers);

    png_destroy_write_struct (&png, &info);

    return BMMRES_SUCCESS;
}
Esempio n. 2
0
BMMRES BitmapIO_BMP::Write(int frame) 
{

   BMMRES result = BMMRES_SUCCESS;
   
   //-- If we haven't gone through an OpenOutput(), leave

   if (openMode != BMM_OPEN_W)
      return (ProcessImageIOError(&bi,BMMRES_INTERNALERROR));

   //-- Resolve Filename --------------------------------

   TCHAR filename[MAX_PATH];

   if (frame == BMM_SINGLEFRAME) 
   {
      _tcscpy(filename,bi.Name());
   } 
   else 
   {
      if (!BMMCreateNumberedFilename(bi.Name(),frame,filename))
         return (ProcessImageIOError(&bi,BMMRES_NUMBEREDFILENAMEERROR));
   }
   
   //-- Create Image File -------------------------------
   
   File file(filename, _T("wb"));
   
   if (!file.stream)
      return (ProcessImageIOError(&bi));
   

   //-- Create File Header-------------------------------

   BITMAPFILEHEADER  hdr;
   PBITMAPINFO       pbmi;
   int               lx,y;
   
   memset(&hdr,0,sizeof(BITMAPFILEHEADER));
   hdr.bfType    = 0x4d42;
   hdr.bfOffBits = sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER);


   //-- Pallette buffer and pixel buffer for 8bit output
   PixelBuf8         *pixBuf;
   BYTE           *pix;
   PixelBuf48        *palBuf;       
   BMM_Color_48      *pal;
   
   int w  = map->Width();
   int wb = (map->Width() + 3) & ~3;   // width must be multiple of 4
   int h  = map->Height();


   switch(mParams.outDepth)
   {

      //-- Paletted BMP required

      case BMM_PALETTED:
         pixBuf = new PixelBuf8(wb*h);
         palBuf = new PixelBuf48(256);
         
         if( (!pixBuf) || (!palBuf) )
            ProcessImageIOError(&bi,BMMRES_MEMORYERROR);
   
         pix = pixBuf->Ptr();
         pal = palBuf->Ptr();
         
         if( (!pix) || (!pal) )
            ProcessImageIOError(&bi,BMMRES_MEMORYERROR);
   
         if( Storage()->Paletted()) 
         {
            //-- Existing map is palletted...so get the pallete and 
            //-- the look up table..we are done..
            
            Storage()->GetPalette(0, 256, pal);
            for(y = 0; y < h; y++)  
               Storage()->GetIndexPixels(0,(h-y-1),w,pix+wb*y);      
         }
         else 
         {
            
            //-- Caluculate the pallete for the image..
            //-- Then create the look up table

            if(CalcOutputPalette(256,pal) == 0)
               ProcessImageIOError(&bi);
      
            PixelBuf64     line(w);
            ColorPacker*   cPack = BMMNewColorPacker(w,pal,256);
            for(y=0; y<h; y++) 
            {
               if(!GetOutputPixels(0,(h-y-1),w,line.Ptr()))
                  ProcessImageIOError(&bi);
               cPack->PackLine(line.Ptr(),pix+y*wb,w);
            }
            cPack->DeleteThis();
         }
   
         //-- Fill in the BITMAPINFO structure---------------------

         lx = sizeof(BITMAPINFOHEADER) + 256*sizeof(RGBQUAD) + wb*h;
         
         pbmi = (PBITMAPINFO)LocalAlloc(LPTR,lx);
         if (!pbmi)
            return (ProcessImageIOError(&bi,GetString(IDS_CONVERT_ERROR)));

         memset(pbmi,0,lx);

         pbmi->bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
         pbmi->bmiHeader.biWidth       = w;
         pbmi->bmiHeader.biHeight      = h;
         pbmi->bmiHeader.biPlanes      = 1;
         pbmi->bmiHeader.biBitCount    = 8;
         pbmi->bmiHeader.biCompression = BI_RGB;
         pbmi->bmiHeader.biSizeImage   = w*h; //256*sizeof(RGBQUAD) + wb*h;
         pbmi->bmiHeader.biXPelsPerMeter = 2834;
         pbmi->bmiHeader.biYPelsPerMeter = 2834;
         
         hdr.bfOffBits += 256*sizeof(RGBQUAD);  // DS 2/16/98

         RGBQUAD *rgb;

         //-- Fill in the palette

         rgb = (RGBQUAD*) &(pbmi->bmiColors[0]);
         for(y=0; y<256; y++)
         {
            rgb->rgbRed   =  pal[y].r >> 8;
            rgb->rgbGreen =  pal[y].g >> 8;
            rgb->rgbBlue  =  pal[y].b >> 8;
            rgb++;
         }

         //-- Fill in the look up table

         memcpy((LPBYTE)rgb, pix,wb*h);

         break;

      //-- RGB24 requested--------------------------------------
      case BMM_NO_TYPE:
      case BMM_TRUE_24:
         {
         //-- Convert Bitmap to DIB ---------------------------
   
         pbmi = GetDitheredOutputDib();
         if (!pbmi)
            return (ProcessImageIOError(&bi,GetString(IDS_CONVERT_ERROR)));
   
   
         //-- Prepare Header ------------------------
   
         if (bi.GetUpdateWindow())
            SendMessage(bi.GetUpdateWindow(),BMM_PROGRESS,25,100);

         int rb  = (map->Width() * 3 + 3) & ~3; // must be multiple of 4 bytes
         lx  = sizeof(BITMAPINFOHEADER) + (rb * map->Height());
         }
         break;
      default:
         assert(0);
         return BMMRES_IOERROR;
         break;

   }
      
   hdr.bfSize    = lx + sizeof(BITMAPFILEHEADER);
   
   //-- Write Header ------------------------

   size_t res = fwrite(&hdr,1,sizeof(BITMAPFILEHEADER),file.stream);

   if (res != sizeof(BITMAPFILEHEADER)) 
   {
      io_error:
      result = ProcessImageIOError(&bi);
      LocalFree(pbmi);
      return (result);
   }

   //-- Write Image File --------------------------------
   
   if (bi.GetUpdateWindow())
      SendMessage(bi.GetUpdateWindow(),BMM_PROGRESS,50,100);

   res = fwrite(pbmi,1,lx,file.stream);
   
   if (res != lx)
      goto io_error;
   
   LocalFree(pbmi);
   
   if (bi.GetUpdateWindow())
      SendMessage(bi.GetUpdateWindow(),BMM_PROGRESS,100,100);

   return (result);

}