/** * We compute a sampling ratio but we keep roughly samplingFactor^2 times more pixels so that after * rescaling quality is better than with sampling using maximal possible ratio. * We compute ratio for both width and height and than discard the one that could result in exceeding * memory expectations defined by samplingFactor. */ static public int computeSubsamplingRatio(final ThumbnailDimension original, final ThumbnailDimension scaled, final int samplingFactor) { final double widthRatio = (double) original.getWidth() / (double) scaled.getWidth(); final double heightRatio = (double) original.getHeight() / (double) scaled.getHeight(); final double maxRatio = Math.max(widthRatio, heightRatio); final double ratio = maxRatio / (double) samplingFactor; return Math.max(1, (int) Math.floor(ratio)); } }
public static ThumbnailDimension determineScaledDimensions(int maxWidth, int maxHeight, int imageWidth, int imageHeight) { if (maxHeight > imageHeight && maxWidth > imageWidth) { return new ThumbnailDimension(imageWidth, imageHeight); } // Determine scale size. // Retain original image proportions with scaled image. double thumbRatio = (double) maxWidth / (double) maxHeight; double imageRatio = (double) imageWidth / (double) imageHeight; if (thumbRatio < imageRatio) { return new ThumbnailDimension(maxWidth, (int) Math.max(1, maxWidth / imageRatio)); } else { return new ThumbnailDimension((int) Math.max(1, maxHeight * imageRatio), maxHeight); } }
/** * Checks whether two <code>Thumbnail</code> objects have equal values. * * @param anObject The object to compare this {@code Thumbnail} against */ @Override public boolean equals(final Object anObject) { if (this == anObject) { return true; } if (!(anObject instanceof Thumbnail)) { return false; } if (!super.equals(anObject)) { return false; } final Thumbnail thumbnail = (Thumbnail) anObject; if (attachmentId != thumbnail.attachmentId) { return false; } if (filename != null ? !filename.equals(thumbnail.filename) : thumbnail.filename != null) { return false; } if (mimeType != thumbnail.mimeType) { return false; } return true; }
private BufferedImage scaleImage(int maxWidth, int maxHeight, ImageInputStream imageInputStream) throws IOException { final Optional<ImageReader> imageReader = ThumbnailUtil.getFirstImageReader(imageInputStream); if (!imageReader.isPresent()) { throw new IOException("Cannot read the image"); } final ImageReader reader = imageReader.get(); try { reader.setInput(imageInputStream); final ThumbnailDimension originalImageDimensions = new ThumbnailDimension(reader.getWidth(0), reader.getHeight(0)); final ThumbnailDimension scaledImageDimension = ThumbnailUtil.determineScaledDimensions(maxWidth, maxHeight, originalImageDimensions.getWidth(), originalImageDimensions.getHeight()); final int ratio = ThumbnailUtil.computeSubsamplingRatio(originalImageDimensions, scaledImageDimension, samplingFactor); final ImageReadParam param = reader.getDefaultReadParam(); param.setSourceSubsampling(ratio, ratio, 0, 0); final BufferedImage scaledImage = reader.read(0, param); //Subsampling does not return an exact size of an image - we need to resize it return scaleImage(scaledImage, scaledImageDimension); } finally { reader.dispose(); } }
/** * Returns the hash code for this <code>Thumbnail</code>. * * @return the hash code for this <code>Thumbnail</code> */ @Override public int hashCode() { int result = super.hashCode(); result = 31 * result + (mimeType != null ? mimeType.hashCode() : 0); result = 31 * result + (filename != null ? filename.hashCode() : 0); result = 31 * result + (int) (attachmentId ^ (attachmentId >>> 32)); return result; }
/** * This method should take BufferedImage argument, but takes just Image for backward compatibility (so that the * client code can stay intact). Normally anyway a BufferedImage instance will be provided and the image will be * directly processed without transforming it to BufferedImage first. * * @param imageToScale image to scale (BufferedImage is welcome, other image types will be transformed to * BufferedImage first) * @param newDimensions desired max. dimensions * @return scaled image */ public BufferedImage scaleImage(Image imageToScale, ThumbnailDimension newDimensions) { final BufferedImage sourceImage = Pictures.toBufferedImage(imageToScale); final Image scaledInstance = sourceImage.getScaledInstance(newDimensions.getWidth(), newDimensions.getHeight(), Image.SCALE_SMOOTH); final BufferedImage bufferedScaledImage = new BufferedImage(newDimensions.getWidth(), newDimensions.getHeight(), Pictures.hasAlpha(imageToScale) ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB); final Graphics graphics = bufferedScaledImage.getGraphics(); try { graphics.drawImage(scaledInstance, 0, 0, null); } finally { graphics.dispose(); } return bufferedScaledImage; }
public static ThumbnailDimension dimensionsForImage(final @Nonnull InputStream inputStream) throws IOException { final BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream); try { final ImageInputStream imageInputStream = getImageInputStream(inputStream); try { final Optional<ImageReader> imageReader = getFirstImageReader(imageInputStream); if (!imageReader.isPresent()) { throw new IOException("There is no ImageReader available for the given ImageInputStream"); } // Use the first one available final ImageReader reader = imageReader.get(); try { reader.setInput(imageInputStream); return new ThumbnailDimension(reader.getWidth(0), reader.getHeight(0)); } finally { reader.dispose(); } } finally { imageInputStream.close(); } } finally { IOUtils.closeQuietly(bufferedInputStream); } }
public UploadedAvatar scaleImageToTempFile(final Image sourceImage, final File targetFile, final int edgeSize) throws IOException { ThumbnailDimension targetDimension = thumber.determineScaleSize(edgeSize, edgeSize, sourceImage.getWidth(null), sourceImage.getHeight(null)); BufferedImage scaledImage = thumber.scaleImage(sourceImage, targetDimension); ImageIO.write(scaledImage, AVATAR_IMAGE_FORMAT, targetFile); return new UploadedAvatar(targetFile, AVATAR_IMAGE_FORMAT_FULL.getContentType(), targetDimension.getWidth(), targetDimension.getHeight()); } }
private Thumbnail readThumbnail(@Nonnull final Attachment attachment, @Nonnull final File thumbnailFile) { if (thumbnailFile.exists()) { log.debug("Thumbnail file '{}' already exists. Returning existing thumbnail.", thumbnailFile); InputStream inputStream = null; try { inputStream = new FileInputStream(thumbnailFile); final ThumbnailDimension thumbnailDimension = ThumbnailUtil.dimensionsForImage(inputStream); return new Thumbnail(thumbnailDimension.getHeight(), thumbnailDimension.getWidth(), thumbnailFile.getName(), attachment.getId(), MIME_TYPE); } catch (IOException asd) { log.debug("Unable to read image data from existing thumbnail file '{}'. Deleting this thumbnail.", thumbnailFile); deleteQuietly(thumbnailFile); } finally { closeQuietly(inputStream); } } return null; }