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