// CompressRLE
//		Main compress routine, this function will call the appropriate RLE compression
// method depending on the pixel depth of the source image.
OSErr CompressPixMapRLE(PixMapHandle pixMapHdl, Ptr compressBuffer, Size *compressBufferSizePtr)
{
	Handle hdl = NULL;
	Ptr	   tempPtr = NULL,srcData;
	Ptr	   pixBaseAddr = GetPixBaseAddr(pixMapHdl);
	OSType pixelFormat = GETPIXMAPPIXELFORMAT(*pixMapHdl);
	int		depth = QTGetPixelSize(pixelFormat);
	long   rowBytes = QTGetPixMapHandleRowBytes(pixMapHdl);
	int		width = (**pixMapHdl).bounds.right - (**pixMapHdl).bounds.left;
	int		i, height = (**pixMapHdl).bounds.bottom - (**pixMapHdl).bounds.top;
	Size   widthByteSize = (depth * (long)width + 7) >> 3;
	OSErr  err = noErr;

	// need to remove padding between rows?
	if(widthByteSize != rowBytes){
		// Make a temp buffer for the source
		hdl = NewHandle(height * widthByteSize);
		err = MemError();
		if (err) goto bail;
		
		HLock(hdl);
		
		srcData = tempPtr = *hdl;
		
		// Get rid of row bytes padding
		for (i = 0; i < height; i++) {
			BlockMoveData(pixBaseAddr, tempPtr, widthByteSize);
			tempPtr += widthByteSize;
			pixBaseAddr += rowBytes;
		}
	}else
		srcData = pixBaseAddr;

	// Compress
	switch (depth) {
	case 1:
		CompressRLE8((UInt8*)srcData, height * widthByteSize, compressBuffer, compressBufferSizePtr);
		break;
	case 8:
		CompressRLE8((UInt8*)srcData, height * widthByteSize, compressBuffer, compressBufferSizePtr);
		break;
	case 16:
		CompressRLE16((UInt16*)srcData, height * (widthByteSize >> 1), compressBuffer, compressBufferSizePtr);
		break;
	case 32:
		CompressRLE32((UInt32*)srcData, height * (widthByteSize >> 2), compressBuffer, compressBufferSizePtr);
		break;
	}
	
bail:
	if (hdl)
		DisposeHandle(hdl);

	return err;
}
OSErr CompressRLE(Ptr baseAddr, long rowBytes, int depth, int width, int height, Ptr compressBuffer, Size *compressBufferSizePtr)
{
	Handle hdl;
	Ptr    tempPtr;
	int  i;
	Size   widthByteSize = (depth * (long)width + 7) >> 3;
	OSErr  err;

	// Make a temp buffer for the source
	hdl = NewHandleClear(height * widthByteSize);
	err = MemError();
	if (err) goto bail;
	
	HLock(hdl);
	
	tempPtr = *hdl;
	
	// Get rid of row bytes padding
	for (i = 0; i < height; i++) {
		BlockMoveData(baseAddr, tempPtr, widthByteSize);
		
		tempPtr += widthByteSize;
		baseAddr += rowBytes;
	}

	// Compress
	switch (depth) {
	case 1:
		CompressRLE8((UInt8 *)*hdl, height * widthByteSize, compressBuffer, compressBufferSizePtr);
		break;
	case 8:
		CompressRLE8((UInt8 *)*hdl, height * widthByteSize, compressBuffer, compressBufferSizePtr);
		break;
	case 16:
		CompressRLE16((UInt16 *)*hdl, height * (widthByteSize >> 1), compressBuffer, compressBufferSizePtr);
		break;
	case 32:
		CompressRLE32((UInt32 *)*hdl, height * (widthByteSize >> 2), compressBuffer, compressBufferSizePtr);
		break;
	}
	
bail:
	if (hdl)
		DisposeHandle(hdl);

	return err;
}
예제 #3
0
Word Burger::FileBMP::Save(OutputMemoryStream *pOutput,const Image *pImage,Word bCompress)
{
	// Temp buffer
	Word8 Filler[16];

	Image::ePixelTypes eType = pImage->GetType();
	// Only 24 and 8 bit formats are supported
	if ((eType!=Image::PIXELTYPE8BIT) &&
		(eType!=Image::PIXELTYPE555) && 
		(eType!=Image::PIXELTYPE1555) && 
		(eType!=Image::PIXELTYPE888) && 
		(eType!=Image::PIXELTYPE8888)) {
		return 10;
	}

	// Save the signature (14 bytes)

	pOutput->Append("BM");
	WordPtr uFileLengthMark = pOutput->GetSize();
	pOutput->Append(static_cast<Word32>(0));		// Write the file length (Change later)
	pOutput->Append(m_uReserved1);		// Write the reserved entries
	pOutput->Append(m_uReserved2);

	// Save the image description block and maybe the palette

	Word32 uMark = 14+40+1024;
	Word uDepth = 8;
	if (eType!=Image::PIXELTYPE8BIT) {
		bCompress = FALSE;	// No compression is allowed!!!
		uMark = 14+40;		// No palette
		if (eType==Image::PIXELTYPE888) {
			uDepth = 24;
		} else if (eType==Image::PIXELTYPE8888) {
			uDepth = 32;
		} else {
			uDepth = 16;
		}
	}
	Word uWidth = pImage->GetWidth();
	Word uHeight = pImage->GetHeight();
	WordPtr uStride = pImage->GetStride();

	pOutput->Append(uMark);		// Header with palette size
	pOutput->Append(static_cast<Word32>(40));		// Data info size
	pOutput->Append(static_cast<Word32>(uWidth));	// Image size
	pOutput->Append(static_cast<Word32>(uHeight));
	pOutput->Append(static_cast<Word16>(1));		// Bit planes
	pOutput->Append(static_cast<Word16>(uDepth));	// Bit depth
	pOutput->Append(static_cast<Word32>(bCompress ? BMP_RLE8 : BMP_RGB));		// Data type
	WordPtr uOutputMark = pOutput->GetSize();
	pOutput->Append(static_cast<Word32>(0));		// Output length
	pOutput->Append(static_cast<Word32>(m_iXPixelsPerMeter));	// Pixels per meter
	pOutput->Append(static_cast<Word32>(m_iYPixelsPerMeter));
	pOutput->Append(static_cast<Word32>(m_uColorsUsed));		// Colors used
	pOutput->Append(static_cast<Word32>(m_uColorsImportant));	// Colors important

	// Output the supported types! 8 Bit, 24 and 32 bit

	MemoryClear(Filler,sizeof(Filler));
	const Word8 *pData = pImage->GetImage()+((uHeight-1)*uStride);
	WordPtr uSizeMark;
	if (eType==Image::PIXELTYPE8BIT) {

		// 8 bit paletted!
		// Write out the palette first

		RGBAWord8_t *pPalette = m_Palette;	// First save the palette
		Word i = 256;
		do {
			pOutput->Append(pPalette->m_uBlue);		// Blue
			pOutput->Append(pPalette->m_uGreen);	// Green
			pOutput->Append(pPalette->m_uRed);		// Red
			pOutput->Append(pPalette->m_uAlpha);	// Extra
			++pPalette;
		} while (--i);				// All done?

		// Adjust the start mark for the pixel data to skip past the inserted palette
		uSizeMark = pOutput->GetSize();

		// Compressed?
		if (bCompress) {
			do {
				CompressRLE8(pOutput,pData,uWidth,uHeight==1);	// Compress a line
				pData = pData-uStride;	// Next line up
			} while (--uHeight);		// All done?
		} else {

			// Raw!
			Word uPadding = (0-uWidth)&3;	// 0,3,2,1
			do {
				pOutput->Append(pData,uWidth);	// Save a line to disk 
				pOutput->Append(Filler,uPadding);	// Filler
				pData = pData-uStride;	// Next line up
			} while (--uHeight);				// All done?
		}
	} else {
		uSizeMark = pOutput->GetSize();
		if (eType==Image::PIXELTYPE888) {
			Word uPadding = (0-(uWidth*3))&3;	// Padding after each pixel
			do {
				Word j = uWidth;		// Get count
				const Word8 *pWork = pData;
				do {
					pOutput->Append(pWork[2]);	// Save out the scan line
					pOutput->Append(pWork[1]);
					pOutput->Append(pWork[0]);
					pWork=pWork+3;		// Next triplet
				} while (--j);			// Next pixel
				pOutput->Append(Filler,uPadding);	// Filler
				pData = pData-uStride;	// Next line up
			} while (--uHeight);		// All done?
		} else if (eType==Image::PIXELTYPE8888) {
			// 8888 format
			do {
				Word j = uWidth;		// Get count
				const Word8 *pWork = pData;
				do {
					pOutput->Append(pWork[2]);	// Save out the scan line
					pOutput->Append(pWork[1]);
					pOutput->Append(pWork[0]);
					pOutput->Append(pWork[3]);
					pWork=pWork+4;		// Next triplet
				} while (--j);			// Next pixel
				pData = pData-uStride;	// Next line up
			} while (--uHeight);		// All done?	
		} else {
			Word uPadding = (0-(uWidth*2))&3;	// Padding after each pixel
			// 1555 or x555 format
			do {
				Word j = uWidth;		// Get count
				const Word8 *pWork = pData;
				do {
					pOutput->Append(static_cast<Word16>(reinterpret_cast<const Word16 *>(pWork)[0]&0x7FFFU));	// Save out the scan line
					pWork=pWork+2;		// Next triplet
				} while (--j);			// Next pixel
				pOutput->Append(Filler,uPadding);	// Filler
				pData = pData-uStride;	// Next line up
			} while (--uHeight);		// All done?
		}
	}

	// Wrap up the file

	WordPtr uTell = pOutput->GetSize();

	// Write the length of the total file
	// +2 is for "BM"
	Word32 uLittleData = LittleEndian::Load(static_cast<Word32>((uTell-uFileLengthMark)+2));
	pOutput->Overwrite(&uLittleData,sizeof(Word32),uFileLengthMark);

	// Write the length of the packed data
	uLittleData = LittleEndian::Load(static_cast<Word32>(uTell-uSizeMark));
	pOutput->Overwrite(&uLittleData,sizeof(Word32),uOutputMark);
	return FALSE;
}