source: trunk/grails-app/utils/Imaging.groovy @ 672

Last change on this file since 672 was 182, checked in by gav, 15 years ago

Add support for inventory item Pictures and Images.
Add new PersonService, refactor CreateDataService and TaskService to suite.

File size: 6.5 KB
Line 
1import java.awt.AlphaComposite
2import java.awt.Color
3import java.awt.Graphics2D
4import java.awt.geom.AffineTransform
5import java.awt.geom.Rectangle2D
6import java.awt.image.AffineTransformOp
7import java.awt.image.BufferedImage
8import java.io.ByteArrayInputStream
9import java.io.ByteArrayOutputStream
10import javax.imageio.ImageIO
11
12class Imaging {
13
14    static def createAll(InventoryItem inventoryItem, Picture picture, InputStream stream) {
15        BufferedImage original = ImageIO.read(stream)
16        picture.contentType = 'image/jpeg'
17        picture.width = original.width
18        picture.height = original.height
19        def images = [ 
20            new Image(inventoryItem: inventoryItem, picture: picture, size: Image.Original),
21            new Image(inventoryItem: inventoryItem, picture: picture, size: Image.Large),
22            new Image(inventoryItem: inventoryItem, picture: picture, size: Image.Medium),
23            new Image(inventoryItem: inventoryItem, picture: picture, size: Image.Small)
24            ]
25        ByteArrayOutputStream output = new ByteArrayOutputStream(1024 * 1024)
26        updateImages(images, original, output)
27        images
28    }
29   
30    static def updateAll(Picture picture) {
31        def operation = picture.operation
32        if (operation == Picture.NoOp) {
33            return null
34        }
35        def images = picture.images.toArray() // Image.findAllByPicture(picture, [ sort: 'size', order: 'asc' ])
36        BufferedImage original = ImageIO.read(new ByteArrayInputStream(images[0].data))
37        AffineTransform transform = new AffineTransform();
38        def op = null
39        boolean paint = false
40        Integer width = original.width
41        Integer height = original.height
42        switch (operation) {
43            case Picture.RotateClockWise90:
44                transform.rotate(Math.PI / 2.0)
45                transform.translate(0, -height)
46                op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
47                width = original.height
48                height = original.width
49                paint = true
50                break
51            case Picture.RotateAntiClockWise90:
52                transform.rotate(-Math.PI / 2.0)
53                transform.translate(-width, 0)
54                op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
55                width = original.height
56                height = original.width
57                paint = true
58                break
59            case Picture.Rotate180:
60                transform.rotate(Math.PI)
61                transform.translate(-width, -height)
62                op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
63                break
64            case Picture.Flip: // vertical
65                transform.scale(-1.0d, 1.0d)
66                transform.translate(-width, 0)
67                op = new AffineTransformOp(transform, AffineTransformOp.TYPE_NEAREST_NEIGHBOR)
68                break
69            case Picture.Flop: // horizontal
70                transform.scale(1.0d, -1.0d)
71                transform.translate(0, -height)
72                op = new AffineTransformOp(transform, AffineTransformOp.TYPE_NEAREST_NEIGHBOR)
73                break
74            default:
75                return images
76                break
77        }
78        BufferedImage modified = op.filter(original, null);
79        if (paint) {
80            BufferedImage changed = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB)
81            Graphics2D graphics = changed.createGraphics()
82            graphics.drawImage(modified, 0, 0, width, height, null)
83            graphics.dispose()
84            modified = changed
85            picture.width = width
86            picture.height = height
87        }
88        ByteArrayOutputStream output = new ByteArrayOutputStream(1024 * 1024)
89        updateImages(images, modified, output)
90        images
91    }
92
93    private static def updateImages(images, original, stream) {
94        updateImage(images[0], original, 'jpeg', stream)
95        def large = resizeImage(original, dimensions(Image.Large), false)
96        updateImage(images[1], large, 'png', stream)
97        updateImage(images[2], resizeImage(large, dimensions(Image.Medium), true), 'png', stream)
98        updateImage(images[3], resizeImage(large, dimensions(Image.Small), true), 'png', stream)
99    }
100
101    private static def updateImage(image, data, format, stream) {
102        image.contentType = "image/${format}"
103        image.width = data.width
104        image.height = data.height
105        stream.reset()
106        if (!ImageIO.write(data, format, stream)) {
107            throw new IOException("Can't write the image in the given format '${format}'")
108        }
109        image.data = stream.toByteArray()
110    }
111
112    private static def dimensions(size) {
113        [ Image.Widths[size], Image.Heights[size] ]
114    }   
115
116    private static def resizeImage(imageBuffer, dims, fit) {
117        Integer width = dims[0]
118        Integer height = dims[1]
119        Integer imageWidth = imageBuffer.width
120        Integer imageHeight = imageBuffer.height
121     
122        Double widthScale = (double)width / (double)imageWidth
123        Double heightScale = (double)height / (double)imageHeight
124        BufferedImage resizedImage = imageBuffer
125        if (widthScale < 1.0d || heightScale < 1.0d) {
126            Double scale = Math.min(widthScale, heightScale)
127            def transform = new AffineTransform()
128            transform.scale(scale, scale)
129            def op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR)
130            resizedImage = op.filter(imageBuffer, null)
131            imageWidth = resizedImage.width
132            imageHeight = resizedImage.height
133        }
134
135        if (fit && (imageWidth < width || imageHeight < height)) {
136            BufferedImage fittedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB)
137            Integer left = (width - imageWidth) / 2
138            Integer top = (height - imageHeight) / 2
139            Graphics2D graphics = fittedImage.createGraphics()
140            graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f))
141            graphics.fill(new Rectangle2D.Double(0, 0, width, height))
142            graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f))
143            graphics.drawImage(resizedImage, left, top, imageWidth, imageHeight, null)
144            graphics.dispose()
145            return fittedImage
146        }
147        resizedImage
148    }
149}
Note: See TracBrowser for help on using the repository browser.