//----------------------------------------------------------------------------- CGContextRef CGBitmap::createCGContext () { CGContextRef context = 0; if (bits == 0) { allocBits (); if (imageSource) getCGImage (); if (image) { context = createCGContext (); if (context) { CGContextScaleCTM (context, 1, -1); CGContextDrawImage (context, CGRectMake (0, -size.y, size.x, size.y), image); CGContextScaleCTM (context, 1, -1); return context; } } } if (bits) { CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big; context = CGBitmapContextCreate (bits, size.x, size.y, 8, getBytesPerRow (), GetCGColorSpace (), bitmapInfo); CGContextTranslateCTM (context, 0, (CGFloat)size.y); CGContextScaleCTM (context, 1, -1); } return context; }
//----------------------------------------------------------------------------- CGImageRef CGBitmap::getCGImage () { if (image == 0 && imageSource) { const void* keys[] = {kCGImageSourceShouldCache, kCGImageSourceShouldPreferRGB32}; const void* values[] = {kCFBooleanTrue, kCFBooleanTrue}; CFDictionaryRef options = CFDictionaryCreate (NULL, keys, values, 2, NULL, NULL); image = CGImageSourceCreateImageAtIndex (imageSource, 0, options); CFRelease (imageSource); CFRelease (options); imageSource = 0; } if ((dirty || image == 0) && bits) { freeCGImage (); size_t rowBytes = getBytesPerRow (); size_t byteCount = rowBytes * size.y; size_t bitDepth = 32; CGDataProviderRef provider = CGDataProviderCreateWithData (NULL, bits, byteCount, NULL); CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big; image = CGImageCreate (size.x, size.y, 8, bitDepth, rowBytes, GetCGColorSpace (), bitmapInfo, provider, NULL, false, kCGRenderingIntentDefault); CGDataProviderRelease (provider); dirty = false; } return image; }
void PLIFF85Decoder::Open(PLDataSource * pDataSrc) { // Check if the file is a valid IFF-85 file or not Trace(2, "Decoding IFF-85 header.\n"); PLIFF85::Chunk chunk; if (PLIFF85::MakeID(reinterpret_cast<const char*> (pDataSrc->GetBufferPtr(sizeof chunk))) != PLIFF85::ID_FORM) { raiseError(PL_ERRWRONG_SIGNATURE, "File is not a single-form IFF."); } readChunkHeader(chunk, pDataSrc); size_t totalSize = chunk.ckSize + sizeof chunk; size_t lumpIndex = sizeof chunk; // Now read the form type - we only know how to handle PBM and ILBM. chunk.ckID = ReadMLong(pDataSrc); if (chunk.ckID == PLIFF85::ID_PBM) { Trace(2, "Form type: PBM\n"); } else if (chunk.ckID == PLIFF85::ID_ILBM) { Trace(2, "Form type: ILBM\n"); } else { raiseError(PL_ERRFORMAT_UNKNOWN, "Unknown form type."); } m_formType = chunk.ckID; lumpIndex += sizeof chunk.ckID; int numCMapElements = 0; m_viewMode = 0; // Now loop through the chunks, processing the header and cmap. // Stop when we find the body, so the data source is left in the correct // position to read it. bool readBitmapHeader = false; bool readPalette = false; bool foundBody = false; bool done = false; PLIFF85::LONG bodySize = 0; while (!done) { readChunkHeader(chunk, pDataSrc); lumpIndex += sizeof chunk; if (chunk.ckID == PLIFF85::ID_BMHD) { if (size_t(chunk.ckSize) != sizeof m_bitmapHeader) { raiseError(PL_ERRFORMAT_UNKNOWN, "Unexpected header size."); } m_bitmapHeader.w = ReadMWord(pDataSrc); m_bitmapHeader.h = ReadMWord(pDataSrc); m_bitmapHeader.x = ReadMWord(pDataSrc); m_bitmapHeader.y = ReadMWord(pDataSrc); m_bitmapHeader.nPlanes = ReadByte(pDataSrc); m_bitmapHeader.masking = ReadByte(pDataSrc); m_bitmapHeader.compression = ReadByte(pDataSrc); m_bitmapHeader.pad1 = ReadByte(pDataSrc); m_bitmapHeader.transparentColor = ReadMWord(pDataSrc); m_bitmapHeader.xAspect = ReadByte(pDataSrc); m_bitmapHeader.yAspect = ReadByte(pDataSrc); m_bitmapHeader.pageWidth = ReadMWord(pDataSrc); m_bitmapHeader.pageHeight = ReadMWord(pDataSrc); switch (m_bitmapHeader.masking) { case PLIFF85::mskNone: Trace(2, "No masking.\n"); break; case PLIFF85::mskHasMask: Trace(2, "Has mask plane.\n"); break; case PLIFF85::mskHasTransparentColor: Trace(2, "Has transparent colour.\n"); break; case PLIFF85::mskLasso: Trace(2, "Lasso"); break; default: raiseError(PL_ERRFORMAT_UNKNOWN, "Unknown masking technique."); break; } switch (m_bitmapHeader.compression) { case PLIFF85::cmpNone: Trace(2, "No compression.\n"); break; case PLIFF85::cmpByteRun1: Trace(2, "Byte run encoding.\n"); break; default: raiseError(PL_ERRFORMAT_UNKNOWN, "Unknown compression method."); break; } readBitmapHeader = true; } else if (chunk.ckID == PLIFF85::ID_CMAP) { // The palette. PLCOMPILER_ASSERT(sizeof(PLIFF85::ColorRegister) == 3); numCMapElements = chunk.ckSize / 3; for (int i = 0; i < numCMapElements; ++i) { const PLIFF85::ColorRegister * pElement = reinterpret_cast<const PLIFF85::ColorRegister *> (pDataSrc->ReadNBytes(3)); m_pal[i].Set(pElement->red, pElement->green, pElement->blue, 0xFF); } readPalette = true; } else if (chunk.ckID == PLIFF85::ID_CAMG) { // The viewport mode. if (size_t(chunk.ckSize) != sizeof m_viewMode) { raiseError(PL_ERRFORMAT_UNKNOWN, "Unexpected CAMG size."); } m_viewMode = ReadMLong(pDataSrc); #if DETAILED_TRACE std::ostringstream strTrace; strTrace << "View mode " << std::hex << std::showbase << m_viewMode << ".\n"; Trace(2, strTrace.str().c_str()); #endif } else if (chunk.ckID == PLIFF85::ID_BODY) { bodySize = chunk.ckSize; foundBody = true; done = true; } else { // Some other chunk type - ignore it. pDataSrc->Skip(chunk.ckSize); } if (!done) { lumpIndex += chunk.ckSize; } if (lumpIndex >= totalSize - 1) { done = true; } } // We must have seen a header, cmap and body at this point. if (!readBitmapHeader) { raiseError(PL_ERRFORMAT_UNKNOWN, "Header not found."); } if ((!readPalette) && (m_bitmapHeader.nPlanes <= 8)) { raiseError(PL_ERRFORMAT_UNKNOWN, "Palette not found."); } if (!foundBody) { raiseError(PL_ERRFORMAT_UNKNOWN, "Body not found."); } // Check the body is the expected size ... if (m_bitmapHeader.compression == PLIFF85::cmpNone) { if (bodySize != getBytesPerRow() * m_bitmapHeader.h) { raiseError(PL_ERRFORMAT_UNKNOWN, "Unexpected body size."); } } // ... and that it does not extend beyond the end of the form. if (lumpIndex + bodySize > totalSize) { raiseError(PL_ERRFORMAT_UNKNOWN, "Body extends beyond form."); } // Too many CMAP entries probably indicates an error. const int maxExpectedCMapElements = int(((m_viewMode & PLIFF85::viewHAM) != 0) ? pow(2.0, m_bitmapHeader.nPlanes - 2) : pow(2.0, m_bitmapHeader.nPlanes)); if (numCMapElements > maxExpectedCMapElements) { raiseError(PL_ERRFORMAT_UNKNOWN, "Too many CMAP entries."); } PLPixelFormat pf; int DestBPP = m_bitmapHeader.nPlanes; bool bAlpha = (m_bitmapHeader.masking == PLIFF85::mskHasTransparentColor); if ((DestBPP > 8) || ((m_viewMode & PLIFF85::viewHAM) != 0) || (m_bitmapHeader.masking == PLIFF85::mskHasTransparentColor)) { if (bAlpha) { pf = PLPixelFormat::A8R8G8B8; } else { pf = PLPixelFormat::X8R8G8B8; } } else { pf = PLPixelFormat::I8; } SetBmpInfo(PLPoint(m_bitmapHeader.w, m_bitmapHeader.h), PLPoint(0, 0), pf); } // Open
void PLIFF85Decoder::GetImage(PLBmpBase & Bmp) { Trace(2, "Decoding IFF-85 body.\n"); if (GetBitsPerPixel() == 8) { Bmp.SetPalette(&m_pal[0]); } // Decode each row into local storage, further processing depends on // form type. const int bytes_per_row = getBytesPerRow(); std::vector<PLBYTE> buf(bytes_per_row); for (int row = 0; row < m_bitmapHeader.h; ++row) { #if DETAILED_TRACE std::ostringstream strTrace; strTrace << "#Row " << row << ".\n"; Trace(3, strTrace.str().c_str()); #endif if (m_bitmapHeader.compression == PLIFF85::cmpByteRun1) { readCompressedRow(&buf[0], m_pDataSrc, bytes_per_row); } else { PLASSERT(m_bitmapHeader.compression == PLIFF85::cmpNone); readUncompressedRow(&buf[0], m_pDataSrc, bytes_per_row); } std::vector<PLBYTE> decodedBuf(m_bitmapHeader.w * GetBitsPerPixel() / 8); if (m_formType == PLIFF85::ID_PBM) { // The number of bytes we want to output may be less than the number // we have read in, as the input must have an even number of bytes per // plane (which can produce a lot of unnecessary padding for a PBM). const int bytes_per_row = m_bitmapHeader.w * GetBitsPerPixel() / 8; decodedBuf.assign(buf.begin(), buf.begin() + bytes_per_row); } else { PLASSERT(m_formType == PLIFF85::ID_ILBM); for (int bp = 0; bp < m_bitmapHeader.nPlanes; ++bp) { const int start_index = bp * bytes_per_row / m_bitmapHeader.nPlanes; for (int i = 0; i < m_bitmapHeader.w; ++i) { // Get the byte we're interested in. PLBYTE the_byte = buf[start_index + i / 8]; // Isolate the bit we're interested in. the_byte &= static_cast<PLBYTE> (1 << (7 - (i % 8))); // Now shift the bit to the correct position for this plane. if ((7 - (i % 8)) > bp) { the_byte >>= 7 - (i % 8) - bp; } else { the_byte <<= bp - (7 - (i % 8)); } decodedBuf[i] |= the_byte; } } }