void ZDCPixmapEncoder_JPEGLib::Imp_Write(const ZStreamW& iStream, const void* iBaseAddress, const ZDCPixmapNS::RasterDesc& iRasterDesc, const ZDCPixmapNS::PixelDesc& iPixelDesc, const ZRect& iBounds) { jpeg_compress_struct theJCS; JPEGErrorMgr theEM; theJCS.err = &theEM; ::jpeg_create_compress(&theJCS); theJCS.image_width = iBounds.Width(); theJCS.image_height = iBounds.Height(); JPEGWriter theJW(iStream); theJCS.dest = &theJW; vector<uint8> rowBufferVector; try { ZDCPixmapNS::PixvalDesc destPixvalDesc; ZDCPixmapNS::PixelDesc destPixelDesc; ZRef<ZDCPixmapNS::PixelDescRep> thePixelDescRep = iPixelDesc.GetRep(); if (ZDCPixmapNS::PixelDescRep_Gray* thePixelDescRep_Gray = ZRefDynamicCast<ZDCPixmapNS::PixelDescRep_Gray>(thePixelDescRep)) { theJCS.input_components = 1; theJCS.in_color_space = JCS_GRAYSCALE; rowBufferVector.resize(iBounds.Width()); destPixelDesc = ZDCPixmapNS::PixelDesc(ZDCPixmapNS::eFormatStandard_Gray_8); destPixvalDesc.fDepth = 8; destPixvalDesc.fBigEndian = true; } else { theJCS.input_components = 3; theJCS.in_color_space = JCS_RGB; rowBufferVector.resize(3 * iBounds.Width()); destPixelDesc = ZDCPixmapNS::PixelDesc(ZDCPixmapNS::eFormatStandard_RGB_24); destPixvalDesc.fDepth = 24; destPixvalDesc.fBigEndian = true; } ::jpeg_set_defaults(&theJCS); ::jpeg_set_quality(&theJCS, fQuality, TRUE); theJCS.dct_method = JDCT_FASTEST; ::jpeg_start_compress(&theJCS, TRUE); JSAMPROW rowPtr[1]; rowPtr[0] = &rowBufferVector[0]; for (size_t y = iBounds.top; y < iBounds.bottom; ++y) { const void* sourceRowAddress = iRasterDesc.CalcRowAddress(iBaseAddress, y); ZDCPixmapNS::sBlitRow( sourceRowAddress, iRasterDesc.fPixvalDesc, iPixelDesc, iBounds.left, rowPtr[0], destPixvalDesc, destPixelDesc, 0, iBounds.Width()); ::jpeg_write_scanlines(&theJCS, rowPtr, 1); } ::jpeg_finish_compress(&theJCS); } catch (...) { ::jpeg_destroy(reinterpret_cast<j_common_ptr>(&theJCS)); throw; } ::jpeg_destroy(reinterpret_cast<j_common_ptr>(&theJCS)); }
void ZDCPixmapEncoder_GIF::Imp_Write(const ZStreamW& iStream, const void* iBaseAddress, const ZDCPixmapNS::RasterDesc& iRasterDesc, const ZDCPixmapNS::PixelDesc& iPixelDesc, const ZRect& iBounds) { ZRef<ZDCPixmapNS::PixelDescRep_Indexed> thePixelDescRep_Indexed = ZRefDynamicCast<ZDCPixmapNS::PixelDescRep_Indexed>(iPixelDesc.GetRep()); ZAssertStop(2, thePixelDescRep_Indexed); if (fTransparent) iStream.WriteString("GIF89a"); else iStream.WriteString("GIF87a"); iStream.WriteUInt16LE(iBounds.Width()); iStream.WriteUInt16LE(iBounds.Height()); uint8 globalStrmFlags = 0; globalStrmFlags |= 0x80; // hasGlobalColorTable globalStrmFlags |= 0x70; // colorResolution (8 bits per component) // globalStrmFlags |= 0x08; // set this if the color table is sorted in priority order ZAssertStop(2, iRasterDesc.fPixvalDesc.fDepth > 0 && iRasterDesc.fPixvalDesc.fDepth <= 8); globalStrmFlags |= iRasterDesc.fPixvalDesc.fDepth - 1; // globalColorTableSize & depth iStream.WriteUInt8(globalStrmFlags); iStream.WriteUInt8(0); // backgroundColorIndex iStream.WriteUInt8(0); // Pixel aspect ratio -- 0 == none specified. const ZRGBColorPOD* theColors; size_t theColorsCount; thePixelDescRep_Indexed->GetColors(theColors, theColorsCount); sWriteColorTable(iStream, theColors, theColorsCount, 1 << iRasterDesc.fPixvalDesc.fDepth); if (fTransparent) { iStream.WriteUInt8('!'); // Extension block iStream.WriteUInt8(0xF9); // Graphic Control Extension iStream.WriteUInt8(4); // Block size // The next byte encodes four fields: // 3 bits, Reserved == 0 // 3 bits, Disposal Method == none (0), // 1 bit, User Input Flag == none (0) // 1 bit, Transparent Color Flag = yes (1) iStream.WriteUInt8(1); iStream.WriteUInt16LE(0); // Delay time iStream.WriteUInt8(fTransparentPixval); iStream.WriteUInt8(0); // Block terminator } iStream.WriteUInt8(','); // Start of image iStream.WriteUInt16LE(0); // Origin h iStream.WriteUInt16LE(0); // Origin v iStream.WriteUInt16LE(iBounds.Width()); iStream.WriteUInt16LE(iBounds.Height()); uint8 localStrmFlags = 0; // localStrmFlags |= 0x80; // hasLocalColorTable if (fInterlace) localStrmFlags |= 0x40; // interlaced // localStrmFlags |= 0x20; // sorted // localStrmFlags |= 0x70; // localColorTableSize iStream.WriteUInt8(localStrmFlags); iStream.WriteUInt8(iRasterDesc.fPixvalDesc.fDepth); // Initial code size. { // Scope theSC. StreamW_Chunk theSC(iStream); ZStreamW_LZWEncode* theSLZW = nil; ZStreamW_LZWEncodeNoPatent* theSLZWNP = nil; ZStreamW* theStream; if (fNoPatent) { theSLZWNP = new ZStreamW_LZWEncodeNoPatent(iRasterDesc.fPixvalDesc.fDepth, theSC); theStream = theSLZWNP; } else { theSLZW = new ZStreamW_LZWEncode(iRasterDesc.fPixvalDesc.fDepth, theSC); theStream = theSLZW; } ZDCPixmapNS::PixvalDesc destPixvalDesc(8, true); vector<uint8> theRowBufferVector(iBounds.Width()); void* theRowBuffer = &theRowBufferVector[0]; try { if (fInterlace) { for (int pass = 0; pass < 4; ++pass) { for (ZCoord currentY = iBounds.top + sInterlaceStart[pass]; currentY < iBounds.bottom; currentY += sInterlaceIncrement[pass]) { const void* sourceRowAddress = iRasterDesc.CalcRowAddress(iBaseAddress, currentY); ZDCPixmapNS::sBlitRowPixvals( sourceRowAddress, iRasterDesc.fPixvalDesc, iBounds.left, theRowBuffer, destPixvalDesc, 0, iBounds.Width()); theStream->Write(theRowBuffer, iBounds.Width()); } } } else { for (ZCoord currentY = iBounds.top; currentY < iBounds.bottom; ++currentY) { const void* sourceRowAddress = iRasterDesc.CalcRowAddress(iBaseAddress, currentY); ZDCPixmapNS::sBlitRowPixvals( sourceRowAddress, iRasterDesc.fPixvalDesc, iBounds.left, theRowBuffer, destPixvalDesc, 0, iBounds.Width()); theStream->Write(theRowBuffer, iBounds.Width()); } } } catch (...) { delete theSLZW; delete theSLZWNP; throw; } delete theSLZW; delete theSLZWNP; } iStream.WriteUInt8(';'); // Trailer. }
static void sUnpackFromStream(const ZStreamR& inStream, ZCoord inSourceWidth, ZCoord inSourceHeight, unsigned short inSourceRowBytes, short inSourcePixelSize, const ZRGBColorPOD* inSourceColors, size_t inSourceColorTableSize, void* inDestBaseAddress, const ZDCPixmapNS::RasterDesc& inDestRasterDesc, const ZDCPixmapNS::PixelDesc& inDestPixelDesc) { // We're only supporting indexed pixels right now ZAssert(inSourcePixelSize == 1 || inSourcePixelSize == 2 || inSourcePixelSize == 4 || inSourcePixelSize == 8); ZDCPixmapNS::PixelDesc sourcePixelDesc(inSourceColors, inSourceColorTableSize); ZDCPixmapNS::PixvalDesc sourcePixvalDesc(inSourcePixelSize, true); if (inSourceRowBytes < 8) { // ah-ha! The bits aren't actually packed. This will be easy. uint8 lineBuffer[8]; for (ZCoord theScanLine = 0; theScanLine < inSourceHeight; ++theScanLine) { inStream.Read(lineBuffer, inSourceRowBytes); void* destRowAddress = inDestRasterDesc.CalcRowAddress(inDestBaseAddress, theScanLine); ZDCPixmapNS::sBlitRow(lineBuffer, sourcePixvalDesc, sourcePixelDesc, 0, destRowAddress, inDestRasterDesc.fPixvalDesc, inDestPixelDesc, 0, inSourceWidth); } } else { // Sometimes we get rows with length > rowBytes. Allocate some extra for slop. // Also note that the data is stored as multiples of rowBytes, which may represent more // pixels than inSourceWidth (if inSourceWidth % 4 != 0). So we have to check for // destinationH < inSourceWidth before we actually blit to the destination. vector<uint8> lineBufferVector(inSourceRowBytes + 80); uint8* lineBuffer = &lineBufferVector[0]; ZDCPixmapNS::PixvalAccessor destAccessor(inDestRasterDesc.fPixvalDesc); for (ZCoord theScanLine = 0; theScanLine < inSourceHeight; ++theScanLine) { void* destRowAddress = inDestRasterDesc.CalcRowAddress(inDestBaseAddress, theScanLine); size_t lineLen; if (inSourceRowBytes > 250 || inSourcePixelSize > 8) lineLen = inStream.ReadUInt16(); else lineLen = inStream.ReadUInt8(); if (lineLen > inSourceRowBytes + 80) ::sThrowBadFormat(); inStream.Read(lineBuffer, lineLen); ZCoord destinationH = 0; for (size_t j = 0; j < lineLen; /*no increment*/) { if (lineBuffer[j] & 0x80) { size_t repeatCount = (lineBuffer[j++] ^ 0xFF) + 2; ZRGBColorPOD theRGBColor; sourcePixelDesc.AsRGBColor(lineBuffer[j++], theRGBColor); uint32 destPixval = inDestPixelDesc.AsPixval(theRGBColor); for (size_t k = 0; k < repeatCount; ++k) { if (destinationH < inSourceWidth) destAccessor.SetPixval(destRowAddress, destinationH, destPixval); destinationH += 1; } } else { size_t realLength = lineBuffer[j] + 1; if (inSourceWidth > destinationH) { size_t countToCopy = min(realLength, size_t(inSourceWidth - destinationH)); ZDCPixmapNS::sBlitRow(lineBuffer, sourcePixvalDesc, sourcePixelDesc, j + 1, destRowAddress, inDestRasterDesc.fPixvalDesc, inDestPixelDesc, destinationH, countToCopy); destinationH += countToCopy; } j += realLength + 1; } } } } }