用java实现图片渐变叠加(3种方法)

用java实现图片渐变叠加(3种方法)

用java实现图片渐变叠加(3种方法) - souljava - 千鸟

用java实现图片渐变叠加是件很酷的事情,中文的实现资料几乎为0,搞了我好几天时间。

原理上是2种方法,但是可以用3种方法实现(没想到花了我那么多时间):1.是根据alpha值计算,象素的各单色分量衰减后相加;2.是修改一张图片的透明度,然后用画到另一张图片上面;3.是象素点的插值,不涉及透明度的使用。做的时候先试的第3种方法的,花的时间最多,结果发现效果最烂,象素差别过大看起来就像麻子一样。代码里的渐变范围是图片的1/4到3/4.自己可以修改的^_^。

最简单的是第2种方法。第3种效果最差,但是最容易想到。我最喜欢的是第1种。

代码和上一篇blog《用java分离象素》有很多重复的地方,但是为了众看客运行方便,重复的部分还是写了出来。

实现过程描述如下:

一。根据alpha值计算

把图片的象素分离出来。原图的alpha值都设为0xff。确定一张图片A渐变的衰减系数div(0~1),另一张图片B的衰减就是1-div。

div=row/range; row是递增的行,range是渐变范围。

合成渐变的象素的公式我发现是:

color=(A.blue+A.green+A.red)*div+(B.blue+B.green+B.red)*(1-div)

A表示图片A的某点象素,B表示图片B的某点象素。当然实现上各种颜色不能直接相加,要位移相应的位,然后 进行或运算。

二。修改透明度

修改图片B的渐变范围象素的alpha值,alpha为0就是透明,0xff为不透明。渐变就是alpha的值的递变。然后以图片B的大小,新建一个图像缓冲bi

Graphics2D g2= (Graphics2D)bi.getGraphics();
g2.drawImage(imageA.getImage(),0,0,null)//将图片A画入缓冲区bi

最后把修改好的半透明图片画入bi
g2.drawImage(image,0,0,null);

最后完整的图片渐变叠加就保存在了这个缓冲区内。最后输出图片即可。

javax.imageio.ImageIO.write(bi, "JPEG", new java.io.File(filename));

我想应该还有别的办法可以实现:对两张图片的象素,基于alpha值进行计算,是可以合成渐变效果的象素 的。目前还没有试验出这个计算方法。

三。象素插值。等差数列的原理。

有两张图片A,B,图片A的象素密度随横坐标的的增加减小,图片B的密度与图片A变化相反。

我用的方法是,描述每一列相隔row行,需要插入一个象素。row这个变量的取值,在纸面上画出来的曲线,是在渐变区先增后减的一次函数。转折点是渐变区的中点。

下面的代码按顺序对应的上面的每种方法。每个程序用图片分割。

用java实现图片渐变叠加(3种方法) - souljava - 千鸟

//SpliceCount.java
/*
*author by liuke
*email: soulnew@gmail.com
*blog: souljava.blog.163.com
**/

package com.soulnew.Pixel;
import java.awt.image.PixelGrabber;
import java.awt.Image;
import java.awt.image.ImageObserver;
import javax.swing.ImageIcon;
import java.io.FileWriter;
import javax.swing.JFrame;
import java.awt.image.MemoryImageSource;
import java.awt.Graphics2D;
import java.io.File;
public class SpliceCount{
int pixels[];
int Aw,Ah,Bw,Bh;
int Wmax,Hmax; //the size of splice image
int arrayImageA[],arrayImageB[]; //arrays used to save the pixels
String imagepathA="images/try.gif"; //you can change the image path here
String imagepathB="images/fruit1.jpg";
String outputimage="SpliceCount.jpg";
FileWriter fw; //used to write log
int index=0;
ImageIcon imageA,imageB;
public SpliceCount(){

imageA=new ImageIcon(imagepathA);
imageB=new ImageIcon(imagepathB);

Aw=imageA.getIconWidth();
Ah=imageA.getIconHeight();
Bw=imageB.getIconWidth();
Bh=imageB.getIconHeight();
arrayImageA=handlepixels(imageA.getImage(),0,0,Aw,Ah);
arrayImageB=handlepixels(imageB.getImage(),0,0,Bw,Bh);
if(arrayImageA!=null&&arrayImageB!=null){

doSplice(arrayImageA,arrayImageB);
Image image=createImage(pixels);
saveImage(image,outputimage);
}
if(fw!=null){
try{
fw.close();
}catch(Exception e){
e.printStackTrace();
}
}
}

public void doSplice(int[] imageA,int[] imageB){
pixels=imageB;
Hmax=Bh;
Wmax=Bw;
int rangeFrom=Bw/4;
int rangeTo=Bw*3/4;
int range=Bw>>1;

for(int i=rangeFrom;i<Bw;i++){
float div=(float)(rangeTo-i)/(float)range;
if(i>rangeTo){ //渐变范围以外,不衰减
div=0;
}
float div1=1-div; //渐变左边范围以外,不衰减,用imgeA填充


for(int j=0;j<Bh;j++){
int pixel=pixels[j*Bw+i];
int alpha = (pixel >> 24) & 0xff; //分离imageB象素好相加
int red = (pixel >> 16) & 0xff;
int green = (pixel >> 8) & 0xff;
int blue = (pixel ) & 0xff;

int alpha1,red1,green1,blue1;
pixel=imageA[j*Aw+i]; //准备分离imageA象素
if(i>Aw||j>Ah){ //imageA 的大小不够,用白色填充
alpha1 = 0xff;
red1 = 0xff;
green1= 0xff;
blue1= 0xff;
}else{
alpha1 = (pixel >> 24) & 0xff;
red1 = (pixel >> 16) & 0xff;
green1 = (pixel >> 8) & 0xff;
blue1 = (pixel ) & 0xff;
}

alpha=0xff;
red =Math.round(red*div+red1*div1); //象素按每种颜色的衰减相加
green =Math.round(green*div+green1*div1);
blue =Math.round(blue*div+blue1*div1);

pixels[j*Bw+i]=(alpha<<24)|(red<<16)|(green<<8)|(blue);//合成颜色

}
}
}
public void writePixel2File(int color){
index++;

if(fw==null){
try{
fw =new FileWriter("pixel.txt");
}catch(Exception e){
e.printStackTrace();
}
}
try{
if(index%100==0)
fw.write("\n");

fw.write("\t"+color);
}catch(Exception e){
e.printStackTrace();
}
}

public Image createImage(int[] colors){
JFrame jf=new JFrame();
ImagemodImg = jf.createImage(
new MemoryImageSource(
Wmax,Hmax,colors,0,Wmax));
return modImg;
}


public void saveImage(Image image,String filename){
java.awt.image.BufferedImage bi = new java.awt.image.BufferedImage(Wmax, Hmax, java.awt.image.BufferedImage.TYPE_INT_BGR);
Graphics2D g2= (Graphics2D)bi.getGraphics();

g2.drawImage(image,0,0,null);

try{
javax.imageio.ImageIO.write(bi, "JPEG", new java.io.File(filename));
}catch(Exception e){
e.printStackTrace();
}
}

public int[] handlepixels(Image img, int x, int y, int w, int h) {
int[] pixel = new int[w * h];
PixelGrabber pg = new PixelGrabber(img, x, y, w, h, pixel, 0, w);
try {
pg.grabPixels();
} catch (InterruptedException e) {
System.err.println("interrupted waiting for pixels!");

}
if ((pg.getStatus() & ImageObserver.ABORT) != 0) {
System.err.println("image fetch aborted or errored");
}
return pixel;
}
public static void main(String[] args){
SpliceCount splice=new SpliceCount();
}
}

用java实现图片渐变叠加(3种方法) - souljava - 千鸟

用java实现图片渐变叠加(3种方法) - souljava - 千鸟用java实现图片渐变叠加(3种方法) - souljava - 千鸟

/*
*author by liuke
*email: soulnew@gmail.com
*blog: souljava.blog.163.com
**/

package com.soulnew.Pixel;
import java.awt.image.PixelGrabber;
import java.awt.Image;
import java.awt.image.ImageObserver;
import javax.swing.ImageIcon;
import java.io.FileWriter;
import javax.swing.JFrame;
import java.awt.image.MemoryImageSource;
import java.awt.Graphics2D;
import java.io.File;
public class SpliceAlpha{
int pixels[];
int Aw,Ah,Bw,Bh;
int Wmax,Hmax; //the size of splice image
int arrayImageA[],arrayImageB[]; //arrays used to save the pixels
String imagepathA="images/try.gif"; //you can change the image path here
String imagepathB="images/fruit1.jpg";
String outputimage="splicealpha.jpg";
FileWriter fw; //used to write log
int index=0;
ImageIcon imageA,imageB;
public SpliceAlpha(){

imageA=new ImageIcon(imagepathA);
imageB=new ImageIcon(imagepathB);

Aw=imageA.getIconWidth();
Ah=imageA.getIconHeight();
Bw=imageB.getIconWidth();
Bh=imageB.getIconHeight();
arrayImageA=handlepixels(imageA.getImage(),0,0,Aw,Ah);
arrayImageB=handlepixels(imageB.getImage(),0,0,Bw,Bh);
if(arrayImageA!=null&&arrayImageB!=null){

doSplice(arrayImageA,arrayImageB);
Image image=createImage(pixels);
saveImage(image,outputimage);
}
if(fw!=null){
try{
fw.close();
}catch(Exception e){
e.printStackTrace();
}
}
}

public void doSplice(int[] imageA,int[] imageB){
pixels=imageB;
Hmax=Bh;
Wmax=Bw;
int rangeFrom=Bw/4;
int rangeTo=Bw*3/4;
int range=Bw>>1;

for(int i=rangeFrom;i<Bw;i++){
float div=(float)(rangeTo-i)/(float)range;
int alpha=(int)(0xff*div);
alpha=alpha<<24;

for(int j=0;j<Bh;j++){
if(i>=rangeTo){
pixels[j*Bw+i]=0;
continue;
}
pixels[j*Bw+i]=pixels[j*Bw+i]&0xffffff;
pixels[j*Bw+i]=pixels[j*Bw+i]|(alpha);

}
}
}
public void writePixel2File(int color){
index++;

if(fw==null){
try{
fw =new FileWriter("pixel.txt");
}catch(Exception e){
e.printStackTrace();
}
}
try{
if(index%100==0)
fw.write("\n");

fw.write("\t"+color);
}catch(Exception e){
e.printStackTrace();
}
}

public Image createImage(int[] colors){
JFrame jf=new JFrame();
ImagemodImg = jf.createImage(
new MemoryImageSource(
Wmax,Hmax,colors,0,Wmax));
return modImg;
}


public void saveImage(Image image,String filename){
java.awt.image.BufferedImage bi = new java.awt.image.BufferedImage(Wmax, Hmax, java.awt.image.BufferedImage.TYPE_INT_BGR);
Graphics2D g2= (Graphics2D)bi.getGraphics();
g2.drawImage(imageA.getImage(),0,0,null);
g2.drawImage(image,0,0,null);

try{
javax.imageio.ImageIO.write(bi, "JPEG", new java.io.File(filename));
}catch(Exception e){
e.printStackTrace();
}
}

public int[] handlepixels(Image img, int x, int y, int w, int h) {
int[] pixel = new int[w * h];
PixelGrabber pg = new PixelGrabber(img, x, y, w, h, pixel, 0, w);
try {
pg.grabPixels();
} catch (InterruptedException e) {
System.err.println("interrupted waiting for pixels!");

}
if ((pg.getStatus() & ImageObserver.ABORT) != 0) {
System.err.println("image fetch aborted or errored");
}
return pixel;
}
public static void main(String[] args){
SpliceAlpha splice=new SpliceAlpha();
}
}

用java实现图片渐变叠加(3种方法) - souljava - 千鸟

用java实现图片渐变叠加(3种方法) - souljava - 千鸟用java实现图片渐变叠加(3种方法) - souljava - 千鸟

用象素交错填充的办法实现的图片叠加。

效果不怎么好

/*
*author by liuke
*email: soulnew@gmail.com
*blog: souljava.blog.163.com
**/

package com.soulnew.Pixel;
import java.awt.image.PixelGrabber;
import java.awt.Image;
import java.awt.image.ImageObserver;
import javax.swing.ImageIcon;
import java.io.FileWriter;
import javax.swing.JFrame;
import java.awt.image.MemoryImageSource;
import java.awt.Graphics2D;
import java.io.File;


public class Splice{
int arrayImageA[],arrayImageB[]; //arrays used to save the pixels
String imagepathA="images/try.gif"; //you can change the image path here
String imagepathB="images/fruit1.jpg";
int rangeFrom,rangeTo; //the transition range from one position to another
int splicePixel[];
int Aw,Ah,Bw,Bh;
int Wmax,Hmax; //the size of splice image
String outputimage="splice.jpg";
int index=0;
FileWriter fw;


public Splice(){

ImageIcon imageA=new ImageIcon(imagepathA);
ImageIcon imageB=new ImageIcon(imagepathB);

Aw=imageA.getIconWidth();
Ah=imageA.getIconHeight();
Bw=imageB.getIconWidth();
Bh=imageB.getIconHeight();

arrayImageA=handlepixels(imageA.getImage(),0,0,Aw,Ah);
arrayImageB=handlepixels(imageB.getImage(),0,0,Bw,Bh);
if(arrayImageA!=null&&arrayImageB!=null){
doSplice2(arrayImageA,arrayImageB);
Image image=createImage(splicePixel);
saveImage(image,outputimage);
}
if(fw!=null){
try{
fw.close();
}catch(Exception e){
e.printStackTrace();
}
}

}
public Image createImage(int[] colors){
JFrame jf=new JFrame();
ImagemodImg = jf.createImage(
new MemoryImageSource(
Wmax,Hmax,colors,0,Wmax));
return modImg;
}

public void saveImage(Image image,String filename){
java.awt.image.BufferedImage bi = new java.awt.image.BufferedImage(Wmax, Hmax, java.awt.image.BufferedImage.TYPE_INT_BGR);
Graphics2D g2= (Graphics2D)bi.getGraphics();
g2.drawImage(image,0,0,null);

try{
javax.imageio.ImageIO.write(bi, "JPEG", new java.io.File(filename));
}catch(Exception e){
e.printStackTrace();
}
}
/*
*the method can splice two image(array) into one image(array)
*the the range smaller than the the image size
*@all parameter must not to be null!!!
*
**/

public void doSplice2(int[] imageA,int[] imageB){
//first of all,you should check whether the condition fill this method
if(Aw>Bw){
Wmax=Aw;
}else{
Wmax=Bw;
}

rangeFrom=Wmax/4; // you can set range here
rangeTo=Wmax*3/4;
if(rangeFrom>Wmax)
return;
if(rangeFrom>=rangeTo)
return;
if(Ah>Bh){
Hmax=Ah;
}else{
Hmax=Bh;
}
splicePixel=new int[Wmax*Hmax];
int range=rangeTo-rangeFrom;
float sp=((float)Hmax/(float)range); //step



for(int i=0;i<Wmax;i++){ //col

float rownumber=sp*(rangeTo-i);
float row=((float)Hmax)/rownumber;
int start=(int)Math.round(Math.random()*row);
float point=start;
//System.out.print("\n"+row);
for(int j=0;j<Hmax;j++){ //row
start=Math.round(point);
//start=start+(int)Math.round((Math.random()-0.5)*row);
if(start<0)
start=0;

if(i<rangeFrom){
if(j>=Bh||i>=Bw){
splicePixel[j*Wmax+i]=0xffffffff;
continue;
}
splicePixel[j*Wmax+i]=imageB[j*Bw+i];
continue;
}else if(i>=rangeTo){
if(j>=Ah||i>=Aw){
splicePixel[j*Wmax+i]=0xffffffff;
continue;
}
splicePixel[j*Wmax+i]=imageA[j*Aw+i];
continue;
}
//this.writePixel2File((int)Math.round((Math.random()-0.5)*row));
if(j==start){

if(j>=Ah||i>=Aw){
splicePixel[j*Wmax+i]=0xffffffff;
continue;
}
splicePixel[j*Wmax+i]=imageB[j*Bw+i];
point=point+row;
}else{
if(j>=Bh||i>=Bw){
splicePixel[j*Wmax+i]=0xffffffff;
continue;
}
splicePixel[j*Wmax+i]=imageA[j*Aw+i];
}
}
}
}

public void writePixel2File(int color){
index++;

if(fw==null){
try{
fw =new FileWriter("pixel.txt");
}catch(Exception e){
e.printStackTrace();
}
}
try{
if(index%100==0)
fw.write("\n");

fw.write("\t"+color);
}catch(Exception e){
e.printStackTrace();
}
}
public int[] handlepixels(Image img, int x, int y, int w, int h) {
int[] pixels = new int[w * h];
PixelGrabber pg = new PixelGrabber(img, x, y, w, h, pixels, 0, w);
try {
pg.grabPixels();
} catch (InterruptedException e) {
System.err.println("interrupted waiting for pixels!");

}
if ((pg.getStatus() & ImageObserver.ABORT) != 0) {
System.err.println("image fetch aborted or errored");
}
return pixels;
}
public static void main(String[] args){
Splice splice=new Splice();
}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值