`
san_yun
  • 浏览: 2594941 次
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

使用JAVA对图片进行效果变换

阅读更多
原文: http://blog.ccidnet.com/blog-htm-do-showone-uid-4581-type-blog-itemid-21625.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组成的,其格式为




因此,我们可以将颜色分解成单独的RGB信息

int alpha = (pixel >> 24) & 0xff;

int red = (pixel >> 16) & 0xff;

int green = (pixel >> & 0xff;

int blue = (pixel) & 0xff;

假如要实现显示图片A后,图片B由上至下展开,则可以每次将图片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 = pixelA; //保存图像A的像素信息

redA = pixelA & 0xff0000; //保存图像B的red值

greenA = pixelA & 0x00ff00; //保存图像B的green值

blueA = pixelA & 0x0000ff; //保存图像B的blue值

redB = pixelB & 0xff0000; //保存图像B的red值

greenB = pixelB & 0x00ff00; //保存图像B的green值

blueB = pixelB & 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();

}

}

新建一个HTML文件,加入以下语句可作为Applet(其中width/height分别是图片的高和宽):

<APPLET height=640 width=480 code=pic.effect.class></APPLET>

作为应用程序运行的时候,在命令行输入:

java pic.effect

分享到:
评论

相关推荐

    Java生成图片百叶窗变换效果.rar

    Java生成图片百叶窗变换效果,类似于网页中的图片切换过渡效果,百叶窗变化的过程中显示出图片内容,创建一个图片切换效果的线程,代码中的注释丰富,部分代码如下:  Image images[],showImage; //待显示的图像...

    图像变换算法(java版本)

    用java实现的图像变化算法,包含大量类似ps中图像处理的算法,其中包含一个编辑器可以查看效果,很详细很强大,共享之。

    java GUI 图片渐变效果源代码

    图片的渐变,能够实现图片的渐进渐出,图片的切换等功能

    java源码包---java 源码 大量 实例

     util实现Java图片水印添加功能,有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码...

    java源码包4

     util实现Java图片水印添加功能,有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码...

    java源码包3

     util实现Java图片水印添加功能,有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码...

    JAVA上百实例源码以及开源项目

     util实现Java图片水印添加功能,有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码...

    Java 图片浏览器 支持多种格式图片

    图片浏览器的常用功能进行设计开发,包括对图片的读写,显示等功能和一些常用的小功能类似QQ截图和设置桌面的背景以及背景音乐,以及数字图像处理的中的一些常用的变换算法,如图像的放大,缩小,旋转以及黑白变换的...

    JAVA上百实例源码以及开源项目源代码

     util实现Java图片水印添加功能,有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码...

    java源码包2

     util实现Java图片水印添加功能,有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码...

    Java开发技术大全(500个源代码).

    示例描述:本章演示如何开始使用JDK进行程序的开发。 HelloWorldApp.java 第一个用Java开发的应用程序。 firstApplet.java 第一个用Java开发的Applet小程序。 firstApplet.htm 用来装载Applet的网页文件 第2章 ...

    基于opencv3.1库的JAVA源码

    第6章 使用核矩阵进行影像处理 165 范例6-1-1 Mean filter处理 165 范例6-2-1 Prewitt Filter处理 167 范例6-3-1 Laplacian Filter处理1 170 范例6-3-2 Laplacian Filter处理2 171 范例6-3-3 Laplacian Filter灰阶...

    成百上千个Java 源码DEMO 4(1-4是独立压缩包)

    Java数组倒置 简单 Java图片加水印,支持旋转和透明度设置 摘要:Java源码,文件操作,图片水印 util实现Java图片水印添加功能,有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印...

    成百上千个Java 源码DEMO 3(1-4是独立压缩包)

    Java数组倒置 简单 Java图片加水印,支持旋转和透明度设置 摘要:Java源码,文件操作,图片水印 util实现Java图片水印添加功能,有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印...

    基于java-swing的开心农场游戏

    1、使用JAVA SWING 或者 AWT 包下的API类实现该项目; 2、控制鼠标依次点击植物状态(播种、生长、开花、结果); 3、农场中的植物根据对应状态变换不同图片效果; 4、当点击收获时图片消失,果实加一;

    基于Java+swing项目实战之天天酷跑

    一个用JAVA语言开发的天天酷跑小游戏,核心思想是运用Java中的线程机制实现对图片数组的反复绘制,达到动态效果,人物与障碍物的运动逻辑实质为x,y坐标上的变换,碰撞逻辑写的较为粗糙,是将障碍物与人物图片作为...

    Java天天酷跑.zip

    一个用JAVA语言开发的天天酷跑小游戏,核心思想是运用Java中的线程机制实现对图片数组的反复绘制,达到动态效果,人物与障碍物的运动逻辑实质为x,y坐标上的变换,碰撞逻辑写的较为粗糙,是将障碍物与人物图片作为...

    专门为OpenHarmony打造的一款图像加载缓存库,致力于更高效、更轻便、更简单

    本项目基于开源库 Glide 进行OpenHarmony的自研版本:支持内存缓存,使用LRUCache算法,对图片数据进行内存缓存。支持磁盘缓存,对于下载图片会保存一份至磁盘当中。支持进行图片变换: 支持图像像素源图片变换效果。...

    Effects.java

    图片处理,锐化,黑白,模糊,镜像处理,可通过Bitmap变换达到想要的效果,可以做图片的基本处理,需要的下载

Global site tag (gtag.js) - Google Analytics