import java.awt.image.BufferedImage; import javax.imageio.ImageIO; import java.io.File; import java.io.IOException; import java.lang.Math; class ParseOptions { String input = ""; String output = ""; int radius = 30; public void parse(String[] args) { input = args[args.length-1]; output = "enhanced_" + input; for (int i = 0; i < (args.length - 1); i++) { //System.out.println(args[i]); if (args[i].equals("-o") || args[i].equals("--output")) { output = args[i+1]; ++i; } if (args[i].equals("-r") || args[i].equals("--radius")) { radius = Integer.parseInt(args[i+1]); ++i; } if (args[i].equals("-d") || args[i].equals("--dpi")) { radius = (Integer.parseInt(args[i+1])) / 10; ++i; } } } } class EnhanceBookPhoto { static double distance(float x1, float y1, float x2, float y2) { return(Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2))); } static double interpolate(int x1, double y1, int x2, double y2, double x) { if (x1 == x2) { return(y1); } double yStepPerUnitOfX = (y2 - y1) / ((double)x2 - (double)x1); double y = y1 + (yStepPerUnitOfX * (double)(x - x1)); return y; } static int interpolate2d(double x, double y, int[][] blurArray) { x = ((int)x >= blurArray.length) ? (blurArray.length - 1) : x; y = ((int)y >= blurArray[0].length) ? (blurArray[0].length - 1) : y; if ((x == Math.round(x)) && (y == Math.round(y))) { return(blurArray[(int)x][(int)y]); } int prevX = (int)x; int prevY = (int)y; int nextX = ((int)x + 1) >= blurArray.length ? (int)x : (int)x + 1; int nextY = ((int)y + 1) >= blurArray[0].length ? (int)y : (int)y + 1; int NW = blurArray[prevX][prevY]; int NE = blurArray[nextX][prevY]; int SW = blurArray[prevX][nextY]; int SE = blurArray[nextX][nextY]; double valueInUpperRow = interpolate(prevX, NW, nextX, NE, x); double valueInLowerRow = interpolate(prevX, SW, nextX, SE, x); double result = interpolate(prevY, valueInUpperRow, nextY, valueInLowerRow, y); return((int)result); } static int[] pixel2rgb(int pixel) { int[] result = { (pixel & 0x00FF0000) >> 16, (pixel & 0x0000FF00) >> 8, (pixel & 0x000000FF) }; return(result); } static int pixelValue(int pixel) { int[] samples = { (pixel & 0x00FF0000) >> 16, (pixel & 0x0000FF00) >> 8, (pixel & 0x000000FF) }; return ((samples[0] + samples[1] + samples[2]) / 3); } static int pixel2int(int[] pixel) { return( (pixel[0] << 16) + (pixel[1] << 8) + pixel[2] ); } static void enhanceBookPhoto(String input, String output, int radius) { BufferedImage originalImage = null; try { originalImage = ImageIO.read(new File(input)); } catch (IOException e) { e.printStackTrace(); } int originalHeight = originalImage.getHeight(null); int originalWidth = originalImage.getWidth(null); int bluredHeight = (int)(originalHeight / radius); int bluredWidth = (int)(originalWidth / radius); int[][] blured = new int[bluredWidth][bluredHeight]; for (int y = 0; y < bluredHeight; y++) { for (int x = 0; x < bluredWidth; x++) { int sum = 0; for (int bluredX = x * radius; bluredX < (x + 1) * radius; bluredX++) { for (int bluredY = y * radius; bluredY < (y + 1) * radius; bluredY++) { sum += pixelValue(originalImage.getRGB(bluredX, bluredY)); } } blured[x][y] = sum / (radius*radius); } } for (int y = 0; y < originalHeight; y++) { for (int x = 0; x < originalWidth; x++) { int[] pixel = pixel2rgb(originalImage.getRGB(x, y)); for (int channel = 0; channel < 3; channel++) { float bluredX = x/(float)radius; float bluredY = y/(float)radius; float bluredSample = interpolate2d(bluredX, bluredY, blured) / 255f; float actualSample = pixel[channel] / 255f; float result = (bluredSample > 0) ? (actualSample / bluredSample) : 1; result = (result > 1) ? 1 : result; pixel[channel] = (int)(result * 255); //pixel[channel] = (int)(bluredSample*255); } originalImage.setRGB(x, y, pixel2int(pixel)); } } try { String format = output.substring(output.lastIndexOf('.') + 1); ImageIO.write(originalImage, format, new File(output)); } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) { if (args.length == 0) { System.out.println("Usage: java -jar enhance_book_photo.jar picture.png\nYou can use some options, too - read docs for details."); System.exit(0); } ParseOptions parser = new ParseOptions(); parser.parse(args); enhanceBookPhoto(parser.input, parser.output, parser.radius); } }