123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277 |
- /* ====================================================================
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- ==================================================================== */
- package org.apache.poi.ss.util;
-
- import static org.apache.poi.util.Units.EMU_PER_PIXEL;
-
- import java.awt.Dimension;
- import java.awt.image.BufferedImage;
- import java.io.ByteArrayInputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.util.Iterator;
-
- import javax.imageio.ImageIO;
- import javax.imageio.ImageReader;
- import javax.imageio.stream.ImageInputStream;
-
- import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
- import org.apache.poi.ss.usermodel.ClientAnchor;
- import org.apache.poi.ss.usermodel.Picture;
- import org.apache.poi.ss.usermodel.PictureData;
- import org.apache.poi.ss.usermodel.Row;
- import org.apache.poi.ss.usermodel.Sheet;
- import org.apache.poi.ss.usermodel.Workbook;
- import org.apache.poi.util.POILogFactory;
- import org.apache.poi.util.POILogger;
- import org.apache.poi.util.Units;
- import org.w3c.dom.Element;
- import org.w3c.dom.NodeList;
-
- /**
- * @author Yegor Kozlov
- */
- public class ImageUtils {
- private static final POILogger logger = POILogFactory.getLogger(ImageUtils.class);
-
- public static final int PIXEL_DPI = 96;
-
- /**
- * Return the dimension of this image
- *
- * @param is the stream containing the image data
- * @param type type of the picture: {@link org.apache.poi.ss.usermodel.Workbook#PICTURE_TYPE_JPEG},
- * {@link org.apache.poi.ss.usermodel.Workbook#PICTURE_TYPE_PNG} or {@link org.apache.poi.ss.usermodel.Workbook#PICTURE_TYPE_DIB}
- *
- * @return image dimension in pixels
- */
- public static Dimension getImageDimension(InputStream is, int type){
- Dimension size = new Dimension();
-
- switch (type){
- //we can calculate the preferred size only for JPEG, PNG and BMP
- //other formats like WMF, EMF and PICT are not supported in Java
- case Workbook.PICTURE_TYPE_JPEG:
- case Workbook.PICTURE_TYPE_PNG:
- case Workbook.PICTURE_TYPE_DIB:
- try {
- //read the image using javax.imageio.*
- ImageInputStream iis = ImageIO.createImageInputStream( is );
- Iterator<ImageReader> i = ImageIO.getImageReaders( iis );
- ImageReader r = i.next();
- r.setInput( iis );
- BufferedImage img = r.read(0);
-
- int[] dpi = getResolution(r);
-
- //if DPI is zero then assume standard 96 DPI
- //since cannot divide by zero
- if (dpi[0] == 0) dpi[0] = PIXEL_DPI;
- if (dpi[1] == 0) dpi[1] = PIXEL_DPI;
-
- size.width = img.getWidth()*PIXEL_DPI/dpi[0];
- size.height = img.getHeight()*PIXEL_DPI/dpi[1];
-
- r.dispose();
- iis.close();
-
- } catch (IOException e){
- //silently return if ImageIO failed to read the image
- logger.log(POILogger.WARN, e);
- }
-
- break;
- default:
- logger.log(POILogger.WARN, "Only JPEG, PNG and DIB pictures can be automatically sized");
- }
- return size;
- }
-
- /**
- * The metadata of PNG and JPEG can contain the width of a pixel in millimeters.
- * Return the the "effective" dpi calculated as <code>25.4/HorizontalPixelSize</code>
- * and <code>25.4/VerticalPixelSize</code>. Where 25.4 is the number of mm in inch.
- *
- * @return array of two elements: <code>{horisontalPdi, verticalDpi}</code>.
- * {96, 96} is the default.
- */
- public static int[] getResolution(ImageReader r) throws IOException {
- int hdpi=96, vdpi=96;
- double mm2inch = 25.4;
-
- NodeList lst;
- Element node = (Element)r.getImageMetadata(0).getAsTree("javax_imageio_1.0");
- lst = node.getElementsByTagName("HorizontalPixelSize");
- if(lst != null && lst.getLength() == 1) hdpi = (int)(mm2inch/Float.parseFloat(((Element)lst.item(0)).getAttribute("value")));
-
- lst = node.getElementsByTagName("VerticalPixelSize");
- if(lst != null && lst.getLength() == 1) vdpi = (int)(mm2inch/Float.parseFloat(((Element)lst.item(0)).getAttribute("value")));
-
- return new int[]{hdpi, vdpi};
- }
-
- /**
- * Calculate and set the preferred size (anchor) for this picture.
- *
- * @param scaleX the amount by which image width is multiplied relative to the original width.
- * @param scaleY the amount by which image height is multiplied relative to the original height.
- * @return the new Dimensions of the scaled picture in EMUs
- */
- public static Dimension setPreferredSize(Picture picture, double scaleX, double scaleY){
- ClientAnchor anchor = picture.getClientAnchor();
- boolean isHSSF = (anchor instanceof HSSFClientAnchor);
- PictureData data = picture.getPictureData();
- Sheet sheet = picture.getSheet();
-
- // in pixel
- Dimension imgSize = getImageDimension(new ByteArrayInputStream(data.getData()), data.getPictureType());
- // in emus
- Dimension anchorSize = ImageUtils.getDimensionFromAnchor(picture);
- final double scaledWidth = (scaleX == Double.MAX_VALUE)
- ? imgSize.getWidth() : anchorSize.getWidth()/EMU_PER_PIXEL * scaleX;
- final double scaledHeight = (scaleY == Double.MAX_VALUE)
- ? imgSize.getHeight() : anchorSize.getHeight()/EMU_PER_PIXEL * scaleY;
-
- double w = 0;
- int col2 = anchor.getCol1();
- int dx2 = 0;
-
- //space in the leftmost cell
- w = sheet.getColumnWidthInPixels(col2++);
- if (isHSSF) {
- w *= 1 - anchor.getDx1()/1024d;
- } else {
- w -= anchor.getDx1()/EMU_PER_PIXEL;
- }
-
- while(w < scaledWidth){
- w += sheet.getColumnWidthInPixels(col2++);
- }
-
- if(w > scaledWidth) {
- //calculate dx2, offset in the rightmost cell
- double cw = sheet.getColumnWidthInPixels(--col2);
- double delta = w - scaledWidth;
- if (isHSSF) {
- dx2 = (int)((cw-delta)/cw*1024);
- } else {
- dx2 = (int)((cw-delta)*EMU_PER_PIXEL);
- }
- if (dx2 < 0) dx2 = 0;
- }
- anchor.setCol2(col2);
- anchor.setDx2(dx2);
-
- double h = 0;
- int row2 = anchor.getRow1();
- int dy2 = 0;
-
- h = getRowHeightInPixels(sheet,row2++);
- if (isHSSF) {
- h *= 1 - anchor.getDy1()/256d;
- } else {
- h -= anchor.getDy1()/EMU_PER_PIXEL;
- }
-
- while(h < scaledHeight){
- h += getRowHeightInPixels(sheet,row2++);
- }
-
- if(h > scaledHeight) {
- double ch = getRowHeightInPixels(sheet,--row2);
- double delta = h - scaledHeight;
- if (isHSSF) {
- dy2 = (int)((ch-delta)/ch*256);
- } else {
- dy2 = (int)((ch-delta)*EMU_PER_PIXEL);
- }
- if (dy2 < 0) dy2 = 0;
- }
-
- anchor.setRow2(row2);
- anchor.setDy2(dy2);
-
- Dimension dim = new Dimension(
- (int)Math.round(scaledWidth*EMU_PER_PIXEL),
- (int)Math.round(scaledHeight*EMU_PER_PIXEL)
- );
-
- return dim;
- }
-
- /**
- * Calculates the dimensions in EMUs for the anchor of the given picture
- *
- * @param picture the picture containing the anchor
- * @return the dimensions in EMUs
- */
- public static Dimension getDimensionFromAnchor(Picture picture) {
- ClientAnchor anchor = picture.getClientAnchor();
- boolean isHSSF = (anchor instanceof HSSFClientAnchor);
- Sheet sheet = picture.getSheet();
-
- double w = 0;
- int col2 = anchor.getCol1();
-
- //space in the leftmost cell
- w = sheet.getColumnWidthInPixels(col2++);
- if (isHSSF) {
- w *= 1 - anchor.getDx1()/1024d;
- } else {
- w -= anchor.getDx1()/EMU_PER_PIXEL;
- }
-
- while(col2 < anchor.getCol2()){
- w += sheet.getColumnWidthInPixels(col2++);
- }
-
- if (isHSSF) {
- w += sheet.getColumnWidthInPixels(col2) * anchor.getDx2()/1024d;
- } else {
- w += anchor.getDx2()/EMU_PER_PIXEL;
- }
-
- double h = 0;
- int row2 = anchor.getRow1();
-
- h = getRowHeightInPixels(sheet,row2++);
- if (isHSSF) {
- h *= 1 - anchor.getDy1()/256d;
- } else {
- h -= anchor.getDy1()/EMU_PER_PIXEL;
- }
-
- while(row2 < anchor.getRow2()){
- h += getRowHeightInPixels(sheet,row2++);
- }
-
- if (isHSSF) {
- h += getRowHeightInPixels(sheet,row2) * anchor.getDy2()/256;
- } else {
- h += anchor.getDy2()/EMU_PER_PIXEL;
- }
-
- return new Dimension((int)w*EMU_PER_PIXEL, (int)h*EMU_PER_PIXEL);
- }
-
-
- private static double getRowHeightInPixels(Sheet sheet, int rowNum) {
- Row r = sheet.getRow(rowNum);
- double points = (r == null) ? sheet.getDefaultRowHeightInPoints() : r.getHeightInPoints();
- return Units.toEMU(points)/EMU_PER_PIXEL;
- }
- }
|