Last active
August 29, 2015 14:09
-
-
Save bendem/0c2f74f8af8eb0adf674 to your computer and use it in GitHub Desktop.
Image edition tests, main class is PictureTest (java 8!)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package be.bendem.testing.utils; | |
public class ColorUtils { | |
private ColorUtils() {} | |
public static int[] decompose(int color) { | |
int[] rgb = new int[3]; | |
rgb[0] = color >> 16 & 0xFF; | |
rgb[1] = color >> 8 & 0xFF; | |
rgb[2] = color & 0xFF; | |
return rgb; | |
} | |
public static int recompose(int[] rgb) { | |
if(rgb.length != 3) { | |
throw new IllegalArgumentException("Provided color doesn't have 3 components"); | |
} | |
int color = rgb[0]; | |
color = (color << 8) | (rgb[1] & 0xFF); | |
color = (color << 8) | (rgb[2] & 0xFF); | |
return color; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package be.bendem.testing.utils; | |
@FunctionalInterface | |
public interface IntArrayBiFunction { | |
public int[] apply(int[] a, int[] b); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package be.bendem.testing.utils; | |
public class NumberUtils { | |
private NumberUtils() {} | |
public static int decodeHexa(String str) { | |
return Integer.decode((str.startsWith("0x") ? "" : "0x") + str); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package be.bendem.testing; | |
import be.bendem.testing.utils.ColorUtils; | |
import be.bendem.testing.utils.IntArrayBiFunction; | |
import be.bendem.testing.utils.NumberUtils; | |
import java.awt.image.BufferedImage; | |
import java.io.File; | |
import java.io.IOException; | |
import java.util.Arrays; | |
import java.util.function.IntBinaryOperator; | |
import javax.imageio.ImageIO; | |
public class PictureTest { | |
private final BufferedImage image; | |
private final File output; | |
private final String extension; | |
private final Operation operation; | |
private final int[] colorMask; | |
public PictureTest(File file, Operation operation, int[] colorMask) throws IOException { | |
String[] nameParts = file.getName().split("\\."); | |
extension = nameParts[nameParts.length - 1]; | |
output = new File("./output." + extension); | |
this.image = ImageIO.read(file); | |
this.operation = operation; | |
this.colorMask = colorMask; | |
System.out.println("Options are: " | |
+ "file=" + file.getName() + " | " | |
+ "operation=" + operation.name() + " | " | |
+ "colormask=" + Arrays.toString(colorMask) + " | " | |
+ "colormaskhexa=" + (colorMask == null ? "none" : Integer.toHexString(ColorUtils.recompose(colorMask))) | |
); | |
} | |
private void doStuff() throws IOException { | |
for(int i = 0; i < image.getWidth(); ++i) { | |
for(int j = 0; j < image.getHeight(); ++j) { | |
int rgbInt = image.getRGB(i, j); | |
int[] rgb = ColorUtils.decompose(rgbInt); | |
rgbInt >>= 24; // Save missed precision | |
// Applying provided mask | |
rgb = operation.apply(rgb, colorMask); | |
image.setRGB(i, j, ColorUtils.recompose(rgb) | rgbInt << 24); // Readds precision | |
} | |
} | |
} | |
private void save() throws IOException { | |
ImageIO.write(image, extension, output); | |
} | |
public static void main(String[] args) throws Exception { | |
if(args.length < 1) { | |
System.err.println("No file path provided"); | |
return; | |
} | |
File file = new File(args[0]); | |
if(!file.exists() || !file.isFile()) { | |
System.err.println("File not found :("); | |
return; | |
} | |
// Operation | |
if(args.length < 2) { | |
System.err.println("No operation provided"); | |
} | |
Operation operation = Operation.valueOf(args[1].toUpperCase()); | |
int colorMask[]; | |
if(operation == Operation.AVG) { | |
colorMask = null; | |
} else if(args.length == 3) { | |
colorMask = ColorUtils.decompose(NumberUtils.decodeHexa(args[2])); | |
} else { | |
System.err.println("Color should be provided as an hexacolor (like #ff3366)"); | |
return; | |
} | |
PictureTest test = new PictureTest(file, operation, colorMask); | |
test.doStuff(); | |
test.save(); | |
} | |
public enum Operation { | |
/** | |
* Adds the color mask to the provided color | |
* (generally brightens color components) | |
*/ | |
ADD((rgb, mask) -> arrayMap(new int[3], rgb, mask, (x, y) -> x + y)), | |
/** | |
* Substract the color mask from the provided color | |
* (generally darkens color components) | |
*/ | |
SUBSTRACT((rgb, mask) -> arrayMap(new int[3], rgb, mask, (x, y) -> x - y)), | |
/** | |
* Applies an "and" operation on the provided color | |
* (generally removes parts of the provided colors) | |
*/ | |
AND((rgb, mask) -> arrayMap(new int[3], rgb, mask, (x, y) -> x & y)), | |
/** | |
* Applies an "or" operation on the provided color | |
* (generally adds color components to the provided colors) | |
*/ | |
OR((rgb, mask) -> arrayMap(new int[3], rgb, mask, (x, y) -> x | y)), | |
/** | |
* Computes the average out of the 3 components (used to get gray colors) | |
*/ | |
AVG((rgb, unused) -> { | |
int[] result = new int[3]; | |
double avg = Arrays.stream(rgb) | |
.average() | |
.getAsDouble(); | |
int rounded = (int) (Math.round(avg) & 0xff); | |
// Applying provided mask | |
for(int k = 0; k < 3; ++k) { | |
result[k] = rounded; | |
} | |
return result; | |
}) | |
; | |
private final IntArrayBiFunction function; | |
Operation(IntArrayBiFunction function) { | |
this.function = function; | |
} | |
public int[] apply(int[] a, int[] b) { | |
int[] result = function.apply(a, b); | |
for(int i = 0; i < result.length; i++) { | |
if(result[i] < 0) { | |
result[i] = 0; | |
} else if(result[i] > 0xff) { | |
result[i] = 0xff; | |
} | |
} | |
return result; | |
} | |
private static int[] arrayMap(int[] result, int[] a, int[] b, IntBinaryOperator function) { | |
for(int i = 0; i < a.length; i++) { | |
result[i] = function.applyAsInt(a[i], b[i]); | |
} | |
return result; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment