1
22
23 package com.liferay.portal.image;
24
25 import com.liferay.portal.kernel.image.ImageBag;
26 import com.liferay.portal.kernel.image.ImageProcessor;
27 import com.liferay.portal.kernel.util.JavaProps;
28 import com.liferay.portal.util.FileImpl;
29
30 import com.sun.media.jai.codec.ImageCodec;
31 import com.sun.media.jai.codec.ImageDecoder;
32
33 import java.awt.Graphics2D;
34 import java.awt.Image;
35 import java.awt.image.BufferedImage;
36 import java.awt.image.DataBuffer;
37 import java.awt.image.IndexColorModel;
38 import java.awt.image.RenderedImage;
39 import java.awt.image.SampleModel;
40
41 import java.io.ByteArrayInputStream;
42 import java.io.File;
43 import java.io.IOException;
44 import java.io.OutputStream;
45
46 import java.util.Enumeration;
47
48 import javax.imageio.ImageIO;
49
50 import javax.media.jai.RenderedImageAdapter;
51
52 import net.jmge.gif.Gif89Encoder;
53
54 import org.apache.commons.logging.Log;
55 import org.apache.commons.logging.LogFactory;
56
57
63 public class ImageProcessorImpl implements ImageProcessor {
64
65 public BufferedImage convertImageType(BufferedImage sourceImage, int type) {
66 BufferedImage targetImage = new BufferedImage(
67 sourceImage.getWidth(), sourceImage.getHeight(), type);
68
69 Graphics2D graphics = targetImage.createGraphics();
70
71 graphics.drawRenderedImage(sourceImage, null);
72 graphics.dispose();
73
74 return targetImage;
75 }
76
77 public void encodeGIF(RenderedImage renderedImage, OutputStream os)
78 throws IOException {
79
80 if (JavaProps.isJDK6()) {
81 ImageIO.write(renderedImage, "GIF", os);
82 }
83 else {
84 BufferedImage bufferedImage = getBufferedImage(renderedImage);
85
86 if (!(bufferedImage.getColorModel() instanceof IndexColorModel)) {
87 bufferedImage = convertImageType(
88 bufferedImage, BufferedImage.TYPE_BYTE_INDEXED);
89 }
90
91 Gif89Encoder encoder = new Gif89Encoder(bufferedImage);
92
93 encoder.encode(os);
94 }
95 }
96
97 public void encodeWBMP(RenderedImage renderedImage, OutputStream os)
98 throws IOException {
99
100 BufferedImage bufferedImage = getBufferedImage(renderedImage);
101
102 SampleModel sampleModel = bufferedImage.getSampleModel();
103
104 int type = sampleModel.getDataType();
105
106 if ((bufferedImage.getType() != BufferedImage.TYPE_BYTE_BINARY) ||
107 (type < DataBuffer.TYPE_BYTE) || (type > DataBuffer.TYPE_INT) ||
108 (sampleModel.getNumBands() != 1) ||
109 (sampleModel.getSampleSize(0) != 1)) {
110
111 BufferedImage binaryImage = new BufferedImage(
112 bufferedImage.getWidth(), bufferedImage.getHeight(),
113 BufferedImage.TYPE_BYTE_BINARY);
114
115 binaryImage.getGraphics().drawImage(bufferedImage, 0, 0, null);
116
117 renderedImage = binaryImage;
118 }
119
120 if (!ImageIO.write(renderedImage, "wbmp", os)) {
121
122
124 os.write(0);
125 os.write(0);
126 os.write(_toMultiByte(bufferedImage.getWidth()));
127 os.write(_toMultiByte(bufferedImage.getHeight()));
128
129 DataBuffer dataBuffer = bufferedImage.getData().getDataBuffer();
130
131 int size = dataBuffer.getSize();
132
133 for (int i = 0; i < size; i++) {
134 os.write((byte)dataBuffer.getElem(i));
135 }
136 }
137 }
138
139 public BufferedImage getBufferedImage(RenderedImage renderedImage) {
140 if (renderedImage instanceof BufferedImage) {
141 return (BufferedImage)renderedImage;
142 }
143 else {
144 RenderedImageAdapter adapter = new RenderedImageAdapter(
145 renderedImage);
146
147 return adapter.getAsBufferedImage();
148 }
149 }
150
151 public ImageBag read(File file) throws IOException {
152 return read(_fileUtil.getBytes(file));
153 }
154
155 public ImageBag read(byte[] bytes) {
156 RenderedImage renderedImage = null;
157 String type = TYPE_NOT_AVAILABLE;
158
159 Enumeration<ImageCodec> enu = ImageCodec.getCodecs();
160
161 while (enu.hasMoreElements()) {
162 ImageCodec codec = enu.nextElement();
163
164 if (codec.isFormatRecognized(bytes)) {
165 type = codec.getFormatName();
166
167 ImageDecoder decoder = ImageCodec.createImageDecoder(
168 type, new ByteArrayInputStream(bytes), null);
169
170 try {
171 renderedImage = decoder.decodeAsRenderedImage();
172 }
173 catch (IOException ioe) {
174 if (_log.isDebugEnabled()) {
175 _log.debug(type + ": " + ioe.getMessage());
176 }
177 }
178
179 break;
180 }
181 }
182
183 if (type.equals("jpeg")) {
184 type = ImageProcessor.TYPE_JPEG;
185 }
186
187 return new ImageBag(renderedImage, type);
188 }
189
190 public RenderedImage scale(
191 RenderedImage renderedImage, int maxHeight, int maxWidth) {
192
193 int imageHeight = renderedImage.getHeight();
194 int imageWidth = renderedImage.getWidth();
195
196 if (maxHeight == 0) {
197 maxHeight = imageHeight;
198 }
199
200 if (maxWidth == 0) {
201 maxWidth = imageWidth;
202 }
203
204 if ((imageHeight <= maxHeight) && (imageWidth <= maxWidth)) {
205 return renderedImage;
206 }
207
208 double factor = Math.min(
209 (double)maxHeight / imageHeight, (double)maxWidth / imageWidth);
210
211 int scaledHeight = (int)(factor * imageHeight);
212 int scaledWidth = (int)(factor * imageWidth);
213
214 BufferedImage bufferedImage = getBufferedImage(renderedImage);
215
216 Image scaledImage = bufferedImage.getScaledInstance(
217 scaledWidth, scaledHeight, Image.SCALE_SMOOTH);
218
219 BufferedImage scaledBufferedImage = new BufferedImage(
220 scaledWidth, scaledHeight, BufferedImage.TYPE_INT_RGB);
221
222 scaledBufferedImage.getGraphics().drawImage(scaledImage, 0, 0, null);
223
224 return scaledBufferedImage;
225 }
226
227 private byte[] _toMultiByte(int intValue) {
228 int numBits = 32;
229 int mask = 0x80000000;
230
231 while (mask != 0 && (intValue & mask) == 0) {
232 numBits--;
233 mask >>>= 1;
234 }
235
236 int numBitsLeft = numBits;
237 byte[] multiBytes = new byte[(numBitsLeft + 6) / 7];
238
239 int maxIndex = multiBytes.length - 1;
240
241 for (int b = 0; b <= maxIndex; b++) {
242 multiBytes[b] = (byte)((intValue >>> ((maxIndex - b) * 7)) & 0x7f);
243
244 if (b != maxIndex) {
245 multiBytes[b] |= (byte)0x80;
246 }
247 }
248
249 return multiBytes;
250 }
251
252 private static Log _log = LogFactory.getLog(ImageProcessorImpl.class);
253
254 private static FileImpl _fileUtil = FileImpl.getInstance();
255
256 }