This is the new Composite class for a Multiply(Overlay) effect made by Kristopher Ives(Howto perform a MULTIPLY composite effect using Graphics2D). As far as I can tell he's been inactive for quite some time. Every time I run the Main class all I get is "Expected integer sample type" exception which is thrown when:
'(r.getSampleModel().getDataType() != DataBuffer.TYPE_INT)'
import java.awt.*;
import java.awt.image.ColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
public class MultiplyComposite implements Composite, CompositeContext {
protected void checkRaster(Raster r) {
if (r.getSampleModel().getDataType() != DataBuffer.TYPE_INT) {
throw new IllegalStateException("Expected integer sample type");
}
}
@Override
public void compose(Raster src, Raster dstIn, WritableRaster dstOut) {
checkRaster(src);
checkRaster(dstIn);
checkRaster(dstOut);
int width = Math.min(src.getWidth(), dstIn.getWidth());
int height = Math.min(src.getHeight(), dstIn.getHeight());
int x, y;
int[] srcPixels = new int[width];
int[] dstPixels = new int[width];
for (y=0; y < height; y++) {
src.getDataElements(0, y, width, 1, srcPixels);
dstIn.getDataElements(0, y, width, 1, dstPixels);
for (x=0; x < width; x++) {
dstPixels[x] = mixPixel(srcPixels[x], dstPixels[x]);
}
dstOut.setDataElements(0, y, width, 1, dstPixels);
}
}
private static int mixPixel(int x, int y) {
int xb = (x) & 0xFF;
int yb = (y) & 0xFF;
int b = (xb * yb) / 255;
int xg = (x >> 8) & 0xFF;
int yg = (y >> 8) & 0xFF;
int g = (xg * yg) / 255;
int xr = (x >> 16) & 0xFF;
int yr = (y >> 16) & 0xFF;
int r = (xr * yr) / 255;
int xa = (x >> 24) & 0xFF;
int ya = (y >> 24) & 0xFF;
int a = Math.min(255, xa + ya);
return (b) | (g << 8) | (r << 16) | (a << 24);
}
@Override
public CompositeContext createContext(ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints) {
return this;
}
@Override
public void dispose() {
}
public static final MultiplyComposite Multiply = new MultiplyComposite();
}
This is my code for blending the two photos together which are BufferedImage types. The Overlay is provided from a folder and converted to a buffered image in a separate method which you can find at the bottom, and the SS is provided by a screenshot that is run through another class to make it greyscale and is then converted to a BufferedImage and is returned(You can find that at the bottom too).
// BLENDING THE PHOTOS TOGETHER
public static BufferedImage photosBlender(BufferedImage SS, BufferedImage Overlay) {
try {
BufferedImage base = SS;
BufferedImage overlay = Overlay;
Graphics2D g2d = base.createGraphics();
g2d.setComposite(MultiplyComposite.Multiply);
int x = (base.getWidth() - overlay.getWidth()) / 2;
int y = (base.getHeight() - overlay.getHeight()) / 2;
g2d.drawImage(overlay, x, y, null);
g2d.dispose();
File f = new File("resources/OutputImages/OutputBlended.png");
ImageIO.write((RenderedImage) base, "png", f);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
GETTING THE OVERLAY: the args is provided by a random selection method for selecting random overlay files provided in resources
public static BufferedImage OverlayProcess(String args) {
BufferedImage OverlayInput = null;
JFrame OverlayFrame = null;
try {
OverlayInput = ImageIO.read(new File(args));
ImageIcon screenShotIcon = new ImageIcon(OverlayInput);
//To Display selected Overlay for Testing purposes
/*OverlayFrame = new JFrame();
OverlayFrame.setLayout(new FlowLayout());
OverlayFrame.setSize(1500, 800);
JLabel lbl = new JLabel();
lbl.setIcon(screenShotIcon);
OverlayFrame.add(lbl);
OverlayFrame.setVisible(true);
OverlayFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);*/
} catch (IOException e) {
}
return OverlayInput;
}
GREYSCALING THE SS
public class GreyscaleTheImage {
public static BufferedImage main(String args) throws IOException {
BufferedImage img = null;
File f = null;
//read image
try {
f = new File(args);
img = ImageIO.read(f);
} catch (IOException e) {
System.out.println(e);
}
//get image width and height
int width = img.getWidth();
int height = img.getHeight();
//convert to grayscale
int x = 0;
int y;
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
int p = img.getRGB(x, y);
int a = (p >> 24) & 0xff;
int r = (p >> 16) & 0xff;
int g = (p >> 8) & 0xff;
int b = p & 0xff;
//calculate average
int avg = (r + g + b) / 3;
//replace RGB value with avg
p = (a << 24) | (avg << 16) | (avg << 8) | avg;
img.setRGB(x, y, p);
}
}
BufferedImage finalImage = null;
try {
finalImage = img;
} catch (Exception e) {
System.out.println(e);
}
//write image
try {
f = new File("resources/OutputImages/Output.png");
ImageIO.write(img, "png", f);
} catch (IOException e) {
System.out.println(e);
}
return finalImage;
}//main() ends here
}//class ends here
I've already tried changing the Raster of the image but it's just too much for my current skill level. I simply can't understand what sampleModels are or what it means to have a DataType of 3. I have a suspicion that it might have something to do with the image possibly having something other than a 32 bit "integer" buffer (whatever that means), because of Kristopher's resources saying that's all it will work with.
I made a new method that converts the image to ARGB, thank you to Harald K for the help he left in the comment section. The ARGB image works with the method I was having issues with.