Blob Blame History Raw
From b814213e898e9f394fac3dc07102baae1aba5304 Mon Sep 17 00:00:00 2001
From: osnola <alonso@loria.fr>
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 <alonso@loria.fr>

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<CWStruct::DSET const &>(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