--- /dev/null
+/**\r
+ * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.\r
+ *\r
+ * This library is free software; you can redistribute it and/or modify it under\r
+ * the terms of the GNU Lesser General Public License as published by the Free\r
+ * Software Foundation; either version 2.1 of the License, or (at your option)\r
+ * any later version.\r
+ *\r
+ * This library is distributed in the hope that it will be useful, but WITHOUT\r
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\r
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more\r
+ * details.\r
+ */\r
+\r
+package com.liferay.portal.image;\r
+\r
+import com.liferay.portal.kernel.image.ImageBag;\r
+import com.liferay.portal.kernel.image.ImageTool;\r
+import com.liferay.portal.kernel.image.ImageToolUtil;\r
+import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayInputStream;\r
+import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayOutputStream;\r
+import com.liferay.portal.kernel.log.Log;\r
+import com.liferay.portal.kernel.log.LogFactoryUtil;\r
+import com.liferay.portal.kernel.util.JavaDetector;\r
+import com.liferay.portal.kernel.util.StringBundler;\r
+import com.liferay.portal.util.FileImpl;\r
+\r
+import com.sun.media.jai.codec.ImageCodec;\r
+import com.sun.media.jai.codec.ImageDecoder;\r
+import com.sun.media.jai.codec.ImageEncoder;\r
+\r
+import java.awt.Graphics2D;\r
+import java.awt.Graphics;\r
+import java.awt.Image;\r
+import java.awt.image.BufferedImage;\r
+import java.awt.image.DataBuffer;\r
+import java.awt.image.IndexColorModel;\r
+import java.awt.image.RenderedImage;\r
+import java.awt.image.SampleModel;\r
+import java.awt.image.WritableRaster;\r
+import java.io.ByteArrayInputStream;\r
+import java.io.File;\r
+import java.io.IOException;\r
+import java.io.OutputStream;\r
+import java.util.Iterator;\r
+import java.util.LinkedList;\r
+import java.util.Queue;\r
+\r
+import javax.imageio.ImageIO;\r
+import javax.imageio.ImageReader;\r
+import javax.imageio.stream.ImageInputStream;\r
+import javax.media.jai.RenderedImageAdapter;\r
+\r
+import net.jmge.gif.Gif89Encoder;\r
+\r
+/**\r
+ * @author Brian Wing Shun Chan\r
+ */\r
+public class ImageToolImpl implements ImageTool {\r
+\r
+ public static ImageTool getInstance() {\r
+ return _instance;\r
+ }\r
+\r
+ public BufferedImage convertImageType(BufferedImage sourceImage, int type) {\r
+ BufferedImage targetImage = new BufferedImage(\r
+ sourceImage.getWidth(), sourceImage.getHeight(), type);\r
+\r
+ Graphics2D graphics = targetImage.createGraphics();\r
+\r
+ graphics.drawRenderedImage(sourceImage, null);\r
+\r
+ graphics.dispose();\r
+\r
+ return targetImage;\r
+ }\r
+\r
+ public void encodeGIF(RenderedImage renderedImage, OutputStream os)\r
+ throws IOException {\r
+\r
+ if (JavaDetector.isJDK6()) {\r
+ try {\r
+ ImageIO.write(renderedImage, TYPE_GIF, os);\r
+ }\r
+ catch (Exception e){\r
+ ImageIO.write(renderedImage, TYPE_PNG, os);\r
+ }\r
+ }\r
+ else {\r
+ BufferedImage bufferedImage = getBufferedImage(renderedImage);\r
+\r
+ if (!(bufferedImage.getColorModel() instanceof IndexColorModel)) {\r
+ bufferedImage = convertImageType(\r
+ bufferedImage, BufferedImage.TYPE_BYTE_INDEXED);\r
+ }\r
+\r
+ Gif89Encoder encoder = new Gif89Encoder(bufferedImage);\r
+\r
+ encoder.encode(os);\r
+ }\r
+ }\r
+\r
+ public void encodeWBMP(RenderedImage renderedImage, OutputStream os)\r
+ throws IOException {\r
+\r
+ BufferedImage bufferedImage = getBufferedImage(renderedImage);\r
+\r
+ SampleModel sampleModel = bufferedImage.getSampleModel();\r
+\r
+ int type = sampleModel.getDataType();\r
+\r
+ if ((bufferedImage.getType() != BufferedImage.TYPE_BYTE_BINARY) ||\r
+ (type < DataBuffer.TYPE_BYTE) || (type > DataBuffer.TYPE_INT) ||\r
+ (sampleModel.getNumBands() != 1) ||\r
+ (sampleModel.getSampleSize(0) != 1)) {\r
+\r
+ BufferedImage binaryImage = new BufferedImage(\r
+ bufferedImage.getWidth(), bufferedImage.getHeight(),\r
+ BufferedImage.TYPE_BYTE_BINARY);\r
+\r
+ Graphics graphics = binaryImage.getGraphics();\r
+\r
+ graphics.drawImage(bufferedImage, 0, 0, null);\r
+\r
+ renderedImage = binaryImage;\r
+ }\r
+\r
+ if (!ImageIO.write(renderedImage, "wbmp", os)) {\r
+\r
+ // See http://www.jguru.com/faq/view.jsp?EID=127723\r
+\r
+ os.write(0);\r
+ os.write(0);\r
+ os.write(_toMultiByte(bufferedImage.getWidth()));\r
+ os.write(_toMultiByte(bufferedImage.getHeight()));\r
+\r
+ DataBuffer dataBuffer = bufferedImage.getData().getDataBuffer();\r
+\r
+ int size = dataBuffer.getSize();\r
+\r
+ for (int i = 0; i < size; i++) {\r
+ os.write((byte)dataBuffer.getElem(i));\r
+ }\r
+ }\r
+ }\r
+\r
+ public BufferedImage getBufferedImage(RenderedImage renderedImage) {\r
+ if (renderedImage instanceof BufferedImage) {\r
+ return (BufferedImage)renderedImage;\r
+ }\r
+ else {\r
+ RenderedImageAdapter adapter = new RenderedImageAdapter(\r
+ renderedImage);\r
+\r
+ return adapter.getAsBufferedImage();\r
+ }\r
+ }\r
+\r
+ public byte[] getBytes(RenderedImage renderedImage, String contentType)\r
+ throws IOException {\r
+\r
+ UnsyncByteArrayOutputStream baos = new UnsyncByteArrayOutputStream();\r
+\r
+ write(renderedImage, contentType, baos);\r
+\r
+ return baos.toByteArray();\r
+ }\r
+\r
+ public ImageBag read(byte[] bytes) {\r
+\r
+// // Here the old way was using com.sun.jai package, which is only included in sun jdk.\r
+// // Now we use standard java\r
+\r
+ String formatName = null;\r
+ ImageInputStream imageInputStream = null;\r
+ Queue<ImageReader> imageReaders = new LinkedList<ImageReader>();\r
+ RenderedImage renderedImage = null;\r
+\r
+ try {\r
+ imageInputStream = ImageIO.createImageInputStream(new ByteArrayInputStream(bytes));\r
+\r
+ Iterator<ImageReader> iterator = ImageIO.getImageReaders(imageInputStream);\r
+\r
+ while ((renderedImage == null) && iterator.hasNext()) {\r
+ ImageReader imageReader = iterator.next();\r
+\r
+ imageReaders.offer(imageReader);\r
+\r
+ try {\r
+ imageReader.setInput(imageInputStream);\r
+\r
+ int height = imageReader.getHeight(0);\r
+ int width = imageReader.getWidth(0);\r
+\r
+ if (height > 1080 || width > 1920) {\r
+\r
+ StringBundler sb = new StringBundler(9);\r
+\r
+ sb.append("Image's dimensions (");\r
+ sb.append(height);\r
+ sb.append(" px high and ");\r
+ sb.append(width);\r
+ sb.append(" px wide) exceed max dimensions (");\r
+ sb.append("1080");\r
+ sb.append(" px high and ");\r
+ sb.append("1920");\r
+ sb.append(" px wide)");\r
+\r
+ throw new Exception(sb.toString());\r
+ }\r
+\r
+ renderedImage = imageReader.read(0);\r
+ }\r
+ catch (IOException ioe) {\r
+ continue;\r
+ }\r
+\r
+ formatName = imageReader.getFormatName().toLowerCase();\r
+ }\r
+\r
+ } catch (Exception e) {\r
+ _log.error("Error in image read");\r
+ }\r
+ finally {\r
+ while (!imageReaders.isEmpty()) {\r
+ ImageReader imageReader = imageReaders.poll();\r
+ imageReader.dispose();\r
+ }\r
+ if (imageInputStream != null) {\r
+ try {\r
+ imageInputStream.close();\r
+ } catch (Exception e) {\r
+ }\r
+ }\r
+ }\r
+\r
+ String type = TYPE_JPEG;\r
+ if (formatName == null || formatName.isEmpty()) {\r
+ type = TYPE_NOT_AVAILABLE;\r
+ } else if (formatName.contains(TYPE_BMP)) {\r
+ type = TYPE_BMP;\r
+ }\r
+ else if (formatName.contains(TYPE_GIF)) {\r
+ type = TYPE_GIF;\r
+ }\r
+ else if (formatName.contains("jpeg") || formatName.contains("jpg") || type.equalsIgnoreCase("jpeg")) {\r
+ type = TYPE_JPEG;\r
+ }\r
+ else if (formatName.contains(TYPE_PNG)) {\r
+ type = TYPE_PNG;\r
+ }\r
+ else if (formatName.contains(TYPE_TIFF)) {\r
+ type = TYPE_TIFF;\r
+ }\r
+ else {\r
+ throw new IllegalArgumentException("Image type " + type + " is not supported");\r
+ }\r
+\r
+ if (renderedImage == null) {\r
+ _log.error("Image could not be rendered");\r
+ return null;\r
+ }\r
+\r
+ return new ImageBag(renderedImage, type);\r
+\r
+ }\r
+\r
+ public ImageBag read(File file) throws IOException {\r
+ return read(_fileUtil.getBytes(file));\r
+ }\r
+\r
+ public RenderedImage scale(RenderedImage renderedImage, int width) {\r
+ if (width <= 0) {\r
+ return renderedImage;\r
+ }\r
+\r
+ int imageHeight = renderedImage.getHeight();\r
+ int imageWidth = renderedImage.getWidth();\r
+\r
+ double factor = (double) width / imageWidth;\r
+\r
+ int scaledHeight = (int)(factor * imageHeight);\r
+ int scaledWidth = width;\r
+\r
+ BufferedImage bufferedImage = getBufferedImage(renderedImage);\r
+\r
+ int type = bufferedImage.getType();\r
+\r
+ if (type == 0) {\r
+ type = BufferedImage.TYPE_INT_ARGB;\r
+ }\r
+\r
+ BufferedImage scaledBufferedImage = new BufferedImage(\r
+ scaledWidth, scaledHeight, type);\r
+\r
+ Graphics graphics = scaledBufferedImage.getGraphics();\r
+\r
+ Image scaledImage = bufferedImage.getScaledInstance(\r
+ scaledWidth, scaledHeight, Image.SCALE_SMOOTH);\r
+\r
+ graphics.drawImage(scaledImage, 0, 0, null);\r
+\r
+ return scaledBufferedImage;\r
+ }\r
+\r
+ public RenderedImage scale(\r
+ RenderedImage renderedImage, int maxHeight, int maxWidth) {\r
+\r
+ int imageHeight = renderedImage.getHeight();\r
+ int imageWidth = renderedImage.getWidth();\r
+\r
+ if (maxHeight == 0) {\r
+ maxHeight = imageHeight;\r
+ }\r
+\r
+ if (maxWidth == 0) {\r
+ maxWidth = imageWidth;\r
+ }\r
+\r
+ if ((imageHeight <= maxHeight) && (imageWidth <= maxWidth)) {\r
+ return renderedImage;\r
+ }\r
+\r
+ double factor = Math.min(\r
+ (double)maxHeight / imageHeight, (double)maxWidth / imageWidth);\r
+\r
+ int scaledHeight = Math.max(1, (int)(factor * imageHeight));\r
+ int scaledWidth = Math.max(1, (int)(factor * imageWidth));\r
+\r
+ BufferedImage bufferedImage = getBufferedImage(renderedImage);\r
+\r
+ int type = bufferedImage.getType();\r
+\r
+ if (type == 0) {\r
+ type = BufferedImage.TYPE_INT_ARGB;\r
+ }\r
+\r
+ BufferedImage scaledBufferedImage = null;\r
+\r
+ if ((type == BufferedImage.TYPE_BYTE_BINARY) ||\r
+ (type == BufferedImage.TYPE_BYTE_INDEXED)) {\r
+\r
+ IndexColorModel indexColorModel =\r
+ (IndexColorModel)bufferedImage.getColorModel();\r
+\r
+ BufferedImage tempBufferedImage = new BufferedImage(\r
+ 1, 1, type, indexColorModel);\r
+\r
+ int bits = indexColorModel.getPixelSize();\r
+ int size = indexColorModel.getMapSize();\r
+\r
+ byte[] reds = new byte[size];\r
+\r
+ indexColorModel.getReds(reds);\r
+\r
+ byte[] greens = new byte[size];\r
+\r
+ indexColorModel.getGreens(greens);\r
+\r
+ byte[] blues = new byte[size];\r
+\r
+ indexColorModel.getBlues(blues);\r
+\r
+ WritableRaster writableRaster = tempBufferedImage.getRaster();\r
+\r
+ int pixel = writableRaster.getSample(0, 0, 0);\r
+\r
+ IndexColorModel scaledIndexColorModel = new IndexColorModel(\r
+ bits, size, reds, greens, blues, pixel);\r
+\r
+ scaledBufferedImage = new BufferedImage(\r
+ scaledWidth, scaledHeight, type, scaledIndexColorModel);\r
+ }\r
+ else {\r
+ scaledBufferedImage = new BufferedImage(\r
+ scaledWidth, scaledHeight, type);\r
+ }\r
+\r
+ Graphics graphics = scaledBufferedImage.getGraphics();\r
+\r
+ Image scaledImage = bufferedImage.getScaledInstance(\r
+ scaledWidth, scaledHeight, Image.SCALE_SMOOTH);\r
+\r
+ graphics.drawImage(scaledImage, 0, 0, null);\r
+\r
+ return scaledBufferedImage;\r
+ }\r
+\r
+ public void write(\r
+ RenderedImage renderedImage, String contentType, OutputStream os)\r
+ throws IOException {\r
+\r
+// // Here the old way was using com.sun.jai package, which is only included in sun jdk.\r
+// // Now we use standard java\r
+\r
+ if (contentType.contains(TYPE_BMP)) {\r
+ ImageIO.write(renderedImage, "bmp", os);\r
+ }\r
+ else if (contentType.contains(TYPE_GIF)) {\r
+ encodeGIF(renderedImage, os);\r
+ }\r
+ else if (contentType.contains(TYPE_JPEG) || contentType.contains("jpeg")) {\r
+ ImageIO.write(renderedImage, "jpeg", os);\r
+ }\r
+ else if (contentType.contains(TYPE_PNG)) {\r
+ ImageIO.write(renderedImage, TYPE_PNG, os);\r
+ }\r
+ else if (contentType.contains(TYPE_TIFF) || contentType.contains("tif")) {\r
+ ImageIO.write(renderedImage, "tiff", os);\r
+ }\r
+ }\r
+\r
+ private byte[] _toMultiByte(int intValue) {\r
+ int numBits = 32;\r
+ int mask = 0x80000000;\r
+\r
+ while ((mask != 0) && ((intValue & mask) == 0)) {\r
+ numBits--;\r
+ mask >>>= 1;\r
+ }\r
+\r
+ int numBitsLeft = numBits;\r
+ byte[] multiBytes = new byte[(numBitsLeft + 6) / 7];\r
+\r
+ int maxIndex = multiBytes.length - 1;\r
+\r
+ for (int b = 0; b <= maxIndex; b++) {\r
+ multiBytes[b] = (byte)((intValue >>> ((maxIndex - b) * 7)) & 0x7f);\r
+\r
+ if (b != maxIndex) {\r
+ multiBytes[b] |= (byte)0x80;\r
+ }\r
+ }\r
+\r
+ return multiBytes;\r
+ }\r
+\r
+ private static Log _log = LogFactoryUtil.getLog(ImageToolImpl.class);\r
+\r
+ private static ImageTool _instance = new ImageToolImpl();\r
+\r
+ private static FileImpl _fileUtil = FileImpl.getInstance();\r
+\r
+}\r