From b814213e898e9f394fac3dc07102baae1aba5304 Mon Sep 17 00:00:00 2001 From: osnola Date: Sun, 1 Dec 2013 09:38:52 +0100 Subject: [PATCH 5/8] ClarisWorks parser: try to reconstruct compressed bitmap ... (cherry picked from commit ecbabfcc912700602abba3c56543845d1cd243a8) Signed-off-by: osnola Conflicts: src/lib/CWGraph.cxx --- src/lib/CWGraph.cxx | 89 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 67 insertions(+), 22 deletions(-) diff --git a/src/lib/CWGraph.cxx b/src/lib/CWGraph.cxx index 01109f6..52f2a5c 100644 --- a/src/lib/CWGraph.cxx +++ b/src/lib/CWGraph.cxx @@ -311,20 +311,24 @@ struct ZonePict : public Zone { struct Bitmap : public CWStruct::DSET { //! constructor Bitmap(CWStruct::DSET const &dset = CWStruct::DSET()) : - DSET(dset), m_bitmapType(-1), m_bitmapSize(0,0), m_entry(), m_colorMap() { + DSET(dset), m_numBytesPerPixel(0), m_bitmapSize(0,0), m_bitmapRowSize(0), m_entry(), m_colorMap() + { } //! operator<< friend std::ostream &operator<<(std::ostream &o, Bitmap const &bt) { o << static_cast(bt); - if (bt.m_bitmapType >= 0) o << "type=" << bt.m_bitmapType << ","; + if (bt.m_numBytesPerPixel > 0) o << "type=" << bt.m_numBytesPerPixel << ","; + else if (bt.m_numBytesPerPixel < 0) o << "type=1/" << (-bt.m_numBytesPerPixel) << ","; return o; } - //! the bitmap type - int m_bitmapType; + //! the number of bite by pixel + int m_numBytesPerPixel; //! the bitmap size Vec2i m_bitmapSize; + //! the bitmap row size in the file ( with potential alignement) + int m_bitmapRowSize; //! the bitmap entry MWAWEntry m_entry; //! the color map @@ -1992,33 +1996,52 @@ bool CWGraph::readBitmapData(CWGraphInternal::Bitmap &zone) MWAW_DEBUG_MSG(("CWGraph::readBitmapData: file is too short\n")); return false; } - /* Fixme: this code can not works for the packed bitmap*/ - long numColors = zone.m_bitmapSize[0]*zone.m_bitmapSize[1]; - int numBytes = numColors ? int(sz/numColors) : 0; - if (sz != numBytes*numColors) { + + long numPixels = zone.m_bitmapSize[0]*zone.m_bitmapSize[1]; + if (numPixels<=0) { + MWAW_DEBUG_MSG(("CWGraph::readBitmapData: unexpected empty size\n")); + return false; + } + + int numBytesPerPixel = int(sz/numPixels); + int bitmapRowSize=zone.m_bitmapSize[0]*numBytesPerPixel; + if (sz < numPixels) { + int nHalfPixel=(zone.m_bitmapSize[0]+1)/2; + for (int align=1; align <= 4; align*=2) { + int diffToAlign=align==1 ? 0 : align-(nHalfPixel%align); + if (diffToAlign==align) continue; + if (sz == (nHalfPixel+diffToAlign)*zone.m_bitmapSize[1]) { + bitmapRowSize=(nHalfPixel+diffToAlign); + numBytesPerPixel=-2; + break; + } + } + } + else if (sz > numBytesPerPixel*numPixels) { // check for different row alignement: 2 and 4 for (int align=2; align <= 4; align*=2) { int diffToAlign=align-(zone.m_bitmapSize[0]%align); if (diffToAlign==align) continue; - numColors = (zone.m_bitmapSize[0]+diffToAlign)*zone.m_bitmapSize[1]; - numBytes = numColors ? int(sz/numColors) : 0; - if (sz == numBytes*numColors) { - zone.m_bitmapSize[0]+=diffToAlign; - MWAW_DEBUG_MSG(("CWGraph::readBitmapData: increase width to %d\n",zone.m_bitmapSize[0])); + numPixels = (zone.m_bitmapSize[0]+diffToAlign)*zone.m_bitmapSize[1]; + numBytesPerPixel = int(sz/numPixels); + if (sz == numBytesPerPixel*numPixels) { + bitmapRowSize=(zone.m_bitmapSize[0]+diffToAlign)*numBytesPerPixel; break; } } } - if (sz != numBytes*numColors) { + + if (sz != bitmapRowSize*zone.m_bitmapSize[1]) { MWAW_DEBUG_MSG(("CWGraph::readBitmapData: unexpected size\n")); return false; } - zone.m_bitmapType = numBytes; + zone.m_numBytesPerPixel = numBytesPerPixel; + zone.m_bitmapRowSize = bitmapRowSize; zone.m_entry.setBegin(pos+4); zone.m_entry.setEnd(endPos); libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; libmwaw::DebugStream f; - f << "Entries(BitmapData):nBytes=" << numBytes; + f << "Entries(BitmapData):[" << numBytesPerPixel << "]"; ascFile.addPos(pos); ascFile.addNote(f.str().c_str()); ascFile.skipZone(pos+4, endPos-1); @@ -2615,9 +2638,13 @@ bool CWGraph::sendBitmap(int number, bool asGraphic, MWAWPosition const &pos) bool CWGraph::sendBitmap(CWGraphInternal::Bitmap &bitmap, bool asGraphic, MWAWPosition pos) { - if (!bitmap.m_entry.valid() || !bitmap.m_bitmapType) + if (!bitmap.m_entry.valid() || !bitmap.m_numBytesPerPixel) return false; - + int bytesPerPixel = bitmap.m_numBytesPerPixel; + if (bytesPerPixel<0 && (bytesPerPixel!=-2 && bytesPerPixel!=-4)) { + MWAW_DEBUG_MSG(("CWGraph::sendBitmap: unknown group of color\n")); + return false; + } if (asGraphic) { if (!m_parserState->m_graphicListener || !m_parserState->m_graphicListener->isDocumentStarted()) { @@ -2637,21 +2664,38 @@ bool CWGraph::sendBitmap(CWGraphInternal::Bitmap &bitmap, bool asGraphic, MWAWPo bmapIndexed->setColors(bitmap.m_colorMap); bmap.reset(bmapIndexed); indexed = true; - } else + } + else { + if (bytesPerPixel<0) { + MWAW_DEBUG_MSG(("CWGraph::sendBitmap: unexpected mode for compressed bitmap. Bitmap ignored.\n")); + return false; + } bmap.reset((bmapColor=new MWAWPictBitmapColor(bitmap.m_bitmapSize))); + } + bool const isCompressed = bytesPerPixel<0; + int const numColorByData= isCompressed ? -bytesPerPixel : 1; + long const colorMask= !isCompressed ? 0 : numColorByData==2 ? 0xF : 0x3; + int const numColorBytes = isCompressed ? 8/numColorByData : 8*bytesPerPixel; //! let go - int fSz = bitmap.m_bitmapType; MWAWInputStreamPtr &input= m_parserState->m_input; input->seek(bitmap.m_entry.begin(), WPX_SEEK_SET); for (int r = 0; r < bitmap.m_bitmapSize[1]; r++) { + long rPos=input->tell(); + int numRead=0; + long read=0; for (int c = 0; c < bitmap.m_bitmapSize[0]; c++) { - long val = (long) input->readULong(fSz); + if (numRead==0) { + read=(long) input->readULong(isCompressed ? 1 : bytesPerPixel); + numRead=numColorByData; + } + --numRead; + long val=!isCompressed ? read : (read>>(numColorBytes*numRead))&colorMask; if (indexed) { bmapIndexed->set(c,r,(int)val); continue; } - switch(fSz) { + switch (bytesPerPixel) { case 1: bmapColor->set(c,r, MWAWColor((unsigned char)val,(unsigned char)val,(unsigned char)val)); break; @@ -2671,6 +2715,7 @@ bool CWGraph::sendBitmap(CWGraphInternal::Bitmap &bitmap, bool asGraphic, MWAWPo } } } + input->seek(rPos+bitmap.m_bitmapRowSize, WPX_SEEK_SET); } WPXBinaryData data; -- 1.9.0