2 * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
\r
4 * This library is free software; you can redistribute it and/or modify it under
\r
5 * the terms of the GNU Lesser General Public License as published by the Free
\r
6 * Software Foundation; either version 2.1 of the License, or (at your option)
\r
9 * This library is distributed in the hope that it will be useful, but WITHOUT
\r
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
11 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
\r
15 package com.liferay.portal.image;
\r
17 import com.liferay.portal.kernel.image.ImageBag;
\r
18 import com.liferay.portal.kernel.image.ImageTool;
\r
19 import com.liferay.portal.kernel.image.ImageToolUtil;
\r
20 import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayInputStream;
\r
21 import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayOutputStream;
\r
22 import com.liferay.portal.kernel.log.Log;
\r
23 import com.liferay.portal.kernel.log.LogFactoryUtil;
\r
24 import com.liferay.portal.kernel.util.JavaDetector;
\r
25 import com.liferay.portal.kernel.util.StringBundler;
\r
26 import com.liferay.portal.util.FileImpl;
\r
28 import com.sun.media.jai.codec.ImageCodec;
\r
29 import com.sun.media.jai.codec.ImageDecoder;
\r
30 import com.sun.media.jai.codec.ImageEncoder;
\r
32 import java.awt.Graphics2D;
\r
33 import java.awt.Graphics;
\r
34 import java.awt.Image;
\r
35 import java.awt.image.BufferedImage;
\r
36 import java.awt.image.DataBuffer;
\r
37 import java.awt.image.IndexColorModel;
\r
38 import java.awt.image.RenderedImage;
\r
39 import java.awt.image.SampleModel;
\r
40 import java.awt.image.WritableRaster;
\r
41 import java.io.ByteArrayInputStream;
\r
42 import java.io.File;
\r
43 import java.io.IOException;
\r
44 import java.io.OutputStream;
\r
45 import java.util.Iterator;
\r
46 import java.util.LinkedList;
\r
47 import java.util.Queue;
\r
49 import javax.imageio.ImageIO;
\r
50 import javax.imageio.ImageReader;
\r
51 import javax.imageio.stream.ImageInputStream;
\r
52 import javax.media.jai.RenderedImageAdapter;
\r
54 import net.jmge.gif.Gif89Encoder;
\r
57 * @author Brian Wing Shun Chan
\r
59 public class ImageToolImpl implements ImageTool {
\r
61 public static ImageTool getInstance() {
\r
65 public BufferedImage convertImageType(BufferedImage sourceImage, int type) {
\r
66 BufferedImage targetImage = new BufferedImage(
\r
67 sourceImage.getWidth(), sourceImage.getHeight(), type);
\r
69 Graphics2D graphics = targetImage.createGraphics();
\r
71 graphics.drawRenderedImage(sourceImage, null);
\r
78 public void encodeGIF(RenderedImage renderedImage, OutputStream os)
\r
79 throws IOException {
\r
81 if (JavaDetector.isJDK6()) {
\r
83 ImageIO.write(renderedImage, TYPE_GIF, os);
\r
85 catch (Exception e){
\r
86 ImageIO.write(renderedImage, TYPE_PNG, os);
\r
90 BufferedImage bufferedImage = getBufferedImage(renderedImage);
\r
92 if (!(bufferedImage.getColorModel() instanceof IndexColorModel)) {
\r
93 bufferedImage = convertImageType(
\r
94 bufferedImage, BufferedImage.TYPE_BYTE_INDEXED);
\r
97 Gif89Encoder encoder = new Gif89Encoder(bufferedImage);
\r
103 public void encodeWBMP(RenderedImage renderedImage, OutputStream os)
\r
104 throws IOException {
\r
106 BufferedImage bufferedImage = getBufferedImage(renderedImage);
\r
108 SampleModel sampleModel = bufferedImage.getSampleModel();
\r
110 int type = sampleModel.getDataType();
\r
112 if ((bufferedImage.getType() != BufferedImage.TYPE_BYTE_BINARY) ||
\r
113 (type < DataBuffer.TYPE_BYTE) || (type > DataBuffer.TYPE_INT) ||
\r
114 (sampleModel.getNumBands() != 1) ||
\r
115 (sampleModel.getSampleSize(0) != 1)) {
\r
117 BufferedImage binaryImage = new BufferedImage(
\r
118 bufferedImage.getWidth(), bufferedImage.getHeight(),
\r
119 BufferedImage.TYPE_BYTE_BINARY);
\r
121 Graphics graphics = binaryImage.getGraphics();
\r
123 graphics.drawImage(bufferedImage, 0, 0, null);
\r
125 renderedImage = binaryImage;
\r
128 if (!ImageIO.write(renderedImage, "wbmp", os)) {
\r
130 // See http://www.jguru.com/faq/view.jsp?EID=127723
\r
134 os.write(_toMultiByte(bufferedImage.getWidth()));
\r
135 os.write(_toMultiByte(bufferedImage.getHeight()));
\r
137 DataBuffer dataBuffer = bufferedImage.getData().getDataBuffer();
\r
139 int size = dataBuffer.getSize();
\r
141 for (int i = 0; i < size; i++) {
\r
142 os.write((byte)dataBuffer.getElem(i));
\r
147 public BufferedImage getBufferedImage(RenderedImage renderedImage) {
\r
148 if (renderedImage instanceof BufferedImage) {
\r
149 return (BufferedImage)renderedImage;
\r
152 RenderedImageAdapter adapter = new RenderedImageAdapter(
\r
155 return adapter.getAsBufferedImage();
\r
159 public byte[] getBytes(RenderedImage renderedImage, String contentType)
\r
160 throws IOException {
\r
162 UnsyncByteArrayOutputStream baos = new UnsyncByteArrayOutputStream();
\r
164 write(renderedImage, contentType, baos);
\r
166 return baos.toByteArray();
\r
169 public ImageBag read(byte[] bytes) {
\r
171 // // Here the old way was using com.sun.jai package, which is only included in sun jdk.
\r
172 // // Now we use standard java
\r
174 String formatName = null;
\r
175 ImageInputStream imageInputStream = null;
\r
176 Queue<ImageReader> imageReaders = new LinkedList<ImageReader>();
\r
177 RenderedImage renderedImage = null;
\r
180 imageInputStream = ImageIO.createImageInputStream(new ByteArrayInputStream(bytes));
\r
182 Iterator<ImageReader> iterator = ImageIO.getImageReaders(imageInputStream);
\r
184 while ((renderedImage == null) && iterator.hasNext()) {
\r
185 ImageReader imageReader = iterator.next();
\r
187 imageReaders.offer(imageReader);
\r
190 imageReader.setInput(imageInputStream);
\r
192 int height = imageReader.getHeight(0);
\r
193 int width = imageReader.getWidth(0);
\r
195 if (height > 1080 || width > 1920) {
\r
197 StringBundler sb = new StringBundler(9);
\r
199 sb.append("Image's dimensions (");
\r
201 sb.append(" px high and ");
\r
203 sb.append(" px wide) exceed max dimensions (");
\r
205 sb.append(" px high and ");
\r
207 sb.append(" px wide)");
\r
209 throw new Exception(sb.toString());
\r
212 renderedImage = imageReader.read(0);
\r
214 catch (IOException ioe) {
\r
218 formatName = imageReader.getFormatName().toLowerCase();
\r
221 } catch (Exception e) {
\r
222 _log.error("Error in image read");
\r
225 while (!imageReaders.isEmpty()) {
\r
226 ImageReader imageReader = imageReaders.poll();
\r
227 imageReader.dispose();
\r
229 if (imageInputStream != null) {
\r
231 imageInputStream.close();
\r
232 } catch (Exception e) {
\r
237 String type = TYPE_JPEG;
\r
238 if (formatName == null || formatName.isEmpty()) {
\r
239 type = TYPE_NOT_AVAILABLE;
\r
240 } else if (formatName.contains(TYPE_BMP)) {
\r
243 else if (formatName.contains(TYPE_GIF)) {
\r
246 else if (formatName.contains("jpeg") || formatName.contains("jpg") || type.equalsIgnoreCase("jpeg")) {
\r
249 else if (formatName.contains(TYPE_PNG)) {
\r
252 else if (formatName.contains(TYPE_TIFF)) {
\r
256 throw new IllegalArgumentException("Image type " + type + " is not supported");
\r
259 if (renderedImage == null) {
\r
260 _log.error("Image could not be rendered");
\r
264 return new ImageBag(renderedImage, type);
\r
268 public ImageBag read(File file) throws IOException {
\r
269 return read(_fileUtil.getBytes(file));
\r
272 public RenderedImage scale(RenderedImage renderedImage, int width) {
\r
274 return renderedImage;
\r
277 int imageHeight = renderedImage.getHeight();
\r
278 int imageWidth = renderedImage.getWidth();
\r
280 double factor = (double) width / imageWidth;
\r
282 int scaledHeight = (int)(factor * imageHeight);
\r
283 int scaledWidth = width;
\r
285 BufferedImage bufferedImage = getBufferedImage(renderedImage);
\r
287 int type = bufferedImage.getType();
\r
290 type = BufferedImage.TYPE_INT_ARGB;
\r
293 BufferedImage scaledBufferedImage = new BufferedImage(
\r
294 scaledWidth, scaledHeight, type);
\r
296 Graphics graphics = scaledBufferedImage.getGraphics();
\r
298 Image scaledImage = bufferedImage.getScaledInstance(
\r
299 scaledWidth, scaledHeight, Image.SCALE_SMOOTH);
\r
301 graphics.drawImage(scaledImage, 0, 0, null);
\r
303 return scaledBufferedImage;
\r
306 public RenderedImage scale(
\r
307 RenderedImage renderedImage, int maxHeight, int maxWidth) {
\r
309 int imageHeight = renderedImage.getHeight();
\r
310 int imageWidth = renderedImage.getWidth();
\r
312 if (maxHeight == 0) {
\r
313 maxHeight = imageHeight;
\r
316 if (maxWidth == 0) {
\r
317 maxWidth = imageWidth;
\r
320 if ((imageHeight <= maxHeight) && (imageWidth <= maxWidth)) {
\r
321 return renderedImage;
\r
324 double factor = Math.min(
\r
325 (double)maxHeight / imageHeight, (double)maxWidth / imageWidth);
\r
327 int scaledHeight = Math.max(1, (int)(factor * imageHeight));
\r
328 int scaledWidth = Math.max(1, (int)(factor * imageWidth));
\r
330 BufferedImage bufferedImage = getBufferedImage(renderedImage);
\r
332 int type = bufferedImage.getType();
\r
335 type = BufferedImage.TYPE_INT_ARGB;
\r
338 BufferedImage scaledBufferedImage = null;
\r
340 if ((type == BufferedImage.TYPE_BYTE_BINARY) ||
\r
341 (type == BufferedImage.TYPE_BYTE_INDEXED)) {
\r
343 IndexColorModel indexColorModel =
\r
344 (IndexColorModel)bufferedImage.getColorModel();
\r
346 BufferedImage tempBufferedImage = new BufferedImage(
\r
347 1, 1, type, indexColorModel);
\r
349 int bits = indexColorModel.getPixelSize();
\r
350 int size = indexColorModel.getMapSize();
\r
352 byte[] reds = new byte[size];
\r
354 indexColorModel.getReds(reds);
\r
356 byte[] greens = new byte[size];
\r
358 indexColorModel.getGreens(greens);
\r
360 byte[] blues = new byte[size];
\r
362 indexColorModel.getBlues(blues);
\r
364 WritableRaster writableRaster = tempBufferedImage.getRaster();
\r
366 int pixel = writableRaster.getSample(0, 0, 0);
\r
368 IndexColorModel scaledIndexColorModel = new IndexColorModel(
\r
369 bits, size, reds, greens, blues, pixel);
\r
371 scaledBufferedImage = new BufferedImage(
\r
372 scaledWidth, scaledHeight, type, scaledIndexColorModel);
\r
375 scaledBufferedImage = new BufferedImage(
\r
376 scaledWidth, scaledHeight, type);
\r
379 Graphics graphics = scaledBufferedImage.getGraphics();
\r
381 Image scaledImage = bufferedImage.getScaledInstance(
\r
382 scaledWidth, scaledHeight, Image.SCALE_SMOOTH);
\r
384 graphics.drawImage(scaledImage, 0, 0, null);
\r
386 return scaledBufferedImage;
\r
390 RenderedImage renderedImage, String contentType, OutputStream os)
\r
391 throws IOException {
\r
393 // // Here the old way was using com.sun.jai package, which is only included in sun jdk.
\r
394 // // Now we use standard java
\r
396 if (contentType.contains(TYPE_BMP)) {
\r
397 ImageIO.write(renderedImage, "bmp", os);
\r
399 else if (contentType.contains(TYPE_GIF)) {
\r
400 encodeGIF(renderedImage, os);
\r
402 else if (contentType.contains(TYPE_JPEG) || contentType.contains("jpeg")) {
\r
403 ImageIO.write(renderedImage, "jpeg", os);
\r
405 else if (contentType.contains(TYPE_PNG)) {
\r
406 ImageIO.write(renderedImage, TYPE_PNG, os);
\r
408 else if (contentType.contains(TYPE_TIFF) || contentType.contains("tif")) {
\r
409 ImageIO.write(renderedImage, "tiff", os);
\r
413 private byte[] _toMultiByte(int intValue) {
\r
415 int mask = 0x80000000;
\r
417 while ((mask != 0) && ((intValue & mask) == 0)) {
\r
422 int numBitsLeft = numBits;
\r
423 byte[] multiBytes = new byte[(numBitsLeft + 6) / 7];
\r
425 int maxIndex = multiBytes.length - 1;
\r
427 for (int b = 0; b <= maxIndex; b++) {
\r
428 multiBytes[b] = (byte)((intValue >>> ((maxIndex - b) * 7)) & 0x7f);
\r
430 if (b != maxIndex) {
\r
431 multiBytes[b] |= (byte)0x80;
\r
438 private static Log _log = LogFactoryUtil.getLog(ImageToolImpl.class);
\r
440 private static ImageTool _instance = new ImageToolImpl();
\r
442 private static FileImpl _fileUtil = FileImpl.getInstance();
\r