001
014
015 package com.liferay.portal.image;
016
017 import com.liferay.portal.kernel.image.ImageBag;
018 import com.liferay.portal.kernel.image.ImageMagick;
019 import com.liferay.portal.kernel.image.ImageTool;
020 import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayInputStream;
021 import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayOutputStream;
022 import com.liferay.portal.kernel.log.Log;
023 import com.liferay.portal.kernel.log.LogFactoryUtil;
024 import com.liferay.portal.kernel.security.pacl.DoPrivileged;
025 import com.liferay.portal.kernel.util.ArrayUtil;
026 import com.liferay.portal.kernel.util.JavaDetector;
027 import com.liferay.portal.kernel.util.PropsKeys;
028 import com.liferay.portal.kernel.util.StringUtil;
029 import com.liferay.portal.model.Image;
030 import com.liferay.portal.model.impl.ImageImpl;
031 import com.liferay.portal.util.FileImpl;
032 import com.liferay.portal.util.PropsUtil;
033 import com.liferay.portal.util.PropsValues;
034
035 import com.sun.media.jai.codec.ImageCodec;
036 import com.sun.media.jai.codec.ImageDecoder;
037 import com.sun.media.jai.codec.ImageEncoder;
038
039 import java.awt.AlphaComposite;
040 import java.awt.Graphics;
041 import java.awt.Graphics2D;
042 import java.awt.Rectangle;
043 import java.awt.RenderingHints;
044 import java.awt.image.BufferedImage;
045 import java.awt.image.ColorModel;
046 import java.awt.image.DataBuffer;
047 import java.awt.image.IndexColorModel;
048 import java.awt.image.RenderedImage;
049 import java.awt.image.SampleModel;
050
051 import java.io.ByteArrayInputStream;
052 import java.io.File;
053 import java.io.IOException;
054 import java.io.InputStream;
055 import java.io.OutputStream;
056
057 import java.util.Arrays;
058 import java.util.Enumeration;
059 import java.util.HashMap;
060 import java.util.Iterator;
061 import java.util.LinkedList;
062 import java.util.Map;
063 import java.util.Queue;
064 import java.util.concurrent.ExecutionException;
065 import java.util.concurrent.Future;
066 import java.util.concurrent.TimeUnit;
067 import java.util.concurrent.TimeoutException;
068
069 import javax.imageio.ImageIO;
070 import javax.imageio.ImageReader;
071 import javax.imageio.spi.IIORegistry;
072 import javax.imageio.spi.ImageReaderSpi;
073 import javax.imageio.stream.ImageInputStream;
074
075 import javax.media.jai.RenderedImageAdapter;
076
077 import net.jmge.gif.Gif89Encoder;
078
079 import org.im4java.core.IMOperation;
080
081 import org.monte.media.jpeg.CMYKJPEGImageReaderSpi;
082
083
088 @DoPrivileged
089 public class ImageToolImpl implements ImageTool {
090
091 public static ImageTool getInstance() {
092 return _instance;
093 }
094
095 public void afterPropertiesSet() {
096 ClassLoader classLoader = getClass().getClassLoader();
097
098 try {
099 InputStream is = classLoader.getResourceAsStream(
100 PropsUtil.get(PropsKeys.IMAGE_DEFAULT_SPACER));
101
102 if (is == null) {
103 _log.error("Default spacer is not available");
104 }
105
106 _defaultSpacer = getImage(is);
107 }
108 catch (Exception e) {
109 _log.error(
110 "Unable to configure the default spacer: " + e.getMessage());
111 }
112
113 try {
114 InputStream is = classLoader.getResourceAsStream(
115 PropsUtil.get(PropsKeys.IMAGE_DEFAULT_COMPANY_LOGO));
116
117 if (is == null) {
118 _log.error("Default company logo is not available");
119 }
120
121 _defaultCompanyLogo = getImage(is);
122 }
123 catch (Exception e) {
124 _log.error(
125 "Unable to configure the default company logo: " +
126 e.getMessage());
127 }
128
129 try {
130 InputStream is = classLoader.getResourceAsStream(
131 PropsUtil.get(PropsKeys.IMAGE_DEFAULT_ORGANIZATION_LOGO));
132
133 if (is == null) {
134 _log.error("Default organization logo is not available");
135 }
136
137 _defaultOrganizationLogo = getImage(is);
138 }
139 catch (Exception e) {
140 _log.error(
141 "Unable to configure the default organization logo: " +
142 e.getMessage());
143 }
144
145 try {
146 InputStream is = classLoader.getResourceAsStream(
147 PropsUtil.get(PropsKeys.IMAGE_DEFAULT_USER_FEMALE_PORTRAIT));
148
149 if (is == null) {
150 _log.error("Default user female portrait is not available");
151 }
152
153 _defaultUserFemalePortrait = getImage(is);
154 }
155 catch (Exception e) {
156 _log.error(
157 "Unable to configure the default user female portrait: " +
158 e.getMessage());
159 }
160
161 try {
162 InputStream is = classLoader.getResourceAsStream(
163 PropsUtil.get(PropsKeys.IMAGE_DEFAULT_USER_MALE_PORTRAIT));
164
165 if (is == null) {
166 _log.error("Default user male portrait is not available");
167 }
168
169 _defaultUserMalePortrait = getImage(is);
170 }
171 catch (Exception e) {
172 _log.error(
173 "Unable to configure the default user male portrait: " +
174 e.getMessage());
175 }
176 }
177
178 @Override
179 public Future<RenderedImage> convertCMYKtoRGB(byte[] bytes, String type) {
180 ImageMagick imageMagick = getImageMagick();
181
182 if (!imageMagick.isEnabled()) {
183 return null;
184 }
185
186 File inputFile = _fileUtil.createTempFile(type);
187 File outputFile = _fileUtil.createTempFile(type);
188
189 try {
190 _fileUtil.write(inputFile, bytes);
191
192 IMOperation imOperation = new IMOperation();
193
194 imOperation.addRawArgs("-format", "%[colorspace]");
195 imOperation.addImage(inputFile.getPath());
196
197 String[] output = imageMagick.identify(imOperation.getCmdArgs());
198
199 if ((output.length == 1) &&
200 StringUtil.equalsIgnoreCase(output[0], "CMYK")) {
201
202 if (_log.isInfoEnabled()) {
203 _log.info("The image is in the CMYK colorspace");
204 }
205
206 imOperation = new IMOperation();
207
208 imOperation.addRawArgs("-colorspace", "RGB");
209 imOperation.addImage(inputFile.getPath());
210 imOperation.addImage(outputFile.getPath());
211
212 Future<?> future = imageMagick.convert(
213 imOperation.getCmdArgs());
214
215 return new RenderedImageFuture(future, outputFile, type);
216 }
217 }
218 catch (Exception e) {
219 if (_log.isErrorEnabled()) {
220 _log.error(e, e);
221 }
222 }
223 finally {
224 _fileUtil.delete(inputFile);
225 _fileUtil.delete(outputFile);
226 }
227
228 return null;
229 }
230
231 @Override
232 public BufferedImage convertImageType(BufferedImage sourceImage, int type) {
233 BufferedImage targetImage = new BufferedImage(
234 sourceImage.getWidth(), sourceImage.getHeight(), type);
235
236 Graphics2D graphics = targetImage.createGraphics();
237
238 graphics.drawRenderedImage(sourceImage, null);
239
240 graphics.dispose();
241
242 return targetImage;
243 }
244
245 @Override
246 public RenderedImage crop(
247 RenderedImage renderedImage, int height, int width, int x, int y) {
248
249 Rectangle rectangle = new Rectangle(x, y, width, height);
250
251 Rectangle croppedRectangle = rectangle.intersection(
252 new Rectangle(renderedImage.getWidth(), renderedImage.getHeight()));
253
254 BufferedImage bufferedImage = getBufferedImage(renderedImage);
255
256 return bufferedImage.getSubimage(
257 croppedRectangle.x, croppedRectangle.y, croppedRectangle.width,
258 croppedRectangle.height);
259 }
260
261 @Override
262 public void encodeGIF(RenderedImage renderedImage, OutputStream os)
263 throws IOException {
264
265 if (JavaDetector.isJDK6()) {
266 ImageIO.write(renderedImage, TYPE_GIF, os);
267 }
268 else {
269 BufferedImage bufferedImage = getBufferedImage(renderedImage);
270
271 if (!(bufferedImage.getColorModel() instanceof IndexColorModel)) {
272 bufferedImage = convertImageType(
273 bufferedImage, BufferedImage.TYPE_BYTE_INDEXED);
274 }
275
276 Gif89Encoder encoder = new Gif89Encoder(bufferedImage);
277
278 encoder.encode(os);
279 }
280 }
281
282 @Override
283 public void encodeWBMP(RenderedImage renderedImage, OutputStream os)
284 throws IOException {
285
286 BufferedImage bufferedImage = getBufferedImage(renderedImage);
287
288 SampleModel sampleModel = bufferedImage.getSampleModel();
289
290 int type = sampleModel.getDataType();
291
292 if ((bufferedImage.getType() != BufferedImage.TYPE_BYTE_BINARY) ||
293 (type < DataBuffer.TYPE_BYTE) || (type > DataBuffer.TYPE_INT) ||
294 (sampleModel.getNumBands() != 1) ||
295 (sampleModel.getSampleSize(0) != 1)) {
296
297 BufferedImage binaryImage = new BufferedImage(
298 bufferedImage.getWidth(), bufferedImage.getHeight(),
299 BufferedImage.TYPE_BYTE_BINARY);
300
301 Graphics graphics = binaryImage.getGraphics();
302
303 graphics.drawImage(bufferedImage, 0, 0, null);
304
305 renderedImage = binaryImage;
306 }
307
308 if (!ImageIO.write(renderedImage, "wbmp", os)) {
309
310
311
312 os.write(0);
313 os.write(0);
314 os.write(toMultiByte(bufferedImage.getWidth()));
315 os.write(toMultiByte(bufferedImage.getHeight()));
316
317 DataBuffer dataBuffer = bufferedImage.getData().getDataBuffer();
318
319 int size = dataBuffer.getSize();
320
321 for (int i = 0; i < size; i++) {
322 os.write((byte)dataBuffer.getElem(i));
323 }
324 }
325 }
326
327 @Override
328 public BufferedImage getBufferedImage(RenderedImage renderedImage) {
329 if (renderedImage instanceof BufferedImage) {
330 return (BufferedImage)renderedImage;
331 }
332
333 RenderedImageAdapter adapter = new RenderedImageAdapter(renderedImage);
334
335 return adapter.getAsBufferedImage();
336 }
337
338 @Override
339 public byte[] getBytes(RenderedImage renderedImage, String contentType)
340 throws IOException {
341
342 UnsyncByteArrayOutputStream baos = new UnsyncByteArrayOutputStream();
343
344 write(renderedImage, contentType, baos);
345
346 return baos.toByteArray();
347 }
348
349 @Override
350 public Image getDefaultCompanyLogo() {
351 return _defaultCompanyLogo;
352 }
353
354 @Override
355 public Image getDefaultOrganizationLogo() {
356 return _defaultOrganizationLogo;
357 }
358
359 @Override
360 public Image getDefaultSpacer() {
361 return _defaultSpacer;
362 }
363
364 @Override
365 public Image getDefaultUserFemalePortrait() {
366 return _defaultUserFemalePortrait;
367 }
368
369 @Override
370 public Image getDefaultUserMalePortrait() {
371 return _defaultUserMalePortrait;
372 }
373
374 @Override
375 public Image getImage(byte[] bytes) throws IOException {
376 if (bytes == null) {
377 return null;
378 }
379
380 ImageBag imageBag = read(bytes);
381
382 RenderedImage renderedImage = imageBag.getRenderedImage();
383
384 if (renderedImage == null) {
385 throw new IOException("Unable to decode image");
386 }
387
388 String type = imageBag.getType();
389
390 int height = renderedImage.getHeight();
391 int width = renderedImage.getWidth();
392 int size = bytes.length;
393
394 Image image = new ImageImpl();
395
396 image.setTextObj(bytes);
397 image.setType(type);
398 image.setHeight(height);
399 image.setWidth(width);
400 image.setSize(size);
401
402 return image;
403 }
404
405 @Override
406 public Image getImage(File file) throws IOException {
407 byte[] bytes = _fileUtil.getBytes(file);
408
409 return getImage(bytes);
410 }
411
412 @Override
413 public Image getImage(InputStream is) throws IOException {
414 byte[] bytes = _fileUtil.getBytes(is, -1, true);
415
416 return getImage(bytes);
417 }
418
419 @Override
420 public Image getImage(InputStream is, boolean cleanUpStream)
421 throws IOException {
422
423 byte[] bytes = _fileUtil.getBytes(is, -1, cleanUpStream);
424
425 return getImage(bytes);
426 }
427
428 @Override
429 public boolean isNullOrDefaultSpacer(byte[] bytes) {
430 if (ArrayUtil.isEmpty(bytes) ||
431 Arrays.equals(bytes, getDefaultSpacer().getTextObj())) {
432
433 return true;
434 }
435 else {
436 return false;
437 }
438 }
439
440 @Override
441 public ImageBag read(byte[] bytes) throws IOException {
442 String formatName = null;
443 ImageInputStream imageInputStream = null;
444 Queue<ImageReader> imageReaders = new LinkedList<ImageReader>();
445 RenderedImage renderedImage = null;
446
447 try {
448 imageInputStream = ImageIO.createImageInputStream(
449 new ByteArrayInputStream(bytes));
450
451 Enumeration<ImageCodec> enumeration = ImageCodec.getCodecs();
452
453 Map<String, ImageCodec> imageCodecs =
454 new HashMap<String, ImageCodec>();
455
456 while (enumeration.hasMoreElements()) {
457 ImageCodec imageCodec = enumeration.nextElement();
458
459 imageCodecs.put(imageCodec.getFormatName(), imageCodec);
460 }
461
462 Iterator<ImageReader> iterator = ImageIO.getImageReaders(
463 imageInputStream);
464
465 while ((renderedImage == null) && iterator.hasNext()) {
466 ImageReader imageReader = iterator.next();
467
468 imageReaders.offer(imageReader);
469
470 formatName = StringUtil.toLowerCase(
471 imageReader.getFormatName());
472
473 if (formatName.contains("jpeg")) {
474 try {
475 imageReader.setInput(imageInputStream);
476
477 renderedImage = imageReader.read(0);
478 }
479 catch (IOException ioe) {
480 continue;
481 }
482 }
483 else {
484 ImageCodec imageCodec = imageCodecs.get(formatName);
485
486 if (imageCodec.isFormatRecognized(bytes)) {
487 renderedImage = read(bytes, formatName);
488 }
489 }
490 }
491
492 if (renderedImage == null) {
493 throw new IOException("Unsupported image type");
494 }
495 }
496 finally {
497 while (!imageReaders.isEmpty()) {
498 ImageReader imageReader = imageReaders.poll();
499
500 imageReader.dispose();
501 }
502
503 if (imageInputStream != null) {
504 imageInputStream.close();
505 }
506 }
507
508 String type = TYPE_JPEG;
509
510 if (formatName.contains(TYPE_BMP)) {
511 type = TYPE_BMP;
512 }
513 else if (formatName.contains(TYPE_GIF)) {
514 type = TYPE_GIF;
515 }
516 else if (formatName.contains("jpeg") ||
517 StringUtil.equalsIgnoreCase(type, "jpeg")) {
518
519 type = TYPE_JPEG;
520 }
521 else if (formatName.contains(TYPE_PNG)) {
522 type = TYPE_PNG;
523 }
524 else if (formatName.contains(TYPE_TIFF)) {
525 type = TYPE_TIFF;
526 }
527 else {
528 throw new IllegalArgumentException(type + " is not supported");
529 }
530
531 return new ImageBag(renderedImage, type);
532 }
533
534 @Override
535 public ImageBag read(File file) throws IOException {
536 return read(_fileUtil.getBytes(file));
537 }
538
539 @Override
540 public ImageBag read(InputStream inputStream) throws IOException {
541 return read(_fileUtil.getBytes(inputStream));
542 }
543
544 @Override
545 public RenderedImage scale(RenderedImage renderedImage, int width) {
546 if (width <= 0) {
547 return renderedImage;
548 }
549
550 int imageHeight = renderedImage.getHeight();
551 int imageWidth = renderedImage.getWidth();
552
553 double factor = (double)width / imageWidth;
554
555 int scaledHeight = (int)Math.round(factor * imageHeight);
556 int scaledWidth = width;
557
558 return doScale(renderedImage, scaledHeight, scaledWidth);
559 }
560
561 @Override
562 public RenderedImage scale(
563 RenderedImage renderedImage, int maxHeight, int maxWidth) {
564
565 int imageHeight = renderedImage.getHeight();
566 int imageWidth = renderedImage.getWidth();
567
568 if (maxHeight == 0) {
569 maxHeight = imageHeight;
570 }
571
572 if (maxWidth == 0) {
573 maxWidth = imageWidth;
574 }
575
576 if ((imageHeight <= maxHeight) && (imageWidth <= maxWidth)) {
577 return renderedImage;
578 }
579
580 double factor = Math.min(
581 (double)maxHeight / imageHeight, (double)maxWidth / imageWidth);
582
583 int scaledHeight = Math.max(1, (int)Math.round(factor * imageHeight));
584 int scaledWidth = Math.max(1, (int)Math.round(factor * imageWidth));
585
586 return doScale(renderedImage, scaledHeight, scaledWidth);
587 }
588
589 @Override
590 public void write(
591 RenderedImage renderedImage, String contentType, OutputStream os)
592 throws IOException {
593
594 if (contentType.contains(TYPE_BMP)) {
595 ImageEncoder imageEncoder = ImageCodec.createImageEncoder(
596 TYPE_BMP, os, null);
597
598 imageEncoder.encode(renderedImage);
599 }
600 else if (contentType.contains(TYPE_GIF)) {
601 encodeGIF(renderedImage, os);
602 }
603 else if (contentType.contains(TYPE_JPEG) ||
604 contentType.contains("jpeg")) {
605
606 ImageIO.write(renderedImage, "jpeg", os);
607 }
608 else if (contentType.contains(TYPE_PNG)) {
609 ImageIO.write(renderedImage, TYPE_PNG, os);
610 }
611 else if (contentType.contains(TYPE_TIFF) ||
612 contentType.contains("tif")) {
613
614 ImageEncoder imageEncoder = ImageCodec.createImageEncoder(
615 TYPE_TIFF, os, null);
616
617 imageEncoder.encode(renderedImage);
618 }
619 }
620
621 protected RenderedImage doScale(
622 RenderedImage renderedImage, int scaledHeight, int scaledWidth) {
623
624
625
626 BufferedImage originalBufferedImage = getBufferedImage(renderedImage);
627
628 BufferedImage scaledBufferedImage = new BufferedImage(
629 scaledWidth, scaledHeight, originalBufferedImage.getType());
630
631 int originalHeight = originalBufferedImage.getHeight();
632 int originalWidth = originalBufferedImage.getWidth();
633
634 if (((scaledHeight * 2) >= originalHeight) &&
635 ((scaledWidth * 2) >= originalWidth)) {
636
637 Graphics2D scaledGraphics2D = scaledBufferedImage.createGraphics();
638
639 scaledGraphics2D.drawImage(
640 originalBufferedImage, 0, 0, scaledWidth, scaledHeight, null);
641
642 scaledGraphics2D.dispose();
643
644 return scaledBufferedImage;
645 }
646
647 BufferedImage tempBufferedImage = new BufferedImage(
648 originalWidth, originalHeight, scaledBufferedImage.getType());
649
650 Graphics2D tempGraphics2D = tempBufferedImage.createGraphics();
651
652 RenderingHints renderingHints = new RenderingHints(
653 RenderingHints.KEY_INTERPOLATION,
654 RenderingHints.VALUE_INTERPOLATION_BILINEAR);
655
656 tempGraphics2D.setRenderingHints(renderingHints);
657
658 ColorModel originalColorModel = originalBufferedImage.getColorModel();
659
660 if (originalColorModel.hasAlpha()) {
661 tempGraphics2D.setComposite(AlphaComposite.Src);
662 }
663
664 int startHeight = scaledHeight;
665 int startWidth = scaledWidth;
666
667 while ((startHeight < originalHeight) && (startWidth < originalWidth)) {
668 startHeight *= 2;
669 startWidth *= 2;
670 }
671
672 originalHeight = startHeight / 2;
673 originalWidth = startWidth / 2;
674
675 tempGraphics2D.drawImage(
676 originalBufferedImage, 0, 0, originalWidth, originalHeight, null);
677
678 while ((originalHeight >= (scaledHeight * 2)) &&
679 (originalWidth >= (scaledWidth * 2))) {
680
681 originalHeight /= 2;
682
683 if (originalHeight < scaledHeight) {
684 originalHeight = scaledHeight;
685 }
686
687 originalWidth /= 2;
688
689 if (originalWidth < scaledWidth) {
690 originalWidth = scaledWidth;
691 }
692
693 tempGraphics2D.drawImage(
694 tempBufferedImage, 0, 0, originalWidth, originalHeight, 0, 0,
695 originalWidth * 2, originalHeight * 2, null);
696 }
697
698 tempGraphics2D.dispose();
699
700 Graphics2D scaledGraphics2D = scaledBufferedImage.createGraphics();
701
702 scaledGraphics2D.drawImage(
703 tempBufferedImage, 0, 0, scaledWidth, scaledHeight, 0, 0,
704 originalWidth, originalHeight, null);
705
706 scaledGraphics2D.dispose();
707
708 return scaledBufferedImage;
709 }
710
711 protected ImageMagick getImageMagick() {
712 if (_imageMagick == null) {
713 _imageMagick = ImageMagickImpl.getInstance();
714
715 _imageMagick.reset();
716 }
717
718 return _imageMagick;
719 }
720
721 protected RenderedImage read(byte[] bytes, String type) {
722 RenderedImage renderedImage = null;
723
724 try {
725 if (type.equals(TYPE_JPEG)) {
726 type = "jpeg";
727 }
728
729 ImageDecoder imageDecoder = ImageCodec.createImageDecoder(
730 type, new UnsyncByteArrayInputStream(bytes), null);
731
732 renderedImage = imageDecoder.decodeAsRenderedImage();
733 }
734 catch (IllegalArgumentException iae) {
735 if (_log.isDebugEnabled()) {
736 _log.debug(iae, iae);
737 }
738 }
739 catch (IOException ioe) {
740 if (_log.isDebugEnabled()) {
741 _log.debug(type + ": " + ioe.getMessage());
742 }
743 }
744
745 return renderedImage;
746 }
747
748 protected void orderImageReaderSpis() {
749 IIORegistry defaultIIORegistry = IIORegistry.getDefaultInstance();
750
751 ImageReaderSpi firstImageReaderSpi = null;
752 ImageReaderSpi secondImageReaderSpi = null;
753
754 Iterator<ImageReaderSpi> imageReaderSpis =
755 defaultIIORegistry.getServiceProviders(ImageReaderSpi.class, true);
756
757 while (imageReaderSpis.hasNext()) {
758 ImageReaderSpi imageReaderSpi = imageReaderSpis.next();
759
760 if (imageReaderSpi instanceof CMYKJPEGImageReaderSpi) {
761 secondImageReaderSpi = imageReaderSpi;
762 }
763 else {
764 String[] formatNames = imageReaderSpi.getFormatNames();
765
766 if (ArrayUtil.contains(formatNames, TYPE_JPEG, true) ||
767 ArrayUtil.contains(formatNames, "jpeg", true)) {
768
769 firstImageReaderSpi = imageReaderSpi;
770 }
771 }
772 }
773
774 if ((firstImageReaderSpi != null) && (secondImageReaderSpi != null)) {
775 defaultIIORegistry.setOrdering(
776 ImageReaderSpi.class, firstImageReaderSpi,
777 secondImageReaderSpi);
778 }
779 }
780
781 protected byte[] toMultiByte(int intValue) {
782 int numBits = 32;
783 int mask = 0x80000000;
784
785 while ((mask != 0) && ((intValue & mask) == 0)) {
786 numBits--;
787 mask >>>= 1;
788 }
789
790 int numBitsLeft = numBits;
791 byte[] multiBytes = new byte[(numBitsLeft + 6) / 7];
792
793 int maxIndex = multiBytes.length - 1;
794
795 for (int b = 0; b <= maxIndex; b++) {
796 multiBytes[b] = (byte)((intValue >>> ((maxIndex - b) * 7)) & 0x7f);
797
798 if (b != maxIndex) {
799 multiBytes[b] |= (byte)0x80;
800 }
801 }
802
803 return multiBytes;
804 }
805
806 private ImageToolImpl() {
807 ImageIO.setUseCache(PropsValues.IMAGE_IO_USE_DISK_CACHE);
808
809 orderImageReaderSpis();
810 }
811
812 private static Log _log = LogFactoryUtil.getLog(ImageToolImpl.class);
813
814 private static ImageTool _instance = new ImageToolImpl();
815
816 private static FileImpl _fileUtil = FileImpl.getInstance();
817 private static ImageMagick _imageMagick;
818
819 private Image _defaultCompanyLogo;
820 private Image _defaultOrganizationLogo;
821 private Image _defaultSpacer;
822 private Image _defaultUserFemalePortrait;
823 private Image _defaultUserMalePortrait;
824
825 private class RenderedImageFuture implements Future<RenderedImage> {
826
827 public RenderedImageFuture(
828 Future<?> future, File outputFile, String type) {
829
830 _future = future;
831 _outputFile = outputFile;
832 _type = type;
833 }
834
835 @Override
836 public boolean cancel(boolean mayInterruptIfRunning) {
837 if (_future.isCancelled() || _future.isDone()) {
838 return false;
839 }
840
841 _future.cancel(true);
842
843 return true;
844 }
845
846 @Override
847 public RenderedImage get()
848 throws ExecutionException, InterruptedException {
849
850 _future.get();
851
852 byte[] bytes = new byte[0];
853
854 try {
855 bytes = _fileUtil.getBytes(_outputFile);
856
857 ImageBag imageBag = read(bytes);
858
859 return imageBag.getRenderedImage();
860 }
861 catch (IOException ioe) {
862 throw new ExecutionException(ioe);
863 }
864 }
865
866 @Override
867 public RenderedImage get(long timeout, TimeUnit timeUnit)
868 throws ExecutionException, InterruptedException, TimeoutException {
869
870 _future.get(timeout, timeUnit);
871
872 byte[] bytes = new byte[0];
873
874 try {
875 bytes = _fileUtil.getBytes(_outputFile);
876
877 ImageBag imageBag = read(bytes);
878
879 return imageBag.getRenderedImage();
880 }
881 catch (IOException ioe) {
882 throw new ExecutionException(ioe);
883 }
884 }
885
886 @Override
887 public boolean isCancelled() {
888 return _future.isCancelled();
889 }
890
891 @Override
892 public boolean isDone() {
893 return _future.isDone();
894 }
895
896 private final Future<?> _future;
897 private final File _outputFile;
898 private final String _type;
899
900 }
901
902 }