You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by ki...@apache.org on 2015/12/31 21:23:21 UTC

svn commit: r1722465 - in /poi/trunk/src/scratchpad: src/org/apache/poi/hwmf/record/ src/org/apache/poi/hwmf/usermodel/ testcases/org/apache/poi/hwmf/

Author: kiwiwings
Date: Thu Dec 31 20:23:20 2015
New Revision: 1722465

URL: http://svn.apache.org/viewvc?rev=1722465&view=rev
Log:
WMF fixes

Modified:
    poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmap16.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmapDib.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfWindowing.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java
    poi/trunk/src/scratchpad/testcases/org/apache/poi/hwmf/TestHwmfParsing.java

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmap16.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmap16.java?rev=1722465&r1=1722464&r2=1722465&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmap16.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmap16.java Thu Dec 31 20:23:20 2015
@@ -76,33 +76,8 @@ public class HwmfBitmap16 {
         byte buf[] = new byte[bytes];
         leis.read(buf);
         
-//        FileOutputStream fos = new FileOutputStream("bla16.bmp");
-//        fos.write(buf);
-//        fos.close();
-        
-        
-//        BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
-//        
-//        int size2 = 0;
-//        byte buf[] = new byte[widthBytes];
-//        for (int h=0; h<height; h++) {
-//            leis.read(buf);
-//            size2 += widthBytes;
-//
-//            ImageInputStream iis = new MemoryCacheImageInputStream(new ByteArrayInputStream(buf));
-//
-//            for (int w=0; w<width; w++) {
-//                long bitsAtPixel = iis.readBits(bitsPixel);
-//                // TODO: is bitsPixel a multiple of 3 (r,g,b)
-//                // which colortable should be used for the various bit sizes???
-//                
-//            }
-//        }
-//        
-//        assert (bytes == size2);
-//
-//        size += size2;
-        
+        // TODO: this is not implemented ... please provide a sample, if it
+        // ever happens to you, to come here ...
         
         return size;
     }

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmapDib.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmapDib.java?rev=1722465&r1=1722464&r2=1722465&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmapDib.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmapDib.java Thu Dec 31 20:23:20 2015
@@ -22,6 +22,7 @@ import java.awt.image.BufferedImage;
 import java.io.BufferedInputStream;
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -207,7 +208,7 @@ public class HwmfBitmapDib {
     @SuppressWarnings("unused")
     private Color colorTable[];
     @SuppressWarnings("unused")
-    private int colorMaskRed=0,colorMaskGreen=0,colorMaskBlue=0;
+    private int colorMaskR=0,colorMaskG=0,colorMaskB=0;
 
     // size of header and color table, for start of image data calculation
     private int introSize;
@@ -222,7 +223,7 @@ public class HwmfBitmapDib {
         introSize += readColors(leis);
         assert(introSize < 10000);
 
-        int fileSize = (headerImageSize != 0) ? (int)(introSize+headerImageSize) : recordSize;
+        int fileSize = (headerImageSize < headerSize) ? recordSize : (int)Math.min(introSize+headerImageSize,recordSize);
         
         imageData = new byte[fileSize];
         leis.reset();
@@ -316,41 +317,43 @@ public class HwmfBitmapDib {
             return 0;
         case BI_BITCOUNT_1:
             // 2 colors
-            return readRGBQuad(leis, 2);
+            return readRGBQuad(leis, (int)(headerColorUsed == 0 ? 2 : Math.min(headerColorUsed,2)));
         case BI_BITCOUNT_2:
             // 16 colors
-            return readRGBQuad(leis, 16);
+            return readRGBQuad(leis, (int)(headerColorUsed == 0 ? 16 : Math.min(headerColorUsed,16)));
         case BI_BITCOUNT_3:
             // 256 colors
-            return readRGBQuad(leis, (int)headerColorUsed);
-        case BI_BITCOUNT_5:
-            colorMaskRed=0xFF;
-            colorMaskGreen=0xFF;
-            colorMaskBlue=0xFF;
-            return 0;
+            return readRGBQuad(leis, (int)(headerColorUsed == 0 ? 256 : Math.min(headerColorUsed,256)));
         case BI_BITCOUNT_4:
-            if (headerCompression == Compression.BI_RGB) {
-                colorMaskBlue = 0x1F;
-                colorMaskGreen = 0x1F<<5;
-                colorMaskRed = 0x1F<<10;
+            switch (headerCompression) {
+            case BI_RGB:
+                colorMaskB = 0x1F;
+                colorMaskG = 0x1F<<5;
+                colorMaskR = 0x1F<<10;
                 return 0;
-            } else {
-                assert(headerCompression == Compression.BI_BITFIELDS);
-                colorMaskBlue = leis.readInt();
-                colorMaskGreen = leis.readInt();
-                colorMaskRed = leis.readInt();
+            case BI_BITFIELDS:
+                colorMaskB = leis.readInt();
+                colorMaskG = leis.readInt();
+                colorMaskR = leis.readInt();
                 return 3*LittleEndianConsts.INT_SIZE;
+            default:
+                throw new IOException("Invalid compression option ("+headerCompression+") for bitcount ("+headerBitCount+").");
             }
+        case BI_BITCOUNT_5:
         case BI_BITCOUNT_6:
-            if (headerCompression == Compression.BI_RGB) {
-                colorMaskBlue = colorMaskGreen = colorMaskRed = 0xFF;
+            switch (headerCompression) {
+            case BI_RGB:
+                colorMaskR=0xFF;
+                colorMaskG=0xFF;
+                colorMaskB=0xFF;
                 return 0;
-            } else {
-                assert(headerCompression == Compression.BI_BITFIELDS);
-                colorMaskBlue = leis.readInt();
-                colorMaskGreen = leis.readInt();
-                colorMaskRed = leis.readInt();
+            case BI_BITFIELDS:
+                colorMaskB = leis.readInt();
+                colorMaskG = leis.readInt();
+                colorMaskR = leis.readInt();
                 return 3*LittleEndianConsts.INT_SIZE;
+            default:
+                throw new IOException("Invalid compression option ("+headerCompression+") for bitcount ("+headerBitCount+").");
             }
         }
     }
@@ -372,30 +375,36 @@ public class HwmfBitmapDib {
         return size;
     }
 
-    public BufferedImage getImage() {
+    public InputStream getBMPStream() {
         if (imageData == null) {
             throw new RecordFormatException("bitmap not initialized ... need to call init() before");
         }
 
+        // sometimes there are missing bytes after the imageData which will be 0-filled
+        int imageSize = (int)Math.max(imageData.length, introSize+headerImageSize);
+        
         // create the image data and leave the parsing to the ImageIO api
-        byte buf[] = new byte[BMP_HEADER_SIZE+imageData.length];
+        byte buf[] = new byte[BMP_HEADER_SIZE+imageSize];
 
         // https://en.wikipedia.org/wiki/BMP_file_format #  Bitmap file header
         buf[0] = (byte)'B';
         buf[1] = (byte)'M';
         // the full size of the bmp
-        LittleEndian.putInt(buf, 2, (int)(BMP_HEADER_SIZE + introSize + headerImageSize));
+        LittleEndian.putInt(buf, 2, BMP_HEADER_SIZE+imageSize);
         // the next 4 bytes are unused
         LittleEndian.putInt(buf, 6, 0);
         // start of image = BMP header length + dib header length + color tables length
         LittleEndian.putInt(buf, 10, BMP_HEADER_SIZE + introSize);
-        
+        // fill the "known" image data
         System.arraycopy(imageData, 0, buf, BMP_HEADER_SIZE, imageData.length);
         
+        return new ByteArrayInputStream(buf);
+    }
+    
+    public BufferedImage getImage() {
         try {
-            return ImageIO.read(new ByteArrayInputStream(buf));
+            return ImageIO.read(getBMPStream());
         } catch (IOException e) {
-            // ... shouldn't happen
             throw new RecordFormatException("invalid bitmap data", e);
         }
     }

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java?rev=1722465&r1=1722464&r2=1722465&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java Thu Dec 31 20:23:20 2015
@@ -614,7 +614,7 @@ public class HwmfFill {
         
         @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
-            boolean hasBitmap = (recordSize > ((recordFunction >> 8) + 3));
+            boolean hasBitmap = (recordSize/2 != ((recordFunction >> 8) + 3));
 
             int size = 0;
             int rasterOpCode = leis.readUShort();
@@ -802,7 +802,7 @@ public class HwmfFill {
         
         @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
-            boolean hasBitmap = (recordSize > ((recordFunction >> 8) + 3));
+            boolean hasBitmap = (recordSize/2 != ((recordFunction >> 8) + 3));
 
             int size = 0;
             int rasterOpCode = leis.readUShort();
@@ -840,7 +840,7 @@ public class HwmfFill {
 
         @Override
         public BufferedImage getImage() {
-            return target.getImage();
+            return (target == null) ? null : target.getImage();
         }
     }
 

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java?rev=1722465&r1=1722464&r2=1722465&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java Thu Dec 31 20:23:20 2015
@@ -259,6 +259,9 @@ public class HwmfText {
         
         @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
+            // -6 bytes of record function and length header
+            final int remainingRecordSize = (int)(recordSize-6);
+            
             y = leis.readShort();
             x = leis.readShort();
             stringLength = leis.readShort();
@@ -266,7 +269,7 @@ public class HwmfText {
             
             int size = 4*LittleEndianConsts.SHORT_SIZE;
             
-            if (fwOpts != 0) {
+            if (fwOpts != 0 && size+8<=remainingRecordSize) {
                 // the bounding rectangle is optional and only read when fwOpts are given
                 left = leis.readShort();
                 top = leis.readShort();
@@ -280,8 +283,6 @@ public class HwmfText {
             text = new String(buf, 0, stringLength, LocaleUtil.CHARSET_1252);
             size += buf.length;
             
-            // -6 bytes of record function and length header
-            int remainingRecordSize = (int)(recordSize-6);
             if (size < remainingRecordSize) {
                 if (size + stringLength*LittleEndianConsts.SHORT_SIZE < remainingRecordSize) {
                     throw new RecordFormatException("can't read Dx array - given recordSize doesn't contain enough values for string length "+stringLength);

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfWindowing.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfWindowing.java?rev=1722465&r1=1722464&r2=1722465&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfWindowing.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfWindowing.java Thu Dec 31 20:23:20 2015
@@ -542,14 +542,17 @@ public class HwmfWindowing {
             count = leis.readUShort();
             top = leis.readUShort();
             bottom = leis.readUShort();
-            left_scanline = new int[count];
-            right_scanline = new int[count];
-            for (int i=0; i*2<count; i++) {
+            int size = 3*LittleEndianConsts.SHORT_SIZE;
+            left_scanline = new int[count/2];
+            right_scanline = new int[count/2];
+            for (int i=0; i<count/2; i++) {
                 left_scanline[i] = leis.readUShort();
                 right_scanline[i] = leis.readUShort();
+                size += 2*LittleEndianConsts.SHORT_SIZE;
             }
             count2 = leis.readUShort();
-            return 8 + count*4;
+            size += LittleEndianConsts.SHORT_SIZE;
+            return size;
         }
     }
 
@@ -618,26 +621,23 @@ public class HwmfWindowing {
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
             nextInChain = leis.readShort();
             objectType = leis.readShort();
-            objectCount = leis.readUShort();
+            objectCount = leis.readInt();
             regionSize = leis.readShort();
             scanCount = leis.readShort();
             maxScan = leis.readShort();
-            bottom = leis.readShort();
-            right = leis.readShort();
-            top = leis.readShort();
             left = leis.readShort();
+            top = leis.readShort();
+            right = leis.readShort();
+            bottom = leis.readShort();
+            
+            int size = 9*LittleEndianConsts.SHORT_SIZE+LittleEndianConsts.INT_SIZE;
 
-            List<WmfScanObject> soList = new ArrayList<WmfScanObject>();
-            int scanCountI = 0, size = 0;
-            do {
-                WmfScanObject so = new WmfScanObject();
-                size += so.init(leis);
-                scanCountI += so.count;
-                soList.add(so);
-            } while  (scanCountI < scanCount);
-            scanObjects = soList.toArray(new WmfScanObject[soList.size()]);
+            scanObjects = new WmfScanObject[scanCount];
+            for (int i=0; i<scanCount; i++) {
+                size += (scanObjects[i] = new WmfScanObject()).init(leis);
+            }
 
-            return 20 + size;
+            return size;
         }
 
         @Override

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java?rev=1722465&r1=1722464&r2=1722465&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java Thu Dec 31 20:23:20 2015
@@ -70,12 +70,8 @@ public class HwmfPicture {
             int remainingSize = (int)(recordSize - consumedSize);
             assert(remainingSize >= 0);
             if (remainingSize > 0) {
-//                byte remaining[] = new byte[remainingSize];
-//                leis.read(remaining);
-//                FileOutputStream fos = new FileOutputStream("remaining.dat");
-//                fos.write(remaining);
-//                fos.close();
-                 leis.skip(remainingSize);
+            	// skip size in loops, because not always all bytes are skipped in one call 
+                for (int i=remainingSize; i>0; i-=leis.skip(i));
             }
         }
     }

Modified: poi/trunk/src/scratchpad/testcases/org/apache/poi/hwmf/TestHwmfParsing.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/testcases/org/apache/poi/hwmf/TestHwmfParsing.java?rev=1722465&r1=1722464&r2=1722465&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/testcases/org/apache/poi/hwmf/TestHwmfParsing.java (original)
+++ poi/trunk/src/scratchpad/testcases/org/apache/poi/hwmf/TestHwmfParsing.java Thu Dec 31 20:23:20 2015
@@ -20,14 +20,17 @@ package org.apache.poi.hwmf;
 import static org.junit.Assert.assertEquals;
 
 import java.awt.image.BufferedImage;
-import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FileFilter;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
+import java.io.FilterInputStream;
 import java.io.IOException;
+import java.net.URL;
 import java.util.List;
 import java.util.Locale;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
 
 import javax.imageio.ImageIO;
 
@@ -55,55 +58,70 @@ public class TestHwmfParsing {
 
     @Test
     @Ignore
-    public void extract() throws IOException {
-        File dir = new File("test-data/slideshow");
-        File files[] = dir.listFiles(new FileFilter() {
-            public boolean accept(File pathname) {
-                return pathname.getName().matches("(?i).*\\.pptx?$");
-            }
-        });
-
-        boolean outputFiles = false;
-
+    public void fetchWmfFromGovdocs() throws IOException {
+        URL url = new URL("http://digitalcorpora.org/corpora/files/govdocs1/by_type/ppt.zip");
         File outdir = new File("build/ppt");
-        if (outputFiles) {
-            outdir.mkdirs();
-        }
-        int wmfIdx = 1;
-        for (File f : files) {
+        outdir.mkdirs();
+        ZipInputStream zis = new ZipInputStream(url.openStream());
+        ZipEntry ze;
+        while ((ze = zis.getNextEntry()) != null) {
+            String basename = ze.getName().replaceAll(".*?([^/]+)\\.wmf", "$1");
+            FilterInputStream fis = new FilterInputStream(zis){
+                public void close() throws IOException {}
+            };
             try {
-                SlideShow<?,?> ss = SlideShowFactory.create(f);
+                SlideShow<?,?> ss = SlideShowFactory.create(fis);
+                int wmfIdx = 1;
                 for (PictureData pd : ss.getPictureData()) {
                     if (pd.getType() != PictureType.WMF) continue;
                     byte wmfData[] = pd.getData();
-                    if (outputFiles) {
-                        String filename = String.format(Locale.ROOT, "pic%04d.wmf", wmfIdx);
-                        FileOutputStream fos = new FileOutputStream(new File(outdir, filename));
-                        fos.write(wmfData);
-                        fos.close();
-                    }
-
-                    HwmfPicture wmf = new HwmfPicture(new ByteArrayInputStream(wmfData));
-
-                    int bmpIndex = 1;
-                    for (HwmfRecord r : wmf.getRecords()) {
-                        if (r instanceof HwmfImageRecord) {
-                            BufferedImage bi = ((HwmfImageRecord)r).getImage();
-                            if (outputFiles) {
-                                String filename = String.format(Locale.ROOT, "pic%04d-%04d.png", wmfIdx, bmpIndex);
-                                ImageIO.write(bi, "PNG", new File(outdir, filename));
-                            }
-                            bmpIndex++;
-                        }
-                    }
-
+                    String filename = String.format(Locale.ROOT, "%s-%04d.wmf", basename, wmfIdx);
+                    FileOutputStream fos = new FileOutputStream(new File(outdir, filename));
+                    fos.write(wmfData);
+                    fos.close();
                     wmfIdx++;
                 }
                 ss.close();
             } catch (Exception e) {
-                System.out.println(f+" ignored.");
+                System.out.println(ze.getName()+" ignored.");
+            }
+        }
+    }
+    
+    @Test
+    @Ignore
+    public void parseWmfs() throws IOException {
+        boolean outputFiles = false;
+        File indir = new File("build/ppt"), outdir = indir;
+        final String startFile = "";
+        File files[] = indir.listFiles(new FileFilter() {
+            boolean foundStartFile = false;
+            public boolean accept(File pathname) {
+                foundStartFile |= startFile.isEmpty() || pathname.getName().contains(startFile);
+                return foundStartFile && pathname.getName().matches("(?i).*\\.wmf?$");
+            }
+        });
+        for (File f : files) {
+            try {
+                String basename = f.getName().replaceAll(".*?([^/]+)\\.wmf", "$1");
+                FileInputStream fis = new FileInputStream(f);
+                HwmfPicture wmf = new HwmfPicture(fis);
+                fis.close();
+                
+                int bmpIndex = 1;
+                for (HwmfRecord r : wmf.getRecords()) {
+                    if (r instanceof HwmfImageRecord) {
+                        BufferedImage bi = ((HwmfImageRecord)r).getImage();
+                        if (bi != null && outputFiles) {
+                            String filename = String.format(Locale.ROOT, "%s-%04d.png", basename, bmpIndex);
+                            ImageIO.write(bi, "PNG", new File(outdir, filename));
+                        }
+                        bmpIndex++;
+                    }
+                }
+            } catch (Exception e) {
+                System.out.println(f.getName()+" ignored.");                
             }
         }
     }
-
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org