// 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; }
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; }