原文链接: http://www.ismyway.com/articles/simpleimageeffect/index.html
一提到JAVA,谈论最多的就是JSP/SERVLET/J2EE之类的,但对于用JAVA对图片进行效果变换,到论坛里看了看,关于这方面的话题并不多,网上关于图像效果处理的文章也并不丰富,于是在自己摸索了几天,并且参考了AnfyJava(专业级的JAVA效果生成器)后,我用轻量级控件写了一个(AnfyJava继承的是Applet,Applet是java.awt包中的,属于重量级控件,SUN现在推荐使用swing来编写图形程序,因此,我用的是JApplet)。
其实,用JAVA做图像效果和其它语言在本质上并没有什么区别,只不过在实现起来有所不同罢了,下面我就把我在项目中处理的经验与大家分享一下吧。
图像的变换,实际上就是把两幅图片的内容进行某些运算,生成新的图像,然后显示出来,最终实现从一幅图片到另一幅图片的过度效果。变换的具体过程如下:
在上面的过程中,图片A和B的尺寸最好保持一致,如果不一致的话,可能要做一些额外的处理,在此,我选用的图片A和B的尺寸是一致的。
首先,我们将其当作一个Applet来写,由于Applet的局限性,不可以直接使用File类来读取图像文件,因此,我们只能通过如下方法来获取图像文件。
URLClassLoader urlLoader = (URLClassLoader)this.getClass().getClassLoader();
URL url = urlLoader.findResource("imagea.gif");
Image image = Toolkit.getDefaultToolkit().getImage(url);
当我们获得了图像后,可以通过java.awt.image.PixelGrabber包中的PixelGrabber方法来将图像中的像素信息完全读取出来,其用法如下:
PixelGrabber(Image img, int x, int y, int w, int h, int[] pix, int off, int scansize)
其中img是要读取的图像,x/y是要读取图像中的左上角坐标,w/h分别是从x/y开始起的距离,其实x,y,w,h就是一个矩形,pix是保存像素的数组,off是读取图像时开始的位置,scansize是指扫描的宽度,一般来说和w相等。
int width = image.getWidth();
int height = image.getHeight();
int size = width * height;
int[] pixels = new int[size];
pixelgrabber = new PixelGrabber(image, 0, 0, width, height, pixels, 0, width);
try {
pixelgrabber.grabPixels(); //读取像素入数组
}
catch (InterruptedException _ex) {}
由于像素信息是由alpha,red,green,blue组成的,其格式为
int alpha = (pixel >> 24) & 0xff;
int red = (pixel >> 16) & 0xff;
int green = (pixel >> 8) & 0xff;
int blue = (pixel) & 0xff;
假如要实现显示图片A后,图片B由上至下展开,则可以每次将图片A中的一行像素替换为B中的相应行,然后生成新的像素信息:
old = pixelA; //保存图片A的像素信息
oldR = redA; //保存图片A的R信息
oldG = greenA; //保存图片A的G信息
oldB = blueA; //保存图片A的B信息
for (int i = 0; i < width; i++) {//line为行数
oldR[line * width + i] = redA [line * width + i];
oldG[line * width + i] = greenA [line * width + i];
oldB[line * width + i] = blueA [line * width + i];
old[line * width + i] = oldR[line * width + i] << 16 + oldG[line * width + i] << 8 + oldB[line * width + i];
}
当生成新的像素信息后,可以通过java.awt.image.MemoryImageSource包中的MemoryImageSource(int w, int h, ColorModel cm, int[] pix, int off, int scan)方法将像素数组对应到图像,并且可以用newPixels()方法来生成新的图像(具体用法可以参考JAVA API DOC)。
memoryimagesource = new MemoryImageSource(imageWidth, imageHeight,
new DirectColorModel(24, 0xff0000, 0x00ff00, 0x0000ff), blocks, 0, imageWidth);
//检查java版本
String javaVersion;
try {
javaVersion = System.getProperty("java.version");
}
catch (SecurityException _ex) {
javaVersion = "unk";
}
if (!javaVersion.startsWith("1.0")) { //jdk1.1以上的版本才支持此方法
try {
memoryimagesource.setAnimated(true);
memoryimagesource.setFullBufferUpdates(true);
imageBuf = createImage(memoryimagesource);
memoryimagesource.newPixels();//生成新的图像
}
catch (NoSuchMethodError _ex) {
System.out.println("unknow java version!");
}
}
到此,新的图像已经产生,只需要输出到屏幕即可。
在此,需要注意以下几个问题:
1、 由于Applet读取的图像文件可以比较大,对于速度较慢的网络,可能会造成图像未读取完全就开始进行变换,因此,建议使用MediaTracker方法来保证图像能被顺利载入。
2、 在显示的时候,为了避免闪烁,可以采用双缓冲的方法。
3、 由于在某此高速计算机上,生成新的像素可以非常快,为了避免速度过快而造成效果并不明显,可以加以适当的延时处理。
4、 为了保证效果的平滑,我们特地开辟了非常大的数组来保存像素/RGB信息,这是以空间换时间的做法。
完整的源程序附下(在jdk1.4/2k Server/RedHat9下运行通过,所用机器为P4 2.4G/512M)
/*程序只给出了一个从上向下展开的例子,并且申明的变量redA等并没有使用,如果考虑到要做其它更复杂的效果变换,可以查阅相关资料,找到各种变换效果的公式即可(此时redA等就会用上了)*/
package pic;
import java.awt.*;
import java.io.*;
import java.net.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
public class effect
extends JApplet
implements Runnable {
//定义变量
Toolkit toolkit;
int totalBlocks = 0; //图像被分解成的块数,默认为 宽X高
int[] blocks; //保存块数的信息
Image[] bufferImage = new Image[2]; //屏幕上的图形缓冲
VolatileImage offScreenImage;
Image imageBuf; //保存图片缓冲区内容
Graphics2D offScreenGraphics;
Thread thread;
MediaTracker mediaTracker;
boolean[] isImageReady; //图片是否已经装载
MemoryImageSource memoryimagesource;
int imageWidth, imageHeight; //图像的宽及高
int[] pixelA, pixelB;
int[] redA, greenA, blueA, redB, greenB, blueB;
public effect() throws HeadlessException {
bufferImage[0] = getImage("a.jpg");
bufferImage[1] = getImage("b.jpg");
if ( (bufferImage[0].getWidth(this) != bufferImage[1].getWidth(this)) ||
(bufferImage[0].getHeight(this) != bufferImage[1].getHeight(this))) {
System.out.println("图像尺寸不一致!");
return;
}
toolkit = getToolkit();
imageWidth = bufferImage[0].getWidth(this);
imageHeight = bufferImage[0].getHeight(this);
totalBlocks = imageWidth * imageHeight; //计算分解的块数
blocks = new int[totalBlocks];
pixelA = new int[totalBlocks];
pixelB = new int[totalBlocks];
redA = new int[totalBlocks];
greenA = new int[totalBlocks];
blueA = new int[totalBlocks];
redB = new int[totalBlocks];
greenB = new int[totalBlocks];
blueB = new int[totalBlocks];
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gd.getDefaultConfiguration();
offScreenImage = gc.createCompatibleVolatileImage(imageWidth, imageHeight); //创建图像缓冲
offScreenGraphics = offScreenImage.createGraphics(); //取得缓冲的graphics对象
}
public void init() {
getImagePixels(bufferImage[0], pixelA);
getImagePixels(bufferImage[1], pixelB);
for (int i = 0; i < totalBlocks; i++) {
blocks[i] = pixelA[i]; //保存图像A的像素信息
redA[i] = pixelA[i] & 0xff0000; //保存图像B的red值
greenA[i] = pixelA[i] & 0x00ff00; //保存图像B的green值
blueA[i] = pixelA[i] & 0x0000ff; //保存图像B的blue值
redB[i] = pixelB[i] & 0xff0000; //保存图像B的red值
greenB[i] = pixelB[i] & 0x00ff00; //保存图像B的green值
blueB[i] = pixelB[i] & 0x0000ff; //保存图像B的blue值
}
prepareImagePixels(); //将像素信息还原为图像
}
public void run() {
//检查java版本
String javaVersion;
try {
javaVersion = System.getProperty("java.version");
}
catch (SecurityException _ex) {
javaVersion = "unk";
}
if (javaVersion.startsWith("1.0")) {
System.out.println("require java 1.1 or later version!");
return;
}
try { //暂停3秒钟后等待效果开始
thread.sleep(3000l);
}
catch (InterruptedException ex1) {
}
int line = 0;
Thread currentThread = Thread.currentThread();
while (line < imageHeight && thread == currentThread) {
for (int i = 0; i < imageWidth; i++) {
int offset = line * imageWidth + i;
blocks[offset] = pixelB[offset]; //与下一被注释的语句作用相同
//blocks[offset] = redB[offset] | greenB[offset] | blueB[offset];
}
memoryimagesource.newPixels(); //生成新的图像
line++;
repaint();
//适当延时
try {
thread.sleep(20l);
}
catch (InterruptedException ex) {
}
}
}
public void paint(Graphics g) {
if (offScreenGraphics != null) { //保证在destory()时不引发异常
offScreenGraphics.drawImage(imageBuf, 0, 0, this);
g.drawImage(offScreenImage, 0, 0, this);
}
}
public void start() {
if (thread == null) {
thread = new Thread(this);
thread.start();
}
}
public void stop() {
thread = null;
}
public final void update(Graphics g) {
paint(g);
}
public void destroy() {
if (offScreenImage != null) {
offScreenImage.flush();
}
offScreenImage = null;
if (offScreenGraphics != null) {
offScreenGraphics.dispose();
}
offScreenGraphics = null;
System.gc();
}
/**
* 通过给定的文件名获得图像
* @param filename 给定图像的文件名
* @return 图像
*/
Image getImage(String filename) {
URLClassLoader urlLoader = (URLClassLoader)this.getClass().getClassLoader();
URL url = null;
Image image = null;
url = urlLoader.findResource(filename);
image = Toolkit.getDefaultToolkit().getImage(url);
MediaTracker mediatracker = new MediaTracker(this);
try {
mediatracker.addImage(image, 0);
mediatracker.waitForID(0);
}
catch (InterruptedException _ex) {
image = null;
}
if (mediatracker.isErrorID(0)) {
image = null;
}
return image;
}
/**
* 取得给定图像的像素数组
* @param image 指定的图像
* @param pixels 保存像素信息的数组
* @return 成功返回true
*/
private boolean getImagePixels(Image image, int pixels[]) {
PixelGrabber pixelgrabber = new PixelGrabber(image, 0, 0, imageWidth,
imageHeight, pixels,
0, imageWidth);
try {
pixelgrabber.grabPixels();
}
catch (InterruptedException _ex) {
return false;
}
return true;
}
/**
* 将像素数组还原为图像
*/
void prepareImagePixels() {
memoryimagesource = new MemoryImageSource(imageWidth, imageHeight,
new DirectColorModel(24, 0xff0000,
0x00ff00, 0x0000ff), blocks, 0, imageWidth);
try {
memoryimagesource.setAnimated(true);
memoryimagesource.setFullBufferUpdates(true);
imageBuf = createImage(memoryimagesource);
memoryimagesource.newPixels(); //生成新的图像
}
catch (NoSuchMethodError _ex) {
}
}
/**
* 取得图像的宽度
* @return 宽度
*/
public int getWidth() {
return imageWidth;
}
/**
* 取得图像的高度
* @return 高度
*/
public int getHeight() {
return imageHeight;
}
public static void main(String args[]) {
JFrame frame = new JFrame("Demo");
effect e = new effect();
e.init();
e.start();
frame.getContentPane().setLayout(new BorderLayout());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.getContentPane().add(e);
frame.setSize(new Dimension(e.getWidth() + 6, e.getHeight() + 20));
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension frameSize = frame.getSize();
frame.setLocation( (screenSize.width - frameSize.width) / 2,
(screenSize.height - frameSize.height) / 2);
frame.show();
}
}
分享到:
相关推荐
### 使用Java实现彩色图片的灰度变换 #### 灰度变换原理 灰度变换是一种图像处理技术,常用于将彩色图像转换成灰度图像。其基本思想是将彩色图像中的每个像素点的颜色值(红、绿、蓝三原色)通过一定的公式计算成...
总之,通过Java2D的`AffineTransform`类,我们可以方便地实现沿直线的伸缩变换,从而创造出丰富多样的图形效果。这不仅在游戏开发、可视化应用,甚至在数据可视化的场景中都有广泛的应用。熟练掌握这一技术,能极大...
Java生成图片百叶窗变换效果,类似于网页中的图片切换过渡效果,百叶窗变化的过程中显示出图片内容,创建一个图片切换效果的线程,代码中的注释丰富,部分代码如下: Image images[],showImage; //待显示的图像...
本项目使用JAVA编程语言,结合蝶式算法,实现了对图片的快速离散傅里叶变换(FFT)和离散余弦变换(DCT),并使用NetBeans作为集成开发环境。 首先,快速离散傅里叶变换(FFT)是离散傅里叶变换(DFT)的一种高效...
在这个特定的应用场景中,我们利用 JavaCV 对图片进行文字识别(OCR,Optical Character Recognition),以定位并提取指定文字在图片中的位置坐标,同时优化识别速度。 首先,我们需要了解 OCR 的基本概念。OCR ...
在Java中,可以使用`Color`类进行颜色空间的转换,这对于实现某些特定的图像效果至关重要,比如色彩分离或色彩调整。 3. **几何变换**: 包括平移、旋转、缩放和剪切等操作,这些可以改变图像的位置和形状。Java的...
本项目为java实现的视频生成的demo项目,实现了通过多张图片的旋转、缩放等变换来生成视频。本项目使用了第三方jar包,jar包在libs目录下;图片在images下,运行MainApp的main方法即可生成视频,视频输出在目录...
综上所述,实现Java中的图片火焰效果涉及对`JApplet`、`Graphics`对象以及动画原理的理解。通过巧妙地应用图像处理和定时器,可以创建出引人入胜的视觉效果。在实际项目中,你可以根据具体需求调整火焰的复杂性、...
总的来说,Java图片高级处理涉及多个层次的技术,从简单的颜色变换到复杂的数学算法,都需要扎实的编程基础和对图像处理原理的理解。通过学习和实践,你可以创建出具有独特视觉效果的应用程序或工具,满足各种图像...
综上所述,实现"Java图片的火焰效果"涉及了粒子系统、图像处理、动画制作、颜色变换、性能优化等多个Java编程领域的知识。通过深入理解和实践这些知识点,我们可以创建出生动逼真的火焰动画,无论是独立的火焰效果...
本文将深入探讨如何使用Java来创建这种动态的水波荡漾效果。 首先,我们要了解基本的原理。水波荡漾效果通常基于数学模型,如傅立叶变换或者物理模拟中的波动方程。傅立叶变换可以帮助我们分析图像的频率成分,而...
在这个由Eclipse编写的Java小程序中,用户可以轻松地对图像进行打开、保存以及进行变形操作。 1. **Java AWT和Swing库**:这两个Java库提供了丰富的图形用户界面(GUI)组件和图像处理工具。Eclipse项目可能依赖于`...
本篇将详细介绍如何使用Java实现这些功能,并以`ImgRotate.java`为例进行解析。 首先,我们需要了解Java中用于处理图像的主要类库:Java Advanced Imaging (JAI) 和 Java 2D API。虽然JAI提供了更强大的图像处理...
本项目专注于图片的压缩功能,提供了简单易用的API,可以对图片进行缩放和降质处理,并且支持批量操作。下面将详细介绍这个项目涉及的关键知识点。 1. **Java图像处理库**: - Java标准库中的`java.awt.image`和`...
这可能意味着这款Java图片编辑工具不仅可以处理常规的静态图像,还可以对包含动画的SWF文件进行编辑和播放,增加了其功能的多样性。 总的来说,这个Java图片编辑工具利用了Java的跨平台特性以及强大的图像处理库,...
傅里叶变换是它的基础,但DCT相比傅里叶变换在实际应用中更具有优势,因为它对实数信号进行操作并能够更好地捕捉图像的能量集中在低频部分这一特性。 Java是一种广泛使用的编程语言,适用于各种应用程序开发,包括...
在Java编程语言中,创建图片倒影效果是一种常见的图像处理技术,这通常涉及到对原始图像进行翻转并将其叠加在原图下方。本实例源码提供了实现这一效果的方法,可以帮助开发者学习和理解如何利用Java进行图像操作。...
图片剪切通常涉及到获取用户选择的裁剪区域,然后对原始图像进行裁剪操作。这可以通过创建一个BufferedImage对象来表示原始图像,再根据裁剪参数创建一个新的BufferedImage,只包含裁剪后的部分。 其次,JQUERY控件...
Java中可以通过`ImageIO`类的`read`方法读取图片,然后使用`BufferedImage`类的`getScaledInstance`方法进行等比例缩放,最后通过`ImageIO.write`方法以新的尺寸重新保存图片。注意,压缩时应考虑质量与体积的平衡,...
图片的渐变,能够实现图片的渐进渐出,图片的切换等功能