`

写了一个实用的图像放大缩小程序,但是动画GIF转换后不会显示了,只有第一帧

    博客分类:
  • Java
阅读更多
写了一个实用的图像放大缩小程序,但是动画GIF转换后不会显示了,只有第一帧
代码如下,有没做过GIF转换的,提提建议一下,谢谢。

import java.awt.Canvas;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.AreaAveragingScaleFilter;
import java.awt.image.BufferedImage;
import java.awt.image.FilteredImageSource;
import java.io.File;
import java.util.Arrays;
import javax.imageio.ImageIO;
import org.apache.log4j.Logger;

/**
 * 一个实用的图像放大缩小程序
 * 
 * @author YuLimin
 */
public class ZoomImage
{
	private static final Logger logger = Logger.getLogger(ZoomImage.class);
	private static Component component = new Canvas();
	// ".pcx","tga",".tif"这三种格式目前还不支持;
	// 这些定义的格式经过我测试过是可以支持的。
	private static String[] imageFormatArray = new String[]{".jpg",".jpeg",".gif",".png",".bmp"};

	/**
	 * 测试用例
	 * 
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception
	{
		ZoomImage zoomImage = new ZoomImage();
		zoomImage.listFormt();
		// 缩小四倍
		zoomImage.zoom("E:/图片/城市风光",0.25,false);
		// 放大四倍
		zoomImage.zoom("E:/图片/自然风光",4,false);
	}

	/**
	 * 查看图像I/O库所支持的图像格式有哪些格式
	 */
	public void listFormt()
	{
		String readerMIMETypes[] = ImageIO.getReaderMIMETypes();
		String writerMIMETypes[] = ImageIO.getWriterMIMETypes();
		if(logger.isInfoEnabled())
		{
			logger.info("ReaderMIMETypes:" + Arrays.asList(readerMIMETypes));
			logger.info("WriterMIMETypes:" + Arrays.asList(writerMIMETypes));
		}
	}

	/**
	 * 校验图像文件的格式是否可以进行缩放
	 * 
	 * @param fileName
	 * @return
	 */
	public boolean verifyImageFormat(String fileName)
	{
		boolean result = false;
		for(int i = 0;i < imageFormatArray.length;i++)
		{
			if(fileName.toLowerCase().lastIndexOf(imageFormatArray[i]) == (fileName.length() - imageFormatArray[i].length()))
			{
				result = true;
				break;
			}
		}
		return result;
	}

	/**
	 * 将目录下的所有图像进行放大缩小
	 * 
	 * @param strDir 图像的目录
	 * @param zoomRatio 放大缩小的倍率
	 * @param rebuild 是否重新创建,即已经存在的图像是否覆盖重建
	 * @throws Exception
	 */
	public void zoom(String strDir,double zoomRatio,boolean rebuild) throws Exception
	{
		File fileDir = new File(strDir);
		if(!fileDir.exists())
		{
			logger.warn("Not exist:" + strDir);
			return;
		}
		String dirTarget = strDir + "/Zoom" + zoomRatio;
		File fileTarget = new File(dirTarget);
		if(!fileTarget.exists())
		{
			fileTarget.mkdir();
		}
		File[] files = fileDir.listFiles();
		StringBuilder stringBuilder = new StringBuilder();
		for(int i = 0;i < files.length;i++)
		{
			String fileFullName = files[i].getCanonicalPath();
			String fileShortName = files[i].getName();
			if(!new File(fileFullName).isDirectory())// 排除二级目录,如果想就再递归一次,这里省略
			{
				if(verifyImageFormat(fileShortName))
				{
					if(logger.isInfoEnabled())
					{
						logger.info("Begin Zoom:" + fileFullName);
					}
					stringBuilder = new StringBuilder();
					stringBuilder.append(dirTarget).append("/").append(fileShortName);
					if(!new File(stringBuilder.toString()).exists() || rebuild)
					{
						try
						{
							createZoomSizeImage(fileFullName,stringBuilder.toString(),zoomRatio);
						}
						catch(Exception e)
						{
							logger.error("createZoomSizeImage Error:" + fileFullName,e);
						}
					}
					if(logger.isInfoEnabled())
					{
						logger.info("End Zoom:" + fileFullName);
					}
				}
				else
				{
					logger.warn("Can't Zoom:" + fileFullName);
				}
			}
		}
	}

	/**
	 * 按比例进行放大缩小图像,zoomRatio = 1为原大,zoomRatio > 1为放大,zoomRatio < 1 为缩小
	 * 
	 * @param fileName
	 * @param fileNameTarget
	 * @param zoomRatio
	 * @throws Exception
	 */
	public void createZoomSizeImage(String fileName,String fileNameTarget,double zoomRatio) throws Exception
	{
		Image image = ImageIO.read(new File(fileName));
		int width = new Double(image.getWidth(null) * zoomRatio).intValue();
		int height = new Double(image.getHeight(null) * zoomRatio).intValue();
		AreaAveragingScaleFilter areaAveragingScaleFilter = new AreaAveragingScaleFilter(width,height);
		FilteredImageSource filteredImageSource = new FilteredImageSource(image.getSource(),areaAveragingScaleFilter);
		BufferedImage bufferedImage = new BufferedImage(width,height,BufferedImage.TYPE_3BYTE_BGR);
		Graphics graphics = bufferedImage.createGraphics();
		graphics.drawImage(component.createImage(filteredImageSource),0,0,null);
		ImageIO.write(bufferedImage,"JPEG",new File(fileNameTarget));
	}
}
分享到:
评论
14 楼 little06 2008-05-20  
直接读写图片,虽然用java也可以做到
但是 没有试过图片服务器网站用java来处理的
可以用jni,调用底层,比如imagemagick,速度快
不相信的,可以试一试每分钟处理500M,1000张图片左右看看
13 楼 neitnaco 2007-11-23  
我收藏了呀!
你们都是高手耶。
在这个论坛里面我学到了好多得东东!
12 楼 lanhuai 2007-07-24  
我这里有破解的gif4j
11 楼 zelsa 2007-07-10  
试试gif4j
10 楼 jj5715 2007-07-10  
同意楼上,java压缩大图片速度不行,还是感觉linux下自带的图片压缩工具比较快。
9 楼 lordhong 2007-07-09  
直接调用ImageMagick就行了, 自己写重新造轮子?
8 楼 Eastsun 2007-07-09  
YuLimin 写道
谢谢Eastsun
这样可以,但是无论放大还是缩小,看到的全是破DVD的播放效果,呵呵。。。马赛克。。。



马赛克?那应该是你的代码那儿有问题.
有空我写个试试.
7 楼 YuLimin 2007-07-08  
谢谢Eastsun
这样可以,但是无论放大还是缩小,看到的全是破DVD的播放效果,呵呵。。。马赛克。。。

	/**
	 * 读取GIF文件,并进行缩放,存放于BufferedImage数组中
	 * 
	 * @param inputFileName
	 * @param zoomRatio
	 * @return
	 * @throws IOException
	 */
	public BufferedImage[] readGifFile(String inputFileName,double zoomRatio) throws IOException
	{
		Iterator imageReaders = ImageIO.getImageReadersBySuffix("GIF");
		if(!imageReaders.hasNext())
		{
			throw new IOException("no ImageReaders for GIF");
		}
		ImageReader imageReader = (ImageReader)imageReaders.next();
		File file = new File(inputFileName);
		if(!file.exists())
		{
			throw new IOException("no file: " + file.getName());
		}
		imageReader.setInput(ImageIO.createImageInputStream(file));
		List < BufferedImage > images = new ArrayList < BufferedImage >();
		for(int i = 0;true;++i)
		{
			try
			{
				Image image = imageReader.read(i);
				int width = new Double(image.getWidth(null) * zoomRatio).intValue();
				int height = new Double(image.getHeight(null) * zoomRatio).intValue();
				if(width > 0 && height > 0)
				{
					AreaAveragingScaleFilter areaAveragingScaleFilter = new AreaAveragingScaleFilter(width,height);
					FilteredImageSource filteredImageSource = new FilteredImageSource(image.getSource(),areaAveragingScaleFilter);
					BufferedImage bufferedImage = new BufferedImage(width,height,BufferedImage.TYPE_3BYTE_BGR);
					Graphics graphics = bufferedImage.createGraphics();
					graphics.drawImage(component.createImage(filteredImageSource),0,0,null);
					images.add(bufferedImage);
				}
			}
			catch(IndexOutOfBoundsException e)
			{
				break;
			}
		}
		return images.toArray(new BufferedImage[images.size()]);
	}
	/**
	 * 根据BufferedImage数组的数据,写入到GIF文件中去
	 * 
	 * @param images
	 * @param outputFileName
	 * @throws IOException
	 */
	public void writeGifFile(BufferedImage[] images,String outputFileName) throws IOException
	{
		Iterator imageWriters = ImageIO.getImageWritersBySuffix("GIF");
		if(!imageWriters.hasNext())
		{
			throw new IOException("no ImageWriters for GIF");
		}
		ImageWriter imageWriter = (ImageWriter)imageWriters.next();
		File file = new File(outputFileName);
		file.delete();
		imageWriter.setOutput(ImageIO.createImageOutputStream(file));
		if(imageWriter.canWriteSequence())
		{
			if(logger.isInfoEnabled())
			{
				logger.info("Using writeToSequence for format GIF");
			}
			imageWriter.prepareWriteSequence(null);
			for(int i = 0;i < images.length;++i)
			{
				imageWriter.writeToSequence(new IIOImage(images[i],null,null),null);
			}
			imageWriter.endWriteSequence();
		}
		else
		{
			if(logger.isInfoEnabled())
			{
				logger.info("cross fingers for format GIF");
			}
			for(int i = 0;i < images.length;++i)
			{
				imageWriter.write(images[i]);
			}
		}
	}


调用
zoomImage.writeGifFile(zoomImage.readGifFile(inputFileName,zoomRatio),outputFileName);
6 楼 Eastsun 2007-07-08  
YuLimin 写道


直接通过ImageIO.write(bufferedImage,"GIF",new File(fileNameTarget));
但是仍不支持直接的动画写入,仍只是第一帧而已。


呵呵,谁说JDK6不支持gif动画写入了~~
当然是支持的,当然也不能通过简单的ImageIO.write的方法来写入了.

简单的说下gif动画的写入方法.
先通过
        Iterator<ImageWriter> iter =ImageIO.getImageWritersByFormatName("gif");
        ImageWriter writer =null;
        while(iter.hasNext()){
            writer =iter.next();
            if(writer.canWriteSequence()) break;
        }

得到gif文件的写入器.
然后创建一个image输出流
       ImageOutputStream imageOut = ImageIO.createImageOutputStream(new File("xxxx.gif"));

然后设置write:
      write.setOutput(imageOut);

最后反复调用wirte的writeToSequence方法即可.
注意在调用writeToSequence方法前要调用prepareWriteSequence方法,之后调用endWriteSequence方法.
还有一些细节问题可以自己参考jdk6.0的docs文档
5 楼 YuLimin 2007-07-08  
Eastsun 写道
YuLimin 写道


有读取GIF的,没有写GIF的,看来JDK默认的还没有支持?
1.6.0或1.7.0不知道有没有支持了?还是有其它的解决方案?


JDK1.6.0是支持GIF写的.
因为在JDK1.6之前GIF算法是受专利保护的,到JDK1.6时保护过期了,所以JDK1.6就支持GIF写了.

JDK1.6.0支持的格式如下:
ReaderMIMETypes:[image/png, image/jpeg, image/x-png, image/vnd.wap.wbmp, image/bmp, image/gif]
WriterMIMETypes:[image/jpeg, image/png, image/x-png, image/vnd.wap.wbmp, image/bmp, image/gif]
ReaderFormatNames:[BMP, bmp, jpg, JPG, wbmp, jpeg, png, PNG, JPEG, WBMP, GIF, gif]
WriterFormatNames:[jpg, BMP, bmp, JPG, jpeg, wbmp, png, JPEG, PNG, WBMP, GIF, gif]
直接通过ImageIO.write(bufferedImage,"GIF",new File(fileNameTarget));
但是仍不支持直接的动画写入,仍只是第一帧而已。

另外一些资源参考:
肢解GIF格式动画图片
http://sailing8036.spaces.live.com/Blog/cns!1pV60cmgp_2-KECsRGDNzV2w!325.entry
GIF格式可以将多个静态image组合成动画效果,所以一张GIF图片中肯定包含着每个image的内容,以及每个图片的播放演示delay时间。

这个网站提供了开源的java处理算法:
http://www.fmsware.com/stuff/gif.html
文件下载
http://www.fmsware.com/stuff/gif.zip

此开源的网站还提供了PhotoShop (.psd) reader class,Supports uncompressed or RLE-compressed RGB files only.

高级图像处理图像I/O API RC 1.0
http://www.tiantiansoft.com/Get/java/085816818.htm

下面这个地址里作者收集了好几个关于GIF的资源列表
http://www.westbrae.net/lbs/article.asp?id=77
4 楼 xiaoyu 2007-07-07  
GIF太复杂了。 java的2D API太原始了。 用起来不爽
3 楼 Eastsun 2007-07-07  
YuLimin 写道


有读取GIF的,没有写GIF的,看来JDK默认的还没有支持?
1.6.0或1.7.0不知道有没有支持了?还是有其它的解决方案?


JDK1.6.0是支持GIF写的.
因为在JDK1.6之前GIF算法是受专利保护的,到JDK1.6时保护过期了,所以JDK1.6就支持GIF写了.
2 楼 YuLimin 2007-07-07  
Readonly 写道
ImageIO.write(bufferedImage,"JPEG",new File(fileNameTarget));

只生成JPG格式?


支持的格式列表如下:
String readerFormatNames[] = ImageIO.getReaderFormatNames();
String writerFormatNames[] = ImageIO.getWriterFormatNames();
logger.info("ReaderFormatNames:" + Arrays.asList(readerFormatNames));
logger.info("WriterFormatNames:" + Arrays.asList(writerFormatNames));


结果如下:
java version "1.5.0_10"
ReaderFormatNames:[BMP, jpeg, bmp, wbmp, gif, png, JPG, jpg, JPEG, WBMP]
WriterFormatNames:[BMP, bmp, jpeg, wbmp, png, JPG, PNG, jpg, WBMP, JPEG]

java version "1.4.2_12"
ReaderFormatNames:[jpeg, gif, JPG, png, jpg, JPEG]
WriterFormatNames:[jpeg, png, JPG, PNG, jpg, JPEG]

有读取GIF的,没有写GIF的,看来JDK默认的还没有支持?
1.6.0或1.7.0不知道有没有支持了?还是有其它的解决方案?
1 楼 Readonly 2007-07-07  
ImageIO.write(bufferedImage,"JPEG",new File(fileNameTarget));

只生成JPG格式?

相关推荐

    C#程序开发范例宝典(第2版).part08

    精选570个典型范例,全面覆盖实用和热点技术,涉及面广,实用性强源于实际项目开发,帮助读者短时间掌握更多实用技术,提高编程水平范例经过精心编排,重点、难点突出,易学易懂书后附录提供快速索引,即查、即学、...

    C#程序开发范例宝典(第2版).part12

    精选570个典型范例,全面覆盖实用和热点技术,涉及面广,实用性强源于实际项目开发,帮助读者短时间掌握更多实用技术,提高编程水平范例经过精心编排,重点、难点突出,易学易懂书后附录提供快速索引,即查、即学、...

    delphi 开发经验技巧宝典源码

    第1章 开发环境 1 1.1 环境设置 2 0001 如何定制工具栏 2 0002 如何定制组件面板 2 0003 如何定制代码编辑器 3 0004 保存自定义开发环境桌面 4 1.2 组件安装 4 0005 安装ActiveX组件 4 0006 安装...

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

    2个目标文件,FTP的目标是:(1)提高文件的共享性(计算机程序和/或数据),(2)鼓励间接地(通过程序)使用远程计算机,(3)保护用户因主机之间的文件存储系统导致的变化,(4)为了可靠和高效地传输,虽然用户...

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

    2个目标文件,FTP的目标是:(1)提高文件的共享性(计算机程序和/或数据),(2)鼓励间接地(通过程序)使用远程计算机,(3)保护用户因主机之间的文件存储系统导致的变化,(4)为了可靠和高效地传输,虽然用户...

    C#程序开发范例宝典(第2版).part13

    精选570个典型范例,全面覆盖实用和热点技术,涉及面广,实用性强源于实际项目开发,帮助读者短时间掌握更多实用技术,提高编程水平范例经过精心编排,重点、难点突出,易学易懂书后附录提供快速索引,即查、即学、...

    C#程序开发范例宝典(第2版).part02

    精选570个典型范例,全面覆盖实用和热点技术,涉及面广,实用性强源于实际项目开发,帮助读者短时间掌握更多实用技术,提高编程水平范例经过精心编排,重点、难点突出,易学易懂书后附录提供快速索引,即查、即学、...

    FlySee(飞翔看图软件)2.3

    支持GIF动画,支持快速打开快速翻页,支持文件和目录拖放操作,可对图片进行放大缩小,可进行全屏浏览,可以自动播放图片幻灯片,可快速设置任意图片或选区为桌面墙纸,可快速旋转图像,可为图像增加各种特效。...

    C#开发实例大全(基础卷).软件开发技术联盟(带详细书签) PDF 下载

    实例196 以全屏方式显示程序窗体 263 实例197 通过子窗体刷新父窗体 264 实例198 拖动无边框窗体 265 实例199 禁用窗口上的关闭按钮 267 实例200 向窗体中拖放图片并显示 268 实例201 使应用程序在进程中消失 269 ...

    EXCEL集成工具箱V6.0

    允许一次性多图片格式(*.JPG/*.GIF/*.BMP/*.PNG),且支持模糊与非模糊方式导入图片,还可以在导入的图片上显示其文件名称以易于管理。 【批量导出图片】 将EXCEL中指定某列中的图片按显示图片大小导出到指定的...

Global site tag (gtag.js) - Google Analytics