Java:如何快速复制BufferedImage的像素? (包括单元测试) [英] Java: how to do fast copy of a BufferedImage's pixels? (unit test included)

查看:112
本文介绍了Java:如何快速复制BufferedImage的像素? (包括单元测试)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想从源 BufferedImage 中将ARGB值的副本(矩形区域)复制到目标 BufferedImage 。不应该进行合成:如果我复制ARGB值为0x8000BE50(alpha值为128)的像素,则目标像素必须完全 0x8000BE50,完全覆盖目标像素。



我有一个非常精确的问题,我做了一个单元测试来展示我需要的东西。单元测试功能齐全,功能齐全,传递良好,正是我想要的。



但是,我希望更快,更节省内存替换 copySrcIntoDstAt (...)的方法。



这就是我的问题的全部要点:我不是在追求如何以更快的方式填充图像(我所做的仅仅是进行单元测试的一个例子)。我只想知道什么是快速和内存效率的方式(即快速而不是创建不必要的对象)。



我所做的概念验证实现显然非常节省内存,但它很慢(做一个 getRGB 和一个 setRGB



原理上,我有这样的:(其中A表示复制前目标图像的相应像素)

  AAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA

我希望如此:

  AAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAABBBBAAA
AAAAAAAAAAAAABBBBAAA
AAAAAAAAAAAAAAAAAAAA

其中'B'代表 src 图像中的像素。



请注意我正在寻找 copySrcIntoDstAt(...)方法的确切替代品,而不是API链接/报价。

  import org.junit.Test; 

import java.awt.image.BufferedImage;

import static org.junit.Assert。*;

公共类TestCopy {

private static final int COL1 = 0x8000BE50; // alpha at 128
private static final int COL2 = 0x1732FE87; //阿尔法在23

@Test
公共无效testPixelsCopy(){
最终的BufferedImage SRC =新的BufferedImage(5,5,BufferedImage.TYPE_INT_ARGB);
final BufferedImage dst = new BufferedImage(20,20,BufferedImage.TYPE_INT_ARGB);
convenienceFill(src,COL1);
convenienceFill(dst,COL2);
copySrcIntoDstAt(src,dst,3,4);
for(int x = 0; x< dst.getWidth(); x ++){
for(int y = 0; y< dst.getHeight(); y ++){
如果(X> = 3&安培;&安培; X< = 7&安培;&安培; Y> = 4&安培;&安培; Y< = 8){
的assertEquals(COL1,dst.getRGB(X, y));
} else {
assertEquals(COL2,dst.getRGB(x,y));
}
}
}
}

//剪裁是不必要的
private static void copySrcIntoDstAt(
final BufferedImage src,
final BufferedImage dst,
final int dx,
final int dy
){
// TODO:用更高效的方法
替换它(int x = 0; x< src.getWidth(); x ++){
for(int y = 0; y< src.getHeight(); y ++){
dst.setRGB(dx) + x,dy + y,src.getRGB(x,y));
}
}
}

//这个方法只是一个方便的方法,有
//优化这个方法没有意义,这不是什么
//这个问题是关于
private static void convenienceFill(
final BufferedImage bi,
final int color
){
for(int x = 0; x< bi.getWidth(); x ++){
for(int y = 0; y< bi.getHeight(); y ++){
bi.setRGB(x,y,color );
}
}
}

}


解决方案

 私有静态无效copySrcIntoDstAt(最终的BufferedImage SRC,
最终的BufferedImage DST,最终诠释DX,最终诠释DY){
int [] srcbuf =((DataBufferInt)src.getRaster()。getDataBuffer())。getData();
int [] dstbuf =((DataBufferInt)dst.getRaster()。getDataBuffer())。getData();
int width = src.getWidth();
int height = src.getHeight();
int dstoffs = dx + dy * dst.getWidth();
int srcoffs = 0;
为(INT Y = 0; Y<高度; Y ++,dstoffs + = dst.getWidth(),srcoffs + =宽度){
System.arraycopy(srcbuf,srcoffs,dstbuf,dstoffs,宽度) ;
}
}


I want to do a copy (of a rectangle area) of the ARGB values from a source BufferedImage into a destination BufferedImage. No compositing should be done: if I copy a pixel with an ARGB value of 0x8000BE50 (alpha value at 128), then the destination pixel must be exactly 0x8000BE50, totally overriding the destination pixel.

I've got a very precise question and I made a unit test to show what I need. The unit test is fully functional and self-contained and is passing fine and is doing precisely what I want.

However, I want a faster and more memory efficient method to replace copySrcIntoDstAt(...).

That's the whole point of my question: I'm not after how to "fill" the image in a faster way (what I did is just an example to have a unit test). All I want is to know what would be a fast and memory efficient way to do it (ie fast and not creating needless objects).

The proof-of-concept implementation I've made is obviously very memory efficient, but it is slow (doing one getRGB and one setRGB for every pixel).

Schematically, I've got this: (where A indicates corresponding pixels from the destination image before the copy)

AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA

And I want to have this:

AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAABBBBAAA
AAAAAAAAAAAAABBBBAAA
AAAAAAAAAAAAAAAAAAAA

where 'B' represents the pixels from the src image.

Note that I'm looking for an exact replacement of the copySrcIntoDstAt(...) method, not for an API link/quote.

import org.junit.Test;

import java.awt.image.BufferedImage;

import static org.junit.Assert.*;

public class TestCopy {

    private static final int COL1 = 0x8000BE50;  // alpha at 128
    private static final int COL2 = 0x1732FE87;  // alpha at  23 

    @Test
    public void testPixelsCopy() {
        final BufferedImage src = new BufferedImage(  5,  5, BufferedImage.TYPE_INT_ARGB );
        final BufferedImage dst = new BufferedImage( 20, 20, BufferedImage.TYPE_INT_ARGB );
        convenienceFill( src, COL1 );
        convenienceFill( dst, COL2 );
        copySrcIntoDstAt( src, dst, 3, 4 );
        for (int x = 0; x < dst.getWidth(); x++) {
            for (int y = 0; y < dst.getHeight(); y++) {
                if ( x >= 3 && x <= 7 && y >= 4 && y <= 8 ) {
                    assertEquals( COL1, dst.getRGB(x,y) );
                } else {
                    assertEquals( COL2, dst.getRGB(x,y) );
                }
            }
        }
    }

    // clipping is unnecessary
    private static void copySrcIntoDstAt(
            final BufferedImage src,
            final BufferedImage dst,
            final int dx,
            final int dy
    ) {
        // TODO: replace this by a much more efficient method
        for (int x = 0; x < src.getWidth(); x++) {
            for (int y = 0; y < src.getHeight(); y++) {
                dst.setRGB( dx + x, dy + y, src.getRGB(x,y) );
            }
        }
    }

    // This method is just a convenience method, there's
    // no point in optimizing this method, this is not what
    // this question is about
    private static void convenienceFill(
            final BufferedImage bi,
            final int color
    ) {
        for (int x = 0; x < bi.getWidth(); x++) {
            for (int y = 0; y < bi.getHeight(); y++) {
                bi.setRGB( x, y, color );
            }
        }
    }

}

解决方案

private static void copySrcIntoDstAt(final BufferedImage src,
        final BufferedImage dst, final int dx, final int dy) {
    int[] srcbuf = ((DataBufferInt) src.getRaster().getDataBuffer()).getData();
    int[] dstbuf = ((DataBufferInt) dst.getRaster().getDataBuffer()).getData();
    int width = src.getWidth();
    int height = src.getHeight();
    int dstoffs = dx + dy * dst.getWidth();
    int srcoffs = 0;
    for (int y = 0 ; y < height ; y++ , dstoffs+= dst.getWidth(), srcoffs += width ) {
        System.arraycopy(srcbuf, srcoffs , dstbuf, dstoffs, width);
    }
}

这篇关于Java:如何快速复制BufferedImage的像素? (包括单元测试)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆