Alien-FreeImage

 view release on metacpan or  search on metacpan

src/Source/FreeImage/PluginSGI.cpp  view on Meta::CPAN


static const char * DLL_CALLCONV
Format() {
  return "SGI";
}

static const char * DLL_CALLCONV
Description() {
  return "SGI Image Format";
}

static const char * DLL_CALLCONV
Extension() {
  return "sgi,rgb,rgba,bw";
}

static const char * DLL_CALLCONV
RegExpr() {
  return NULL;
}

static const char * DLL_CALLCONV
MimeType() {
  return "image/x-sgi";
}

static BOOL DLL_CALLCONV
Validate(FreeImageIO *io, fi_handle handle) {
	BYTE sgi_signature[2] = { 0x01, 0xDA };
	BYTE signature[2] = { 0, 0 };

	io->read_proc(signature, 1, sizeof(sgi_signature), handle);

	return (memcmp(sgi_signature, signature, sizeof(sgi_signature)) == 0);
}

static BOOL DLL_CALLCONV
SupportsExportDepth(int depth) {
  return FALSE;
}

static BOOL DLL_CALLCONV 
SupportsExportType(FREE_IMAGE_TYPE type) {
  return FALSE;
}

static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
	int width = 0, height = 0, zsize = 0;
	int i, dim;
	int bitcount;
	SGIHeader sgiHeader;
	RLEStatus my_rle_status;
	FIBITMAP *dib = NULL;
	LONG *pRowIndex = NULL;

	try {
		// read the header
		memset(&sgiHeader, 0, sizeof(SGIHeader));
		if(io->read_proc(&sgiHeader, 1, sizeof(SGIHeader), handle) < sizeof(SGIHeader)) {
		   throw SGI_LESS_THAN_HEADER_LENGTH;
		}
#ifndef FREEIMAGE_BIGENDIAN
		SwapHeader(&sgiHeader);
#endif
		if(sgiHeader.magic != 474) {
			throw FI_MSG_ERROR_MAGIC_NUMBER;
		}
		
		BOOL bIsRLE = (sgiHeader.storage == 1) ? TRUE : FALSE;
	
		// check for unsupported image types
		if (sgiHeader.bpc != 1) {
			// Expected one byte per color component
			throw SGI_16_BIT_COMPONENTS_NOT_SUPPORTED; 
		}
		if (sgiHeader.colormap != 0) {
			// Indexed or dithered images not supported
			throw SGI_COLORMAPS_NOT_SUPPORTED; 
		}

		// get the width & height
		dim = sgiHeader.dimension;
		width = sgiHeader.xsize;
		if (dim < 3) {
			zsize = 1;
		} else {
			zsize = sgiHeader.zsize;
		}

		if (dim < 2) {
			height = 1;
		} else {
			height = sgiHeader.ysize;
		}
		
		if(bIsRLE) {
			// read the Offset Tables 
			int index_len = height * zsize;
			pRowIndex = (LONG*)malloc(index_len * sizeof(LONG));
			if(!pRowIndex) {
				throw FI_MSG_ERROR_MEMORY;
			}
			
			if ((unsigned)index_len != io->read_proc(pRowIndex, sizeof(LONG), index_len, handle)) {
				throw SGI_EOF_IN_RLE_INDEX;
			}
			
#ifndef FREEIMAGE_BIGENDIAN		
			// Fix byte order in index
			for (i = 0; i < index_len; i++) {
				SwapLong((DWORD*)&pRowIndex[i]);
			}
#endif
			// Discard row size index
			for (i = 0; i < (int)(index_len * sizeof(LONG)); i++) {
				BYTE packed = 0;
				if( io->read_proc(&packed, sizeof(BYTE), 1, handle) < 1 ) {
					throw SGI_EOF_IN_RLE_INDEX;
				}
			}
		}
		
		switch(zsize) {
			case 1:
				bitcount = 8;
				break;
			case 2:
				//Grayscale+Alpha. Need to fake RGBA
				bitcount = 32;
				break;
			case 3:
				bitcount = 24;
				break;
			case 4:
				bitcount = 32;
				break;
			default:
				throw SGI_INVALID_CHANNEL_COUNT;
		}
		
		dib = FreeImage_Allocate(width, height, bitcount);
		if(!dib) {
			throw FI_MSG_ERROR_DIB_MEMORY;
		}
		
		if (bitcount == 8) {
			// 8-bit SGI files are grayscale images, so we'll generate
			// a grayscale palette.
			RGBQUAD *pclrs = FreeImage_GetPalette(dib);
			for (i = 0; i < 256; i++) {
				pclrs[i].rgbRed = (BYTE)i;
				pclrs[i].rgbGreen = (BYTE)i;
				pclrs[i].rgbBlue = (BYTE)i;
				pclrs[i].rgbReserved = 0;
			}
		}

		// decode the image

		memset(&my_rle_status, 0, sizeof(RLEStatus));
		
		int ns = FreeImage_GetPitch(dib);                                                    
		BYTE *pStartRow = FreeImage_GetScanLine(dib, 0);
		int offset_table[] = { 2, 1, 0, 3 };
		int numChannels = zsize;
		if (zsize < 3) {
			offset_table[0] = 0;
		}
		if (zsize == 2)
		{
			//This is how faked grayscale+alpha works.
			//First channel goes into first 
			//second channel goes into alpha (4th channel)
			//Two channels are left empty and will be copied later
			offset_table[1] = 3;
			numChannels = 4;
		}
		
		LONG *pri = pRowIndex;
		for (i = 0; i < zsize; i++) {
			BYTE *pRow = pStartRow + offset_table[i];
			for (int j = 0; j < height; j++, pRow += ns, pri++) {
				BYTE *p = pRow;
				if (bIsRLE) {
					my_rle_status.cnt = 0;
					io->seek_proc(handle, *pri, SEEK_SET);
				}
				for (int k = 0; k < width; k++, p += numChannels) {
					int ch;
					BYTE packed = 0;
					if (bIsRLE) {
						ch = get_rlechar(io, handle, &my_rle_status);
						packed = (BYTE)ch;
					}
					else {
						ch = io->read_proc(&packed, sizeof(BYTE), 1, handle);
					}
					if (ch == EOF) {
						throw SGI_EOF_IN_IMAGE_DATA;
					}
					*p = packed;
				}
			}
		}
		
		if (zsize == 2)
		{
			BYTE *pRow = pStartRow;
			//If faking RGBA from grayscale + alpha, copy first channel to second and third
			for (int i=0; i<height; i++, pRow += ns)
			{
				BYTE *pPixel = pRow;
				for (int j=0; j<width; j++)
				{
					pPixel[2] = pPixel[1] = pPixel[0];
					pPixel += 4;
				}
			}
		}
		if(pRowIndex)
			free(pRowIndex);

		return dib;

	} catch(const char *text) {
		if(pRowIndex) free(pRowIndex);
		if(dib) FreeImage_Unload(dib);
		FreeImage_OutputMessageProc(s_format_id, text);
		return NULL;
	}
}

// ==========================================================
//   Init
// ==========================================================

void DLL_CALLCONV 
InitSGI(Plugin *plugin, int format_id) {
	s_format_id = format_id;
	
	plugin->format_proc = Format;
	plugin->description_proc = Description;
	plugin->extension_proc = Extension;
	plugin->regexpr_proc = RegExpr;
	plugin->open_proc = NULL;
	plugin->close_proc = NULL;
	plugin->pagecount_proc = NULL;
	plugin->pagecapability_proc = NULL;
	plugin->load_proc = Load;
	plugin->save_proc = NULL;
	plugin->validate_proc = Validate;
	plugin->mime_proc = MimeType;
	plugin->supports_export_bpp_proc = SupportsExportDepth;
	plugin->supports_export_type_proc = SupportsExportType;
	plugin->supports_icc_profiles_proc = NULL;
}



( run in 0.807 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )