import java.awt.AlphaComposite import java.awt.Color import java.awt.Graphics2D import java.awt.geom.AffineTransform import java.awt.geom.Rectangle2D import java.awt.image.AffineTransformOp import java.awt.image.BufferedImage import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream import javax.imageio.ImageIO class Imaging { static def createAll(InventoryItem inventoryItem, Picture picture, InputStream stream) { BufferedImage original = ImageIO.read(stream) picture.contentType = 'image/jpeg' picture.width = original.width picture.height = original.height def images = [ new Image(inventoryItem: inventoryItem, picture: picture, size: Image.Original), new Image(inventoryItem: inventoryItem, picture: picture, size: Image.Large), new Image(inventoryItem: inventoryItem, picture: picture, size: Image.Medium), new Image(inventoryItem: inventoryItem, picture: picture, size: Image.Small) ] ByteArrayOutputStream output = new ByteArrayOutputStream(1024 * 1024) updateImages(images, original, output) images } static def updateAll(Picture picture) { def operation = picture.operation if (operation == Picture.NoOp) { return null } def images = picture.images.toArray() // Image.findAllByPicture(picture, [ sort: 'size', order: 'asc' ]) BufferedImage original = ImageIO.read(new ByteArrayInputStream(images[0].data)) AffineTransform transform = new AffineTransform(); def op = null boolean paint = false Integer width = original.width Integer height = original.height switch (operation) { case Picture.RotateClockWise90: transform.rotate(Math.PI / 2.0) transform.translate(0, -height) op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR); width = original.height height = original.width paint = true break case Picture.RotateAntiClockWise90: transform.rotate(-Math.PI / 2.0) transform.translate(-width, 0) op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR); width = original.height height = original.width paint = true break case Picture.Rotate180: transform.rotate(Math.PI) transform.translate(-width, -height) op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR); break case Picture.Flip: // vertical transform.scale(-1.0d, 1.0d) transform.translate(-width, 0) op = new AffineTransformOp(transform, AffineTransformOp.TYPE_NEAREST_NEIGHBOR) break case Picture.Flop: // horizontal transform.scale(1.0d, -1.0d) transform.translate(0, -height) op = new AffineTransformOp(transform, AffineTransformOp.TYPE_NEAREST_NEIGHBOR) break default: return images break } BufferedImage modified = op.filter(original, null); if (paint) { BufferedImage changed = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB) Graphics2D graphics = changed.createGraphics() graphics.drawImage(modified, 0, 0, width, height, null) graphics.dispose() modified = changed picture.width = width picture.height = height } ByteArrayOutputStream output = new ByteArrayOutputStream(1024 * 1024) updateImages(images, modified, output) images } private static def updateImages(images, original, stream) { updateImage(images[0], original, 'jpeg', stream) def large = resizeImage(original, dimensions(Image.Large), false) updateImage(images[1], large, 'png', stream) updateImage(images[2], resizeImage(large, dimensions(Image.Medium), true), 'png', stream) updateImage(images[3], resizeImage(large, dimensions(Image.Small), true), 'png', stream) } private static def updateImage(image, data, format, stream) { image.contentType = "image/${format}" image.width = data.width image.height = data.height stream.reset() if (!ImageIO.write(data, format, stream)) { throw new IOException("Can't write the image in the given format '${format}'") } image.data = stream.toByteArray() } private static def dimensions(size) { [ Image.Widths[size], Image.Heights[size] ] } private static def resizeImage(imageBuffer, dims, fit) { Integer width = dims[0] Integer height = dims[1] Integer imageWidth = imageBuffer.width Integer imageHeight = imageBuffer.height Double widthScale = (double)width / (double)imageWidth Double heightScale = (double)height / (double)imageHeight BufferedImage resizedImage = imageBuffer if (widthScale < 1.0d || heightScale < 1.0d) { Double scale = Math.min(widthScale, heightScale) def transform = new AffineTransform() transform.scale(scale, scale) def op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR) resizedImage = op.filter(imageBuffer, null) imageWidth = resizedImage.width imageHeight = resizedImage.height } if (fit && (imageWidth < width || imageHeight < height)) { BufferedImage fittedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB) Integer left = (width - imageWidth) / 2 Integer top = (height - imageHeight) / 2 Graphics2D graphics = fittedImage.createGraphics() graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f)) graphics.fill(new Rectangle2D.Double(0, 0, width, height)) graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f)) graphics.drawImage(resizedImage, left, top, imageWidth, imageHeight, null) graphics.dispose() return fittedImage } resizedImage } }