package com.swingsane.business.image.transform; import java.awt.Color; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.io.File; import javax.imageio.ImageIO; import com.swingsane.business.image.ImageDeskew; import com.swingsane.gui.panel.DeskewTransformSettingsPanel; import com.swingsane.gui.panel.ITransformSettingsPanel; import com.swingsane.preferences.IPreferredDefaults; /** * @author Roland Quast (roland@formreturn.com) * */ public class DeskewTransform implements IImageTransform { private double deskewThreshold; private File sourceImageFile; private File outputImageFile; private static final ImageTransformType imageTransformType = ImageTransformType.DESKEW; @Override public void configure(IPreferredDefaults preferredDefaultsImpl) { deskewThreshold = preferredDefaultsImpl.getDefaultDeskewThreshold(); } public final double getDeskewThreshold() { return deskewThreshold; } @Override public final File getOutputImageFile() { return outputImageFile; } @Override public final File getSourceImageFile() { return sourceImageFile; } @Override public final ITransformSettingsPanel getTransformSettingsPanel() { DeskewTransformSettingsPanel transformSettingsPanel = new DeskewTransformSettingsPanel(); transformSettingsPanel.setTransform(this); return transformSettingsPanel; } public final BufferedImage rotate(BufferedImage image, double angle, int cx, int cy) { int width = image.getWidth(null); int height = image.getHeight(null); int minX, minY, maxX, maxY; minX = minY = maxX = maxY = 0; int[] corners = { 0, 0, width, 0, width, height, 0, height }; double theta = Math.toRadians(angle); for (int i = 0; i < corners.length; i += 2) { int x = (int) (((Math.cos(theta) * (corners[i] - cx)) - (Math.sin(theta) * (corners[i + 1] - cy))) + cx); int y = (int) ((Math.sin(theta) * (corners[i] - cx)) + (Math.cos(theta) * (corners[i + 1] - cy)) + cy); if (x > maxX) { maxX = x; } if (x < minX) { minX = x; } if (y > maxY) { maxY = y; } if (y < minY) { minY = y; } } cx = (cx - minX); cy = (cy - minY); BufferedImage bufferedImage = new BufferedImage((maxX - minX), (maxY - minY), image.getType()); Graphics2D graphics2d = bufferedImage.createGraphics(); graphics2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); graphics2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED); graphics2d.setBackground(Color.white); graphics2d.fillRect(0, 0, bufferedImage.getWidth(), bufferedImage.getHeight()); AffineTransform at = new AffineTransform(); at.rotate(theta, cx, cy); graphics2d.setTransform(at); graphics2d.drawImage(image, -minX, -minY, null); graphics2d.dispose(); return bufferedImage; } public final void setDeskewThreshold(double deskewThreshold) { this.deskewThreshold = deskewThreshold; } @Override public final void setOutputImageFile(File outputImageFile) { this.outputImageFile = outputImageFile; } @Override public final void setSourceImageFile(File sourceImageFile) { this.sourceImageFile = sourceImageFile; } @Override public final String toString() { return imageTransformType.toString(); } @Override public final void transform() throws Exception { BufferedImage bufferedImage = ImageIO.read(sourceImageFile); ImageDeskew imageDeskew = new ImageDeskew(bufferedImage); double angle = imageDeskew.getSkewAngle(); ImageIO.write( rotate(bufferedImage, -angle, bufferedImage.getWidth() / 2, bufferedImage.getHeight() / 2), "PNG", outputImageFile); } }