001
014
015 package com.liferay.portal.image;
016
017 import com.liferay.portal.kernel.image.ImageBag;
018 import com.liferay.portal.kernel.image.ImageTool;
019 import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayInputStream;
020 import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayOutputStream;
021 import com.liferay.portal.kernel.log.Log;
022 import com.liferay.portal.kernel.log.LogFactoryUtil;
023 import com.liferay.portal.kernel.security.pacl.DoPrivileged;
024 import com.liferay.portal.kernel.util.JavaDetector;
025 import com.liferay.portal.util.FileImpl;
026
027 import com.sun.media.jai.codec.ImageCodec;
028 import com.sun.media.jai.codec.ImageDecoder;
029 import com.sun.media.jai.codec.ImageEncoder;
030
031 import java.awt.Graphics2D;
032 import java.awt.Graphics;
033 import java.awt.Image;
034 import java.awt.image.BufferedImage;
035 import java.awt.image.DataBuffer;
036 import java.awt.image.IndexColorModel;
037 import java.awt.image.RenderedImage;
038 import java.awt.image.SampleModel;
039 import java.awt.image.WritableRaster;
040
041 import java.io.File;
042 import java.io.IOException;
043 import java.io.OutputStream;
044
045 import java.util.Enumeration;
046
047 import javax.imageio.ImageIO;
048
049 import javax.media.jai.RenderedImageAdapter;
050
051 import net.jmge.gif.Gif89Encoder;
052
053
056 @DoPrivileged
057 public class ImageToolImpl implements ImageTool {
058
059 public static ImageTool getInstance() {
060 return _instance;
061 }
062
063 @Override
064 public BufferedImage convertImageType(BufferedImage sourceImage, int type) {
065 BufferedImage targetImage = new BufferedImage(
066 sourceImage.getWidth(), sourceImage.getHeight(), type);
067
068 Graphics2D graphics = targetImage.createGraphics();
069
070 graphics.drawRenderedImage(sourceImage, null);
071
072 graphics.dispose();
073
074 return targetImage;
075 }
076
077 @Override
078 public void encodeGIF(RenderedImage renderedImage, OutputStream os)
079 throws IOException {
080
081 if (JavaDetector.isJDK6()) {
082 ImageIO.write(renderedImage, TYPE_GIF, os);
083 }
084 else {
085 BufferedImage bufferedImage = getBufferedImage(renderedImage);
086
087 if (!(bufferedImage.getColorModel() instanceof IndexColorModel)) {
088 bufferedImage = convertImageType(
089 bufferedImage, BufferedImage.TYPE_BYTE_INDEXED);
090 }
091
092 Gif89Encoder encoder = new Gif89Encoder(bufferedImage);
093
094 encoder.encode(os);
095 }
096 }
097
098 @Override
099 public void encodeWBMP(RenderedImage renderedImage, OutputStream os)
100 throws IOException {
101
102 BufferedImage bufferedImage = getBufferedImage(renderedImage);
103
104 SampleModel sampleModel = bufferedImage.getSampleModel();
105
106 int type = sampleModel.getDataType();
107
108 if ((bufferedImage.getType() != BufferedImage.TYPE_BYTE_BINARY) ||
109 (type < DataBuffer.TYPE_BYTE) || (type > DataBuffer.TYPE_INT) ||
110 (sampleModel.getNumBands() != 1) ||
111 (sampleModel.getSampleSize(0) != 1)) {
112
113 BufferedImage binaryImage = new BufferedImage(
114 bufferedImage.getWidth(), bufferedImage.getHeight(),
115 BufferedImage.TYPE_BYTE_BINARY);
116
117 Graphics graphics = binaryImage.getGraphics();
118
119 graphics.drawImage(bufferedImage, 0, 0, null);
120
121 renderedImage = binaryImage;
122 }
123
124 if (!ImageIO.write(renderedImage, "wbmp", os)) {
125
126
127
128 os.write(0);
129 os.write(0);
130 os.write(_toMultiByte(bufferedImage.getWidth()));
131 os.write(_toMultiByte(bufferedImage.getHeight()));
132
133 DataBuffer dataBuffer = bufferedImage.getData().getDataBuffer();
134
135 int size = dataBuffer.getSize();
136
137 for (int i = 0; i < size; i++) {
138 os.write((byte)dataBuffer.getElem(i));
139 }
140 }
141 }
142
143 @Override
144 public BufferedImage getBufferedImage(RenderedImage renderedImage) {
145 if (renderedImage instanceof BufferedImage) {
146 return (BufferedImage)renderedImage;
147 }
148 else {
149 RenderedImageAdapter adapter = new RenderedImageAdapter(
150 renderedImage);
151
152 return adapter.getAsBufferedImage();
153 }
154 }
155
156 @Override
157 public byte[] getBytes(RenderedImage renderedImage, String contentType)
158 throws IOException {
159
160 UnsyncByteArrayOutputStream baos = new UnsyncByteArrayOutputStream();
161
162 write(renderedImage, contentType, baos);
163
164 return baos.toByteArray();
165 }
166
167 @Override
168 public ImageBag read(byte[] bytes) {
169 RenderedImage renderedImage = null;
170 String type = TYPE_NOT_AVAILABLE;
171
172 Enumeration<ImageCodec> enu = ImageCodec.getCodecs();
173
174 while (enu.hasMoreElements()) {
175 ImageCodec codec = enu.nextElement();
176
177 if (codec.isFormatRecognized(bytes)) {
178 type = codec.getFormatName();
179
180 ImageDecoder decoder = ImageCodec.createImageDecoder(
181 type, new UnsyncByteArrayInputStream(bytes), null);
182
183 try {
184 renderedImage = decoder.decodeAsRenderedImage();
185 }
186 catch (IOException ioe) {
187 if (_log.isDebugEnabled()) {
188 _log.debug(type + ": " + ioe.getMessage());
189 }
190 }
191
192 break;
193 }
194 }
195
196 if (type.equals("jpeg")) {
197 type = TYPE_JPEG;
198 }
199
200 return new ImageBag(renderedImage, type);
201 }
202
203 @Override
204 public ImageBag read(File file) throws IOException {
205 return read(_fileUtil.getBytes(file));
206 }
207
208 @Override
209 public RenderedImage scale(RenderedImage renderedImage, int width) {
210 if (width <= 0) {
211 return renderedImage;
212 }
213
214 int imageHeight = renderedImage.getHeight();
215 int imageWidth = renderedImage.getWidth();
216
217 double factor = (double)width / imageWidth;
218
219 int scaledHeight = (int)(factor * imageHeight);
220 int scaledWidth = width;
221
222 BufferedImage bufferedImage = getBufferedImage(renderedImage);
223
224 int type = bufferedImage.getType();
225
226 if (type == 0) {
227 type = BufferedImage.TYPE_INT_ARGB;
228 }
229
230 BufferedImage scaledBufferedImage = new BufferedImage(
231 scaledWidth, scaledHeight, type);
232
233 Graphics graphics = scaledBufferedImage.getGraphics();
234
235 Image scaledImage = bufferedImage.getScaledInstance(
236 scaledWidth, scaledHeight, Image.SCALE_SMOOTH);
237
238 graphics.drawImage(scaledImage, 0, 0, null);
239
240 return scaledBufferedImage;
241 }
242
243 @Override
244 public RenderedImage scale(
245 RenderedImage renderedImage, int maxHeight, int maxWidth) {
246
247 int imageHeight = renderedImage.getHeight();
248 int imageWidth = renderedImage.getWidth();
249
250 if (maxHeight == 0) {
251 maxHeight = imageHeight;
252 }
253
254 if (maxWidth == 0) {
255 maxWidth = imageWidth;
256 }
257
258 if ((imageHeight <= maxHeight) && (imageWidth <= maxWidth)) {
259 return renderedImage;
260 }
261
262 double factor = Math.min(
263 (double)maxHeight / imageHeight, (double)maxWidth / imageWidth);
264
265 int scaledHeight = Math.max(1, (int)(factor * imageHeight));
266 int scaledWidth = Math.max(1, (int)(factor * imageWidth));
267
268 BufferedImage bufferedImage = getBufferedImage(renderedImage);
269
270 int type = bufferedImage.getType();
271
272 if (type == 0) {
273 type = BufferedImage.TYPE_INT_ARGB;
274 }
275
276 BufferedImage scaledBufferedImage = null;
277
278 if ((type == BufferedImage.TYPE_BYTE_BINARY) ||
279 (type == BufferedImage.TYPE_BYTE_INDEXED)) {
280
281 IndexColorModel indexColorModel =
282 (IndexColorModel)bufferedImage.getColorModel();
283
284 BufferedImage tempBufferedImage = new BufferedImage(
285 1, 1, type, indexColorModel);
286
287 int bits = indexColorModel.getPixelSize();
288 int size = indexColorModel.getMapSize();
289
290 byte[] reds = new byte[size];
291
292 indexColorModel.getReds(reds);
293
294 byte[] greens = new byte[size];
295
296 indexColorModel.getGreens(greens);
297
298 byte[] blues = new byte[size];
299
300 indexColorModel.getBlues(blues);
301
302 WritableRaster writableRaster = tempBufferedImage.getRaster();
303
304 int pixel = writableRaster.getSample(0, 0, 0);
305
306 IndexColorModel scaledIndexColorModel = new IndexColorModel(
307 bits, size, reds, greens, blues, pixel);
308
309 scaledBufferedImage = new BufferedImage(
310 scaledWidth, scaledHeight, type, scaledIndexColorModel);
311 }
312 else {
313 scaledBufferedImage = new BufferedImage(
314 scaledWidth, scaledHeight, type);
315 }
316
317 Graphics graphics = scaledBufferedImage.getGraphics();
318
319 Image scaledImage = bufferedImage.getScaledInstance(
320 scaledWidth, scaledHeight, Image.SCALE_SMOOTH);
321
322 graphics.drawImage(scaledImage, 0, 0, null);
323
324 return scaledBufferedImage;
325 }
326
327 @Override
328 public void write(
329 RenderedImage renderedImage, String contentType, OutputStream os)
330 throws IOException {
331
332 if (contentType.contains(TYPE_BMP)) {
333 ImageEncoder imageEncoder = ImageCodec.createImageEncoder(
334 TYPE_BMP, os, null);
335
336 imageEncoder.encode(renderedImage);
337 }
338 else if (contentType.contains(TYPE_GIF)) {
339 encodeGIF(renderedImage, os);
340 }
341 else if (contentType.contains(TYPE_JPEG) ||
342 contentType.contains("jpeg")) {
343
344 ImageIO.write(renderedImage, "jpeg", os);
345 }
346 else if (contentType.contains(TYPE_PNG)) {
347 ImageIO.write(renderedImage, TYPE_PNG, os);
348 }
349 else if (contentType.contains(TYPE_TIFF) ||
350 contentType.contains("tif")) {
351
352 ImageEncoder imageEncoder = ImageCodec.createImageEncoder(
353 TYPE_TIFF, os, null);
354
355 imageEncoder.encode(renderedImage);
356 }
357 }
358
359 private byte[] _toMultiByte(int intValue) {
360 int numBits = 32;
361 int mask = 0x80000000;
362
363 while ((mask != 0) && ((intValue & mask) == 0)) {
364 numBits--;
365 mask >>>= 1;
366 }
367
368 int numBitsLeft = numBits;
369 byte[] multiBytes = new byte[(numBitsLeft + 6) / 7];
370
371 int maxIndex = multiBytes.length - 1;
372
373 for (int b = 0; b <= maxIndex; b++) {
374 multiBytes[b] = (byte)((intValue >>> ((maxIndex - b) * 7)) & 0x7f);
375
376 if (b != maxIndex) {
377 multiBytes[b] |= (byte)0x80;
378 }
379 }
380
381 return multiBytes;
382 }
383
384 private static Log _log = LogFactoryUtil.getLog(ImageToolImpl.class);
385
386 private static ImageTool _instance = new ImageToolImpl();
387
388 private static FileImpl _fileUtil = FileImpl.getInstance();
389
390 }