使用Kristopher Ives的Multiply合成效果时TYPE_INT类型不匹配问题
问题:Multiply合成效果抛出"Expected integer sample type"异常
我尝试使用Multiply合成效果类实现图片叠加,但运行时始终抛出Expected integer sample type异常,触发条件是(r.getSampleModel().getDataType() != DataBuffer.TYPE_INT)。我怀疑问题出在图片不是32位整数缓冲区,但不知道怎么解决,也不清楚SampleModel的含义和DataType=3代表什么。
MultiplyComposite类代码
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(); }
图片混合代码
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; }
获取Overlay图片代码
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; }
截图灰度化代码
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
问题原因
DataBuffer.TYPE_INT对应32位整数格式(每个像素用一个int存储ARGB通道),而你加载/处理的图片可能是其他格式(比如8位灰度、24位RGB,或者DataBuffer.TYPE_BYTE,对应DataType=3),导致Raster的SampleModel数据类型不匹配。
解决方法
核心思路:确保所有参与合成的BufferedImage都转换为32位ARGB整数格式(BufferedImage.TYPE_INT_ARGB),这样Raster的SampleModel就会是DataBuffer.TYPE_INT。
1. 新增图片格式转换工具方法
public static BufferedImage convertToIntARGB(BufferedImage image) { if (image.getType() == BufferedImage.TYPE_INT_ARGB) { return image; // 已经是目标格式,直接返回 } // 创建32位ARGB格式的新图片,复制原图片内容 BufferedImage converted = new BufferedImage( image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB ); Graphics2D g = converted.createGraphics(); g.drawImage(image, 0, 0, null); g.dispose(); return converted; }
2. 修改图片混合代码,先转换格式
在photosBlender方法中,先对base和overlay做格式转换:
public static BufferedImage photosBlender(BufferedImage SS, BufferedImage Overlay) { try { // 先转换为32位ARGB格式,确保数据类型匹配 BufferedImage base = convertToIntARGB(SS); BufferedImage overlay = convertToIntARGB(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(base, "png", f); return base; // 改成返回处理后的图片,原代码返回null不合理 } catch (IOException e) { e.printStackTrace(); } return null; }
3. 灰度化代码优化(可选)
原灰度化代码直接修改原图片,如果原图片不是TYPE_INT_ARGB,也会导致格式问题,建议在灰度化前先转换格式:
public class GreyscaleTheImage { public static BufferedImage main(String args) throws IOException { BufferedImage img = null; File f = new File(args); img = ImageIO.read(f); // 先转换为32位ARGB格式 img = convertToIntARGB(img); int width = img.getWidth(); int height = img.getHeight(); for (int y = 0; y < height; y++) { for (int 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; int avg = (r + g + b) / 3; p = (a << 24) | (avg << 16) | (avg << 8) | avg; img.setRGB(x, y, p); } } f = new File("resources/OutputImages/Output.png"); ImageIO.write(img, "png", f); return img; } }
补充说明
SampleModel是描述图片像素数据存储方式的类,包括每个像素的通道数、数据类型等。DataBuffer.TYPE_BYTE(对应DataType=3)是用字节数组存储像素,每个通道占1字节;而DataBuffer.TYPE_INT是用int数组存储,每个像素(含ARGB)占1个int,这也是MultiplyComposite类要求的格式。
内容的提问来源于stack exchange,提问作者TheRatKing
相关产品推荐
相关产品推荐

