View Javadoc

1   package com.atlassian.core.util.thumbnail;
2   
3   import com.atlassian.core.util.ReusableBufferedInputStream;
4   import com.google.common.base.Optional;
5   
6   import javax.imageio.ImageIO;
7   import javax.imageio.ImageReadParam;
8   import javax.imageio.ImageReader;
9   import javax.imageio.stream.ImageInputStream;
10  import java.awt.image.BufferedImage;
11  import java.io.IOException;
12  import java.io.InputStream;
13  import java.util.Iterator;
14  
15  public class StreamImageScale implements ImageScaler
16  {
17      private final DimensionsHelper dimensionsHelper;
18  
19      public StreamImageScale(DimensionsHelper dimensionsHelper)
20      {
21          this.dimensionsHelper = dimensionsHelper;
22      }
23  
24      @Override
25      public BufferedImage scaleImage(int maxWidth, int maxHeight, ReusableBufferedInputStream imageStream) throws IOException
26      {
27          final ImageInputStream imageInputStream = getImageInputStream(imageStream);
28          final Optional<ImageReader> imageReader = getImageReader(imageInputStream);
29  
30          if (!imageReader.isPresent())
31          {
32              throw new IOException("Cannot read the image");
33          }
34  
35          final ImageReader reader = imageReader.get();
36          try
37          {
38              reader.setInput(imageInputStream);
39  
40              final Dimensions scaledDimensions = dimensionsHelper.determineScaledDimensions(maxWidth, maxHeight, reader.getWidth(0), reader.getHeight(0));
41              int ratio = (int) Math.floor(((double) reader.getWidth(0) / (double) scaledDimensions.getWidth()));
42  
43              final ImageReadParam param = reader.getDefaultReadParam();
44              param.setSourceSubsampling(ratio, ratio, 0, 0);
45  
46              final BufferedImage scaledImage = reader.read(0, param);
47              //Subsampling does not return an exact size of an image - we can force it by cropping an image
48              return scaledImage.getSubimage(0, 0,
49                      Math.min(scaledDimensions.getWidth(), scaledImage.getWidth()),
50                      Math.min(scaledDimensions.getHeight(), scaledImage.getHeight()));
51          }
52          finally
53          {
54              reader.dispose();
55          }
56      }
57  
58      ImageInputStream getImageInputStream(InputStream inputStream) throws IOException
59      {
60          return ImageIO.createImageInputStream(inputStream);
61      }
62  
63      Optional<ImageReader> getImageReader(ImageInputStream imageInputStream) throws IOException
64      {
65          final Iterator<ImageReader> readers = ImageIO.getImageReaders(imageInputStream);
66          return readers.hasNext() ? Optional.of(readers.next()) : Optional.<ImageReader>absent();
67      }
68  
69  }