001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.poi.hssf.usermodel;
018:
019: import org.apache.poi.ddf.EscherBSERecord;
020: import org.apache.poi.util.POILogFactory;
021: import org.apache.poi.util.POILogger;
022: import org.w3c.dom.Element;
023: import org.w3c.dom.NodeList;
024:
025: import javax.imageio.ImageIO;
026: import javax.imageio.ImageReader;
027: import javax.imageio.stream.ImageInputStream;
028: import java.awt.image.BufferedImage;
029: import java.io.ByteArrayInputStream;
030: import java.io.IOException;
031: import java.util.Iterator;
032:
033: /**
034: * Represents a escher picture. Eg. A GIF, JPEG etc...
035: *
036: * @author Glen Stampoultzis
037: * @author Yegor Kozlov (yegor at apache.org)
038: */
039: public class HSSFPicture extends HSSFSimpleShape {
040: public static final int PICTURE_TYPE_EMF = HSSFWorkbook.PICTURE_TYPE_EMF; // Windows Enhanced Metafile
041: public static final int PICTURE_TYPE_WMF = HSSFWorkbook.PICTURE_TYPE_WMF; // Windows Metafile
042: public static final int PICTURE_TYPE_PICT = HSSFWorkbook.PICTURE_TYPE_PICT; // Macintosh PICT
043: public static final int PICTURE_TYPE_JPEG = HSSFWorkbook.PICTURE_TYPE_JPEG; // JFIF
044: public static final int PICTURE_TYPE_PNG = HSSFWorkbook.PICTURE_TYPE_PNG; // PNG
045: public static final int PICTURE_TYPE_DIB = HSSFWorkbook.PICTURE_TYPE_DIB; // Windows DIB
046:
047: int pictureIndex;
048: HSSFPatriarch patriarch;
049:
050: private static final POILogger log = POILogFactory
051: .getLogger(HSSFPicture.class);
052:
053: /**
054: * Constructs a picture object.
055: */
056: HSSFPicture(HSSFShape parent, HSSFAnchor anchor) {
057: super (parent, anchor);
058: setShapeType(OBJECT_TYPE_PICTURE);
059: }
060:
061: public int getPictureIndex() {
062: return pictureIndex;
063: }
064:
065: public void setPictureIndex(int pictureIndex) {
066: this .pictureIndex = pictureIndex;
067: }
068:
069: /**
070: * Reset the image to the original size.
071: *
072: * @since POI 3.0.2
073: */
074: public void resize() {
075: HSSFClientAnchor anchor = (HSSFClientAnchor) getAnchor();
076: anchor.setAnchorType(2);
077:
078: HSSFClientAnchor pref = getPreferredSize();
079:
080: int row2 = anchor.getRow1() + (pref.getRow2() - pref.getRow1());
081: int col2 = anchor.getCol1() + (pref.getCol2() - pref.getCol1());
082:
083: anchor.setCol2((short) col2);
084: anchor.setDx1(0);
085: anchor.setDx2(pref.getDx2());
086:
087: anchor.setRow2(row2);
088: anchor.setDy1(0);
089: anchor.setDy2(pref.getDy2());
090: }
091:
092: /**
093: * Calculate the preferred size for this picture.
094: *
095: * @return HSSFClientAnchor with the preferred size for this image
096: * @since POI 3.0.2
097: */
098: public HSSFClientAnchor getPreferredSize() {
099: HSSFClientAnchor anchor = new HSSFClientAnchor();
100:
101: EscherBSERecord bse = (EscherBSERecord) patriarch.sheet.book
102: .getBSERecord(pictureIndex);
103: byte[] data = bse.getBlipRecord().getPicturedata();
104: int type = bse.getBlipTypeWin32();
105: switch (type) {
106: //we can calculate the preferred size only for JPEG and PNG
107: //other formats like WMF, EMF and PICT are not supported in Java
108: case HSSFWorkbook.PICTURE_TYPE_JPEG:
109: case HSSFWorkbook.PICTURE_TYPE_PNG:
110: BufferedImage img = null;
111: ImageReader r = null;
112: try {
113: //read the image using javax.imageio.*
114: ImageInputStream iis = ImageIO
115: .createImageInputStream(new ByteArrayInputStream(
116: data));
117: Iterator i = ImageIO.getImageReaders(iis);
118: r = (ImageReader) i.next();
119: r.setInput(iis);
120: img = r.read(0);
121:
122: int[] dpi = getResolution(r);
123: int imgWidth = img.getWidth() * 96 / dpi[0];
124: int imgHeight = img.getHeight() * 96 / dpi[1];
125:
126: //Excel measures cells in units of 1/256th of a character width.
127: //The cell width calculated based on this info is always "off".
128: //A better approach seems to be to use empirically obtained cell width and row height
129: int cellwidth = 64;
130: int rowheight = 17;
131:
132: int col2 = imgWidth / cellwidth;
133: int row2 = imgHeight / rowheight;
134:
135: int dx2 = (int) ((float) (imgWidth % cellwidth)
136: / cellwidth * 1024);
137: int dy2 = (int) ((float) (imgHeight % rowheight)
138: / rowheight * 256);
139:
140: anchor.setCol2((short) col2);
141: anchor.setDx2(dx2);
142:
143: anchor.setRow2(row2);
144: anchor.setDy2(dy2);
145:
146: } catch (IOException e) {
147: //silently return if ImageIO failed to read the image
148: log.log(POILogger.WARN, e);
149: img = null;
150: }
151:
152: break;
153: }
154: return anchor;
155: }
156:
157: /**
158: * The metadata of PNG and JPEG can contain the width of a pixel in millimeters.
159: * Return the the "effective" dpi calculated as <code>25.4/HorizontalPixelSize</code>
160: * and <code>25.4/VerticalPixelSize</code>. Where 25.4 is the number of mm in inch.
161: *
162: * @return array of two elements: <code>{horisontalPdi, verticalDpi}</code>.
163: * {96, 96} is the default.
164: */
165: protected int[] getResolution(ImageReader r) throws IOException {
166: int hdpi = 96, vdpi = 96;
167: double mm2inch = 25.4;
168:
169: NodeList lst;
170: Element node = (Element) r.getImageMetadata(0).getAsTree(
171: "javax_imageio_1.0");
172: lst = node.getElementsByTagName("HorizontalPixelSize");
173: if (lst != null && lst.getLength() == 1)
174: hdpi = (int) (mm2inch / Float.parseFloat(((Element) lst
175: .item(0)).getAttribute("value")));
176:
177: lst = node.getElementsByTagName("VerticalPixelSize");
178: if (lst != null && lst.getLength() == 1)
179: vdpi = (int) (mm2inch / Float.parseFloat(((Element) lst
180: .item(0)).getAttribute("value")));
181:
182: return new int[] { hdpi, vdpi };
183: }
184:
185: }
|