diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index af03d5562c..0c6acd0ce8 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,6 +34,7 @@ + 51335 - Parse picture goal and crop sizes in HWPF 51305 - Add sprmTCellPaddingDefault support in HWPF 51265 - Enhanced Handling of Picture Parts in XWPF 51292 - Additional HWPF Table Cell Descriptor values diff --git a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Picture.java b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Picture.java index 230bc57919..995e8ec067 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Picture.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Picture.java @@ -41,7 +41,14 @@ public final class Picture static final int PICT_HEADER_OFFSET = 0x4; static final int MFPMM_OFFSET = 0x6; static final int PICF_SHAPE_OFFSET = 0xE; - static final int PICMD_OFFSET = 0x1C; + static final int DXAGOAL_OFFSET = 0x1C; + static final int DYAGOAL_OFFSET = 0x1E; + static final int MX_OFFSET = 0x20; + static final int MY_OFFSET = 0x22; + static final int DXACROPLEFT_OFFSET = 0x24; + static final int DYACROPTOP_OFFSET = 0x26; + static final int DXACROPRIGHT_OFFSET = 0x28; + static final int DYACROPBOTTOM_OFFSET = 0x2A; static final int UNKNOWN_HEADER_SIZE = 0x49; public static final byte[] GIF = new byte[]{'G', 'I', 'F'}; @@ -74,6 +81,13 @@ public final class Picture private int height = -1; private int width = -1; + private int dxaGoal = -1; + private int dyaGoal = -1; + + private int dxaCropLeft = -1; + private int dyaCropTop = -1; + private int dxaCropRight = -1; + private int dyaCropBottom = -1; public Picture(int dataBlockStartOfsset, byte[] _dataStream, boolean fillBytes) { @@ -87,8 +101,16 @@ public final class Picture } - this.aspectRatioX = extractAspectRatioX(_dataStream, dataBlockStartOfsset); - this.aspectRatioY = extractAspectRatioY(_dataStream, dataBlockStartOfsset); + this.dxaGoal = LittleEndian.getShort(_dataStream, dataBlockStartOfsset+DXAGOAL_OFFSET); + this.dyaGoal = LittleEndian.getShort(_dataStream, dataBlockStartOfsset+DYAGOAL_OFFSET); + + this.aspectRatioX = LittleEndian.getShort(_dataStream, dataBlockStartOfsset+MX_OFFSET)/10; + this.aspectRatioY = LittleEndian.getShort(_dataStream, dataBlockStartOfsset+MY_OFFSET)/10; + + this.dxaCropLeft = LittleEndian.getShort(_dataStream, dataBlockStartOfsset+DXACROPLEFT_OFFSET); + this.dyaCropTop = LittleEndian.getShort(_dataStream, dataBlockStartOfsset+DYACROPTOP_OFFSET); + this.dxaCropRight = LittleEndian.getShort(_dataStream, dataBlockStartOfsset+DXACROPRIGHT_OFFSET); + this.dyaCropBottom = LittleEndian.getShort(_dataStream, dataBlockStartOfsset+DYACROPBOTTOM_OFFSET); if (fillBytes) { @@ -116,16 +138,6 @@ public final class Picture } } - private static int extractAspectRatioX(byte[] _dataStream, int dataBlockStartOffset) - { - return LittleEndian.getShort(_dataStream, dataBlockStartOffset+0x20)/10; - } - - private static int extractAspectRatioY(byte[] _dataStream, int dataBlockStartOffset) - { - return LittleEndian.getShort(_dataStream, dataBlockStartOffset+0x22)/10; - } - /** * Tries to suggest a filename: hex representation of picture structure offset in "Data" stream plus extension that * is tried to determine from first byte of picture's content. @@ -154,7 +166,7 @@ public final class Picture out.write(_dataStream, pictureBytesStartOffset, size); } } - + /** * @return The offset of this picture in the picture bytes, used * when matching up with {@link CharacterRun#getPicOffset()} @@ -193,22 +205,67 @@ public final class Picture return size; } - /** - * returns horizontal aspect ratio for picture provided by user - */ - public int getAspectRatioX() - { - return aspectRatioX; - } - /** - * returns vertical aspect ratio for picture provided by user - */ - public int getAspectRatioY() - { - return aspectRatioY; - } + /** + * @return the horizontal aspect ratio for picture provided by user + */ + public int getAspectRatioX() { + return aspectRatioX; + } - /** + /** + * @retrn the vertical aspect ratio for picture provided by user + */ + public int getAspectRatioY() { + return aspectRatioY; + } + + /** + * Gets the initial width of the picture, in twips, prior to cropping or scaling. + * + * @return the initial width of the picture in twips + */ + public int getDxaGoal() { + return dxaGoal; + } + + /** + * Gets the initial height of the picture, in twips, prior to cropping or scaling. + * + * @return the initial width of the picture in twips + */ + public int getDyaGoal() { + return dyaGoal; + } + + /** + * @return The amount the picture has been cropped on the left in twips + */ + public int getDxaCropLeft() { + return dxaCropLeft; + } + + /** + * @return The amount the picture has been cropped on the top in twips + */ + public int getDyaCropTop() { + return dyaCropTop; + } + + /** + * @return The amount the picture has been cropped on the right in twips + */ + public int getDxaCropRight() { + return dxaCropRight; + } + + /** + * @return The amount the picture has been cropped on the bottom in twips + */ + public int getDyaCropBottom() { + return dyaCropBottom; + } + + /** * tries to suggest extension for picture's file by matching signatures of popular image formats to first bytes * of picture's contents * @return suggested file extension @@ -222,7 +279,7 @@ public final class Picture } return extension; } - + /** * Returns the mime type for the image */ @@ -361,10 +418,10 @@ public final class Picture { int realPicoffset = dataBlockStartOffset; final int dataBlockEndOffset = dataBlockSize + dataBlockStartOffset; - + // Skip over the PICT block int PICTFBlockSize = LittleEndian.getShort(_dataStream, dataBlockStartOffset +PICT_HEADER_OFFSET); // Should be 68 bytes - + // Now the PICTF1 int PICTF1BlockOffset = PICTFBlockSize + PICT_HEADER_OFFSET; short MM_TYPE = LittleEndian.getShort(_dataStream, dataBlockStartOffset + PICT_HEADER_OFFSET + 2); diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestPictures.java b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestPictures.java index fbc5bb3576..bd2d6a67ed 100644 --- a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestPictures.java +++ b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestPictures.java @@ -302,4 +302,34 @@ public final class TestPictures extends TestCase { assertEquals(4, escher8s); assertEquals(0, plain8s); } + + public void testCroppedPictures() { + HWPFDocument doc = HWPFTestDataSamples.openSampleFile("testCroppedPictures.doc"); + List pics = doc.getPicturesTable().getAllPictures(); + + assertNotNull(pics); + assertEquals(2, pics.size()); + + Picture pic1 = pics.get(0); + assertEquals(27, pic1.getAspectRatioX()); + assertEquals(27, pic1.getAspectRatioY()); + assertEquals(12000, pic1.getDxaGoal()); // 21.17 cm / 2.54 cm/inch * 72dpi * 20 = 12000 + assertEquals(9000, pic1.getDyaGoal()); // 15.88 cm / 2.54 cm/inch * 72dpi * 20 = 9000 + assertEquals(0, pic1.getDxaCropLeft()); + assertEquals(0, pic1.getDxaCropRight()); + assertEquals(0, pic1.getDyaCropTop()); + assertEquals(0, pic1.getDyaCropBottom()); + + Picture pic2 = pics.get(1); + System.out.println(pic2.getWidth()); + assertEquals(76, pic2.getAspectRatioX()); + assertEquals(68, pic2.getAspectRatioY()); + assertEquals(12000, pic2.getDxaGoal()); // 21.17 cm / 2.54 cm/inch * 72dpi * 20 = 12000 + assertEquals(9000, pic2.getDyaGoal()); // 15.88 cm / 2.54 cm/inch * 72dpi * 20 = 9000 + assertEquals(0, pic2.getDxaCropLeft()); // TODO YK: The Picture is cropped but HWPF reads the crop parameters all zeros + assertEquals(0, pic2.getDxaCropRight()); + assertEquals(0, pic2.getDyaCropTop()); + assertEquals(0, pic2.getDyaCropBottom()); + } + } diff --git a/test-data/document/testCroppedPictures.doc b/test-data/document/testCroppedPictures.doc new file mode 100644 index 0000000000..2f8b5622c1 Binary files /dev/null and b/test-data/document/testCroppedPictures.doc differ