Пример #1
0
  void storeFreeImage(const Ref<Image>& img, const FileName& fileName)
  {
      FIBITMAP* dib = FreeImage_Allocate((int)img->width, (int)img->height, 24);

      for(size_t y = 0; y < img->height; y++)
      {
          for(size_t x = 0; x < img->width; x++)
          {
			  Color4 c = img->get(x, y);
              
              RGBQUAD Value = {0};
              Value.rgbRed   = (BYTE)(clamp(c.r) * 255.0f);
              Value.rgbGreen = (BYTE)(clamp(c.g) * 255.0f);
              Value.rgbBlue  = (BYTE)(clamp(c.b) * 255.0f);

              FreeImage_SetPixelColor(dib, (unsigned int)x, (unsigned int)y, &Value);
          }
      }

      FIBITMAP* fiLogo = loadWatermark();

      unsigned int LogoWidth  = FreeImage_GetWidth (fiLogo);
      unsigned int LogoHeight = FreeImage_GetHeight(fiLogo);

      if(LogoWidth > img->width || LogoHeight > img->height)
      {
          FreeImage_Unload(fiLogo);

          FREE_IMAGE_FORMAT fif = FreeImage_GetFIFFromFilename(fileName.c_str());
          if(FreeImage_FIFSupportsWriting(fif))
              FreeImage_Save(fif, dib, fileName.c_str());

          FreeImage_Unload(dib);
      }
      else
      {
          int x_pos = (int)img->width  - LogoWidth;
          int y_pos = (int)img->height - LogoHeight;

          FIBITMAP* fiFG = FreeImage_Allocate((int)img->width, (int)img->height, 32);
          BOOL b = FreeImage_Paste(fiFG, fiLogo, x_pos, y_pos, 255);
          FreeImage_Unload(fiLogo);

          FIBITMAP* fiNew = FreeImage_Composite(fiFG, FALSE, NULL, dib);
          FreeImage_Unload(dib);

          FREE_IMAGE_FORMAT fif = FreeImage_GetFIFFromFilename(fileName.c_str());

          int save_flags = 0;
          if(fif == FIF_JPEG)
              save_flags = JPEG_QUALITYSUPERB | JPEG_BASELINE | JPEG_OPTIMIZE;

          if(FreeImage_FIFSupportsWriting(fif))
              FreeImage_Save(fif, fiNew, fileName.c_str(), save_flags);

          FreeImage_Unload(fiNew);
      }
  }
Пример #2
0
/**
	Print plugins export capabilities
*/
void PrintExportFormats(iostream& ios) {
	int count = FreeImage_GetFIFCount();
	if(count)
		ios << "FORMAT;DESCRIPTION;EXTENSIONS;BITDEPTH;ICC PROFILES\n";
	for(int i = 0; i < count; i++) {
		FREE_IMAGE_FORMAT fif = (FREE_IMAGE_FORMAT)i;

		if(FreeImage_FIFSupportsWriting(fif)) {
			const char * format = FreeImage_GetFormatFromFIF(fif);
			const char * description = FreeImage_GetFIFDescription(fif);
			const char * ext = FreeImage_GetFIFExtensionList(fif);
			const char * icc = "*";

			ios << format << ";" << description << ";" << ext << ";";
			if(FreeImage_FIFSupportsExportBPP(fif, 1))
				ios << "1 ";
			if(FreeImage_FIFSupportsExportBPP(fif, 4))
				ios << "4 ";
			if(FreeImage_FIFSupportsExportBPP(fif, 8))
				ios << "8 ";
			if(FreeImage_FIFSupportsExportBPP(fif, 16))
				ios << "16 ";
			if(FreeImage_FIFSupportsExportBPP(fif, 24))
				ios << "24 ";
			if(FreeImage_FIFSupportsExportBPP(fif, 32))
				ios << "32 ";
			if(FreeImage_FIFSupportsICCProfiles(fif)) {
				ios << ";" << icc;
			} else {
				ios << "; ";
			}
			ios << "\n";
		}
	}
}
Пример #3
0
BOOL fipImage::saveU(const wchar_t* lpszPathName, int flag) const {
	FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
	BOOL bSuccess = FALSE;

	// Try to guess the file format from the file extension
	fif = FreeImage_GetFIFFromFilenameU(lpszPathName);
	if(fif != FIF_UNKNOWN ) {
		// Check that the dib can be saved in this format
		BOOL bCanSave;

		FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(_dib);
		if(image_type == FIT_BITMAP) {
			// standard bitmap type
			WORD bpp = FreeImage_GetBPP(_dib);
			bCanSave = (FreeImage_FIFSupportsWriting(fif) && FreeImage_FIFSupportsExportBPP(fif, bpp));
		} else {
			// special bitmap type
			bCanSave = FreeImage_FIFSupportsExportType(fif, image_type);
		}

		if(bCanSave) {
			bSuccess = FreeImage_SaveU(fif, _dib, lpszPathName, flag);
			return bSuccess;
		}
	}
	return bSuccess;
}
Пример #4
0
/** Generic image writer
@param dib Pointer to the dib to be saved
@param lpszPathName Pointer to the full file name
@param flag Optional save flag constant
@return Returns true if successful, returns false otherwise
*/
bool GenericWriter(const bitmap_ptr& dib, const std::string& lpszPathName, int flag) {
	auto fif = FIF_UNKNOWN;
	auto bSuccess = FALSE;
	// check if file path is not empty
	if (lpszPathName.empty())
		return false;
	if (dib) {
		// try to guess the file format from the file extension
		fif = FreeImage_GetFIFFromFilename(lpszPathName.c_str());
		if (fif != FIF_UNKNOWN) {
			// check that the plugin has sufficient writing and export capabilities ...
			if (FreeImage_FIFSupportsWriting(fif) && FreeImage_FIFSupportsExportType(fif, FreeImage_GetImageType(dib.get()))) {
				// ok, we can save the file
				bSuccess = FreeImage_Save(fif, dib.get(), lpszPathName.c_str(), flag);
				// unless an abnormal bug, we are done !
			}
			else {
				std::cout << "Can't save file" << lpszPathName << std::endl;
			}
		}
    else {
      std::cerr << "Can't determine output file type" << std::endl;
    }
	}
	return (bSuccess == TRUE);
}
Пример #5
0
static VALUE save(VALUE self, VALUE _output) {
  char * output = STR2CSTR(_output);

        FREE_IMAGE_FORMAT fif = FreeImage_GetFIFFromFilename(output);
        if (fif == FIF_UNKNOWN) fif = FIX2INT(rb_iv_get(self, "@file_type"));
        if ((fif != FIF_UNKNOWN) && FreeImage_FIFSupportsWriting(fif)) { 
          GET_BITMAP(bitmap);
          int flags = fif == FIF_JPEG ? JPEG_QUALITYSUPERB : 0;
          if (fif == FIF_PNG) FreeImage_DestroyICCProfile(bitmap);
          return (FreeImage_Save(fif, bitmap, output, flags) ? Qtrue : Qfalse);
        }
        rb_raise(rb_eTypeError, "Unknown file format");
      }
Пример #6
0
/** Generic image writer
	@param dib Pointer to the dib to be saved
	@param lpszPathName Pointer to the full file name
	@param flag Optional save flag constant
	@return Returns true if successful, returns false otherwise
*/
bool GenericWriter(FIBITMAP* dib, const char* lpszPathName, int flag) {
	FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
	BOOL bSuccess = FALSE;

	if(dib) {
		// try to guess the file format from the file extension
		fif = FreeImage_GetFIFFromFilename(lpszPathName);
		if(fif != FIF_UNKNOWN ) {
			// check that the plugin has sufficient writing and export capabilities ...
			WORD bpp = FreeImage_GetBPP(dib);
			if(FreeImage_FIFSupportsWriting(fif) && FreeImage_FIFSupportsExportBPP(fif, bpp)) {
				// ok, we can save the file
				bSuccess = FreeImage_Save(fif, dib, lpszPathName, flag);
				// unless an abnormal bug, we are done !
			}
		}
	}
	return (bSuccess == TRUE) ? true : false;
}
Пример #7
0
VALUE rb_graffik_write(VALUE self, VALUE rb_filename) {
  char *filename = STR2CSTR(rb_filename);
  FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
  
  // Try various methods to get the image format
  fif = FreeImage_GetFIFFromFilename(filename);
  if (fif == FIF_UNKNOWN) {
    fif = FIX2INT(rb_iv_get(self, "@file_type"));
  }
  
  if ((fif != FIF_UNKNOWN) && FreeImage_FIFSupportsWriting(fif)) {
    int flags = fif == FIF_JPEG ? JPEG_QUALITYSUPERB : 0;
    // Load the image from the instance
    FIBITMAP *image = get_instance_image(self);

    // Return Ruby objects for the write status from FreeImage
    return FreeImage_Save(fif, image, filename, flags) ? Qtrue : Qfalse;
  }
  
  rb_raise(rb_eTypeError, "Unknown file format");
}
Пример #8
0
BOOL fipImage::saveToMemory(FREE_IMAGE_FORMAT fif, fipMemoryIO& memIO, int flag) const {
	BOOL bSuccess = FALSE;

	if(fif != FIF_UNKNOWN ) {
		// Check that the dib can be saved in this format
		BOOL bCanSave;

		FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(_dib);
		if(image_type == FIT_BITMAP) {
			// standard bitmap type
			WORD bpp = FreeImage_GetBPP(_dib);
			bCanSave = (FreeImage_FIFSupportsWriting(fif) && FreeImage_FIFSupportsExportBPP(fif, bpp));
		} else {
			// special bitmap type
			bCanSave = FreeImage_FIFSupportsExportType(fif, image_type);
		}

		if(bCanSave) {
			bSuccess = memIO.save(fif, _dib, flag);
			return bSuccess;
		}
	}
	return bSuccess;
}
Пример #9
0
  bool Texture::saveImToFile(const std::string& filename, const uint8_t* im, 
    const uint32_t width, const uint32_t height, const bool save_flipped, 
    const uint32_t num_channels) {
    freeimage_init_lock_.lock();
    if (!freeimage_init_) {
      freeimage_init_lock_.unlock();
      throw std::wruntime_error("Texture::Texture() - ERROR: Please call "
        "initTextureSystem() before loading textures from file!");
    }
    freeimage_init_lock_.unlock();

    // NEW CODE USING THE FREEIMAGE LIBRARY
    FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;  //image format

	  // if still unknown, try to guess the file format from the file extension
	  if (fif == FIF_UNKNOWN) {
      fif = FreeImage_GetFIFFromFilename(filename.c_str());
    }
	  // if still unkown, return failure
	  if (fif == FIF_UNKNOWN) {
      throw wruntime_error(wstring(L"saveRGBToFile() - ERROR: Cannot deduce "
        L"format of the filename: ") + string_util::ToWideString(filename));
    }

    if (!FreeImage_FIFSupportsWriting(fif)) {
      throw std::wruntime_error("saveRGBToFile() - ERROR: Freeimage does not "
        "support writing to this image format!");
      return false;
    }

    BYTE* fi_bits = NULL;
    uint8_t* im_rev = NULL;

    // Unfortunately, Freeimage has a bug:
    // http://sourceforge.net/p/freeimage/bugs/172/
    // It ignores the mask properties and so the red and blue channels (24bpp)
    // get flipped.  Unfortunately, we have to swap them around.
    // As of 4/26/2013 this issue still isn't fixed.
    switch (num_channels) {
    case 0:
      throw std::wruntime_error("saveImToFile() - ERROR: num_channels == 0");
    case 1:
      fi_bits = (BYTE*)im;
      break;
    case 2:
    case 3:
      im_rev = new uint8_t[width * height * num_channels];
      for (uint32_t i = 0; i < width * height * num_channels; i+=num_channels) {
        for (uint32_t j = 0; j < num_channels; j++) {
          im_rev[i + j] = im[i + (num_channels - 1 - j)];
        }
      }
      fi_bits = (BYTE*)im_rev;
      break;
    default:
      throw std::wruntime_error("saveImToFile() - ERROR: num_channels > 0."
        " Saving images with alpha not yet supported.");
    }
    uint32_t pitch = num_channels * width;
    uint32_t bpp = 8 * num_channels;
    uint32_t red_mask = 0x0000FF;  // Free image likes the mask backwards?
    uint32_t green_mask = 0x00FF00;
    uint32_t blue_mask = 0xFF0000;
    FIBITMAP* fi_bit_map = FreeImage_ConvertFromRawBits(fi_bits, width, height,
      pitch, bpp, red_mask, blue_mask, green_mask, save_flipped);
    bool ret = false;
    if (fi_bit_map) {
      ret = (bool)FreeImage_Save(fif, fi_bit_map, filename.c_str(), 
        JPEG_QUALITYSUPERB);
    }
    if (fi_bit_map) {
      FreeImage_Unload(fi_bit_map);
    }

    SAFE_DELETE_ARR(im_rev);
    return ret;
  }
Пример #10
0
	virtual bool save(const std::string& filename, const Array& lat) {
	
		// check existing image type
		FREE_IMAGE_FORMAT type = FreeImage_GetFIFFromFilename(filename.c_str());
		
		if(type == FIF_UNKNOWN) {
			AL_WARN("image format not recognized: %s", filename.c_str());
			return false;
		}
		if(!FreeImage_FIFSupportsWriting(type)) {
			AL_WARN("image format not supported: %s", filename.c_str());
			return false;
		}
		
		destroy();
		
		
		const AlloArrayHeader& header = lat.header;
		int w = header.dim[0];
		int h = (header.dimcount > 1) ? header.dim[1] : 1;
		Image::Format format = Image::getFormat(header.components);

		switch(format) {
			case Image::RGB: {
				switch(header.type) {

					case AlloUInt8Ty: {
						int bpp = header.stride[0]; 
						mImage = FreeImage_AllocateT(FIT_BITMAP, w, h, bpp*8);
						char *bp = (char *)(lat.data.ptr);
						int rowstride = header.stride[1]; 

						for(unsigned j = 0; j < header.dim[1]; ++j) {
							
							// copy Array row to image buffer
							/*memcpy(
								FreeImage_GetScanLine(mImage, j),
								bp + j*rowstride,
								w*3
							);*/

							RGBTRIPLE *pix = (RGBTRIPLE *)FreeImage_GetScanLine(mImage, j);
							Image::RGBPix<uint8_t> *o_pix = (Image::RGBPix<uint8_t> *)(bp + j*rowstride);
							for(unsigned i=0; i < header.dim[0]; ++i) {
								pix->rgbtRed = o_pix->r;
								pix->rgbtGreen = o_pix->g;
								pix->rgbtBlue = o_pix->b;
								++pix;
								++o_pix;
							}
						}
					}
					break;

					default:
						AL_WARN("input matrix type not supported");
						break;
				}
			}
			break;

			case Image::RGBA: {
				
				switch(header.type) {

					case AlloUInt8Ty: {
	
						int bpp = header.stride[0]; 
						mImage = FreeImage_AllocateT(FIT_BITMAP, w, h, bpp*8);
						
						char *bp = (char *)(lat.data.ptr);
						int rowstride = header.stride[1]; 
						
						for(unsigned j = 0; j < header.dim[1]; ++j) {

							// copy Array row to image buffer
							/*memcpy(
								FreeImage_GetScanLine(mImage, j),
								bp + j*rowstride,
								w*4
							);*/
							
							RGBQUAD *pix = (RGBQUAD *)FreeImage_GetScanLine(mImage, j);
							Image::RGBAPix<uint8_t> *o_pix = (Image::RGBAPix<uint8_t> *)(bp + j*rowstride);
							for(unsigned i=0; i < header.dim[0]; ++i) {
								pix->rgbRed = o_pix->r;
								pix->rgbGreen = o_pix->g;
								pix->rgbBlue = o_pix->b;
								pix->rgbReserved = o_pix->a;
								++pix;
								++o_pix;
							}
						}
					}
					break;

					default:
						AL_WARN("input matrix type not supported");
						return false;
				}
			}
			break;

			default: {
				AL_WARN("input matrix format not supported");
				return false;
			}
		}
		
		
		if (mImage == NULL) {
			AL_WARN("image could not be understood");
			return false;
		}
		
		
		return FreeImage_Save(type, mImage, filename.c_str(), 0);
	}
Пример #11
0
//===========================================================================
//===========================================================================
void KImage::SaveAs(const TCHAR* strFileName, unsigned intFormatType)
{
    static int flag_vect[] = 
    {
        BMP_DEFAULT, BMP_SAVE_RLE,
        EXR_DEFAULT, EXR_FLOAT, EXR_NONE, EXR_ZIP, EXR_PIZ,
        EXR_PXR24, EXR_B44, EXR_LC, 

        J2K_DEFAULT, 

        JP2_DEFAULT,

        JPEG_DEFAULT, JPEG_QUALITYSUPERB, JPEG_QUALITYGOOD,
        JPEG_QUALITYNORMAL, JPEG_QUALITYAVERAGE, JPEG_QUALITYBAD,
        JPEG_PROGRESSIVE, JPEG_SUBSAMPLING_411, JPEG_SUBSAMPLING_420, 
        JPEG_SUBSAMPLING_422, JPEG_SUBSAMPLING_444, JPEG_OPTIMIZE,
        JPEG_BASELINE, 

        PNG_DEFAULT, PNG_Z_BEST_SPEED, PNG_Z_DEFAULT_COMPRESSION,
        PNG_Z_BEST_COMPRESSION, PNG_Z_NO_COMPRESSION, PNG_INTERLACED,

        PNM_DEFAULT, PNM_SAVE_RAW, PNM_SAVE_ASCII,

        TIFF_DEFAULT, TIFF_CMYK, TIFF_PACKBITS,
        TIFF_DEFLATE, TIFF_ADOBE_DEFLATE, TIFF_NONE,
        TIFF_CCITTFAX3, TIFF_CCITTFAX4, TIFF_LZW,
        TIFF_JPEG, TIFF_LOGLUV, 

        TARGA_DEFAULT, TARGA_SAVE_RLE};

        static FREE_IMAGE_FORMAT format_vect[] = 
        {
            FIF_BMP, FIF_BMP,
            FIF_EXR, FIF_EXR, FIF_EXR, FIF_EXR, FIF_EXR, FIF_EXR, FIF_EXR, FIF_EXR,
            FIF_J2K,
            FIF_JP2,
            FIF_JPEG, FIF_JPEG, FIF_JPEG, FIF_JPEG, FIF_JPEG, FIF_JPEG, FIF_JPEG, FIF_JPEG,
            FIF_JPEG, FIF_JPEG, FIF_JPEG, FIF_JPEG, FIF_JPEG,
            FIF_PNG, FIF_PNG, FIF_PNG, FIF_PNG, FIF_PNG, FIF_PNG,
            FIF_PPM, FIF_PPM, FIF_PPM,
            FIF_TIFF, FIF_TIFF, FIF_TIFF, FIF_TIFF, FIF_TIFF, FIF_TIFF, FIF_TIFF, FIF_TIFF, 
            FIF_TIFF, FIF_TIFF, FIF_TIFF,
            FIF_TARGA, FIF_TARGA
        };


        for (int intY = intHeight - 1; intY >= 0; intY--)
        {  
            BYTE* crtLine = FreeImage_GetScanLine(this->fbit, intHeight - 1 - intY);
            memcpy(crtLine, pDataMatrix[intY], intLineRasterSize);
        }

        assert(intFormatType < SAVE_NO_FORMAT);
        // check for incorrect parameter
        if (intFormatType >= SAVE_NO_FORMAT)
            return;

        int flag = flag_vect[intFormatType];
        FREE_IMAGE_FORMAT fif = format_vect[intFormatType];

        BOOL res;
        WORD bpp = WORD(FreeImage_GetBPP(this->fbit));
        if(FreeImage_FIFSupportsWriting(fif) && FreeImage_FIFSupportsExportBPP(fif, bpp))
            res = FreeImage_Save_Wrapper(fif, this->fbit, strFileName, flag);
}
Пример #12
0
int SaveImageFile( const char *filename, const uchar *imageData,
                   int imageWidth, int imageHeight, int numComponents,
				   int flags )
{
// Try to guess the file format from the file extension.
	FREE_IMAGE_FORMAT fif = FreeImage_GetFIFFromFilename( filename );
    if( fif == FIF_UNKNOWN )
    {
        printf( "Error: Cannot determine output image format of %s.\n", filename );
        return 0;
    }

    int bits_per_pixel = numComponents * 8;
    if ( bits_per_pixel != 8 && bits_per_pixel != 16 && bits_per_pixel != 24 && bits_per_pixel != 32 )
    {
        printf( "Error: Only 8, 16, 24, 32 bits per pixel are supported.\n" );
        return 0;
    }

// Check whether user image data can be supported by output image format.
	if( !( FreeImage_FIFSupportsWriting( fif ) && 
		   FreeImage_FIFSupportsExportBPP( fif, bits_per_pixel ) ) )
    {
        printf( "Error: Output image format not supported.\n" );
        return 0;
    }

// Create a FIBITMAP for storing the user image data before writing it to file.
	FIBITMAP *dib = FreeImage_AllocateT( FIT_BITMAP, imageWidth, imageHeight, bits_per_pixel );
	if( !dib )
    {
        FreeImage_Unload( dib );
        printf( "Error: Cannot allocate internal bitmap.\n" );
        return 0;
    }


// Copy user image data to the FIBITMAP.
    int imageDataCount = 0;

    if ( numComponents == 1 )
    {
        for( int y = 0; y < imageHeight; y++ )
        {
            BYTE *dibData = FreeImage_GetScanLine( dib, y );

            for( int x = 0; x < imageWidth; x++) 
            {
                 dibData[x] = imageData[imageDataCount++];
            }
        }
    }
    else if ( numComponents == 2 )
    {
        for( int y = 0; y < imageHeight; y++ )
        {
            BYTE *dibData = FreeImage_GetScanLine( dib, y );

            for( int x = 0; x < imageWidth; x++) 
            {
                dibData[0] = imageData[imageDataCount++];
                dibData[1] = imageData[imageDataCount++];
                dibData += numComponents;
            }
        }
    }
    else if ( numComponents == 3 )
    {
        for( int y = 0; y < imageHeight; y++ )
        {
            BYTE *dibData = FreeImage_GetScanLine( dib, y );

            for( int x = 0; x < imageWidth; x++) 
            {
                dibData[FI_RGBA_RED] = imageData[imageDataCount++];
                dibData[FI_RGBA_GREEN] = imageData[imageDataCount++];
                dibData[FI_RGBA_BLUE] = imageData[imageDataCount++];
                dibData += numComponents;
            }
        }
    }
    else if ( numComponents == 4 )
    {
        for( int y = 0; y < imageHeight; y++ )
        {
            BYTE *dibData = FreeImage_GetScanLine( dib, y );

            for( int x = 0; x < imageWidth; x++) 
            {
                dibData[FI_RGBA_RED] = imageData[imageDataCount++];
                dibData[FI_RGBA_GREEN] = imageData[imageDataCount++];
                dibData[FI_RGBA_BLUE] = imageData[imageDataCount++];
                dibData[FI_RGBA_ALPHA] = imageData[imageDataCount++];
                dibData += numComponents;
            }
        }
    }
	
// Write image in FIBITMAP to file.
	if ( !FreeImage_Save( fif, dib, filename, flags ) )
    {
        FreeImage_Unload( dib );
        printf( "Error: Cannot save image file %s.\n", filename );
        return 0;
    }

    FreeImage_Unload( dib );
    return 1; 
}
    virtual bool save(const std::string& filename, const Array& arr, int compressFlags) {

        // check existing image type
        FREE_IMAGE_FORMAT fileType = FreeImage_GetFIFFromFilename(filename.c_str());

        if(fileType == FIF_UNKNOWN) {
            AL_WARN("image format not recognized: %s", filename.c_str());
            return false;
        }
        if(!FreeImage_FIFSupportsWriting(fileType)) {
            AL_WARN("image format not supported: %s", filename.c_str());
            return false;
        }

        Image::Format format = Image::getFormat(arr.components());

        if(FIF_JPEG == fileType && (Image::RGBA == format || Image::LUMALPHA == format)) {
            AL_WARN("cannot save JPEG with alpha channel; use 24-bit RGB or 8-bit grayscale/luminance");
            return false;
        }

        unsigned w = arr.dim(0);
        unsigned h = (arr.dimcount() > 1) ? arr.dim(1) : 1;
        int bpp = arr.stride(0)*8; // bits/pixel

        resize(w,h,bpp);

        if (mImage == NULL) {
            AL_WARN("image could not be understood");
            return false;
        }

        const int rowstride = arr.stride(1);

        //printf("w=%d, h=%d, bpp=%d, stride=%d\n", w,h,bpp,rowstride);

        switch(format) {

        case Image::LUMINANCE:
            switch(arr.type()) {

            case AlloUInt8Ty: {
                char *bp = (char *)(arr.data.ptr);
                for(unsigned j = 0; j < h; ++j) {
                    memcpy(
                        FreeImage_GetScanLine(mImage, j),
                        bp + j*rowstride,
                        w
                    );
                }
            }
            break;

            default:
                AL_WARN("input Array component type not supported");
                return false;
            }
            break;

        // TODO: must save as RGBA
        /*case Image::LUMALPHA:
        	switch(header.type) {

        		case AlloUInt8Ty: {
        			char *bp = (char *)(arr.data.ptr);
        			for(unsigned j = 0; j < h; ++j) {
        				memcpy(
        					FreeImage_GetScanLine(mImage, j),
        					bp + j*rowstride,
        					w*2
        				);
        			}
        		}
        		break;

        		default:
        			AL_WARN("input Array component type not supported");
        			return false;
        	}
        break;*/

        /* According to the FreeImage documentation ("Pixel access functions"):
        "When accessing to individual color components of a 24- or 32-bit
        DIB, you should always use FreeImage macros or RGBTRIPLE / RGBQUAD
        structures in order to write OS independent code.
        */
        case Image::RGB: {
            switch(arr.type()) {

            case AlloUInt8Ty: { //printf("FreeImageImpl: save uint8/RGB\n");
                char *bp = (char *)(arr.data.ptr);

                for(unsigned j = 0; j < h; ++j) {
                    RGBTRIPLE * dst = (RGBTRIPLE *)FreeImage_GetScanLine(mImage, j);
                    const Image::RGBPix<uint8_t> * src = (const Image::RGBPix<uint8_t> *)(bp + j*rowstride);
                    for(unsigned i=0; i < w; ++i) {
                        dst[i].rgbtRed  = src[i].r;
                        dst[i].rgbtGreen= src[i].g;
                        dst[i].rgbtBlue = src[i].b;
                    }
                }
            }
            break;

            default:
                AL_WARN("input Array component type not supported");
                return false;
            }
        }
        break;

        case Image::RGBA: {

            switch(arr.type()) {

            case AlloUInt8Ty: {
                char *bp = (char *)(arr.data.ptr);

                for(unsigned j = 0; j < h; ++j) {
                    RGBQUAD * dst = (RGBQUAD *)FreeImage_GetScanLine(mImage, j);
                    const Image::RGBAPix<uint8_t> * src = (const Image::RGBAPix<uint8_t> *)(bp + j*rowstride);
                    for(unsigned i=0; i < w; ++i) {
                        dst[i].rgbRed     = src[i].r;
                        dst[i].rgbGreen   = src[i].g;
                        dst[i].rgbBlue    = src[i].b;
                        dst[i].rgbReserved= src[i].a;
                    }
                }
            }
            break;

            default:
                AL_WARN("input Array component type not supported");
                return false;
            }
        }
        break;

        default: {
            AL_WARN("input Array component format not supported");
            return false;
        }
        }


        int flags;
        int compressAmt = compressFlags & 127;
        int quality = 100-(compressAmt<=100?compressAmt:100);

        switch(fileType) {

        case FIF_BMP:
            flags = compressAmt >= 50 ? BMP_SAVE_RLE : BMP_DEFAULT;
            break;

        case FIF_EXR:
            flags = compressAmt >= 50 ? EXR_DEFAULT : EXR_NONE;
            break;

        case FIF_JPEG: // default: JPEG_QUALITYGOOD|JPEG_SUBSAMPLING_420
            /*if(compressAmt <= 25) flags = JPEG_QUALITYSUPERB;
            else if(compressAmt <= 50) flags = JPEG_QUALITYGOOD;
            else if(compressAmt <= 75) flags = JPEG_QUALITYAVERAGE;
            else flags = JPEG_QUALITYBAD;*/
            flags = quality;
            break;

        case FIF_J2K:
        case FIF_JP2:
            flags = int(double(quality)*5.11 + 1); // convert [0,100] -> [1,512]
            break;

        case FIF_PNG: // default: PNG_Z_DEFAULT_COMPRESSION (= 6)
            compressAmt = (compressAmt + 5) / 10;
            if(compressAmt != 0) flags = compressAmt>=9 ? 9 : compressAmt;
            else flags = PNG_Z_NO_COMPRESSION;
            break;

        case FIF_TIFF:
            flags = compressAmt >= 50 ? TIFF_DEFAULT : TIFF_NONE;
            break;

        case FIF_TARGA:
            flags = compressAmt >= 50 ? TARGA_SAVE_RLE : TARGA_DEFAULT;
            break;

        default:
            flags = 0;
        }

        return FreeImage_Save(fileType, mImage, filename.c_str(), flags);
    }