- wq163
- 等级: 初级会员

- 性别:

- 文章: 33
- 积分: 10
- 来自: 上海

|
最后更新时间:2008-03-07 关键字: java, thumbnail, 缩略图, 图片, mediautil
昨天早上朋友传给我一张图片,曾被此君的一些恶作剧图片吓倒过,这次刚开始也不敢打开。这张图片在winxp下缩略图显示与打开后的内容不一样,让几个同学看了一下,他们都说看过了。就是前段时间网上流传的‘一张令所有人吃惊的图片’,是一张椅子的图片,但是,如果你的系统是XP,把它下载后保存到任意一个文件夹中,打开文件夹,用缩略图的方式查看,会看到图片的缩略图是一个机器女人坐在地上。 原图: 缩略图: 
很惊奇,但直觉的反映就是这张图片可能被存储了别的信息或修改了头文件信息。 经过一番研究之后,知道了原理:JPEG标准在文件中记录了一些EXIF信息,缩略图是一幅较小的JPEG图片,存储在EXIF信息段。而Windows在第一次显示缩略图时先读当前目录中的"Thumbs.db"这个文件,其实这是一个缩略图数据库,从而来判断是否有该图片的缩略图。如果不存在"Thumbs.db"文件或者该库中不存在该图片的缩略图,那么Windows会尝试取图片中的EXIF信息,判断是否存在缩略图数据。如果图片中EXIF信息中不存在缩略图信息或信息错误,那么Windows就会用插值的方法重新生成缩略图(如果可能则保存到当前目录中的"Thumbs.db"缩略图数据库中)。 对于修改缩略图方法有用ultraEdit直接编辑文件替换EXIF信息或用exifer这样的工具,这不是本文关心的内容,本文介绍用java实现的方法。 程序把一张jpg格式图片的缩略图用另一张图的内容替换,实现的效果跟上面一样 原图: 缩略图:
实现原理就是抽取一张图片的信息,然后替换掉另一张图片EXIF的Thumbnail。注意抽取的图片长宽比例要与原图一致,否则没有效果,在程序中我已经自动判断并调整了。下面是抽取信息的一个主要方法: java 代码 - public static byte[] getThumbnailImage(InputStream ip,int widthRate,int heightRate) throws IOException
-
-
- private byte[] extractThumbnail(String fileStr,int widthRate,int heightRate)
-
- 向另一张图片写入Thumbnail的方法,用到mediautil库:
- public void writeThumbnail(byte newThumbnail[],String fileStr)
-
- 主方法,thumbnailFile为要抽取缩略图信息的图片,destfile为目标图片也就是把它的缩略图用thumbnailFile信息替换掉
- public void test(String thumbnailFile,String destfile){
- BufferedImage buf=null;
- int wRate=0;
- int hRate=0;
- try{
-
- buf=readImage(destfile);
- wRate=buf.getWidth();
- hRate=buf.getHeight();
- }catch(Exception e){e.printStackTrace();}
- finally{
- byte[] bt=extractThumbnail(thumbnailFile,wRate,hRate);
- writeThumbnail(bt,destfile);
- }
- ———————————————下面是全部源代码(小实验,代码写得很乱)———————————————
- import java.io.*;
- import java.util.Date;
- import java.awt.*;
- import java.awt.image.*;
- import java.util.*;
- import javax.imageio.*;
- import javax.imageio.stream.ImageInputStream;
- import mediautil.gen.directio.*;
- import mediautil.gen.Log;
- import java.awt.geom.AffineTransform;
- import mediautil.image.ImageResources;
- import mediautil.image.jpeg.LLJTran;
- import mediautil.image.jpeg.AbstractImageInfo;
- import mediautil.image.jpeg.Exif;
- import mediautil.image.jpeg.Entry;
- import mediautil.image.jpeg.LLJTranException;
- public class TestExif {
-
-
-
-
-
- private static byte[] getThumbnailImage(InputStream ip) throws IOException{
- return getThumbnailImage(ip,0,0);
- }
-
- public static byte[] getThumbnailImage(InputStream ip,int widthRate,int heightRate) throws IOException {
- ImageReader reader;
- ImageInputStream iis = ImageIO.createImageInputStream(ip);
- reader = (ImageReader) ImageIO.getImageReaders(iis).next();
- reader.setInput(iis);
- BufferedImage image = reader.read(0);
- iis.close();
-
- int t, longer, shorter;
- if(widthRate>0&&heightRate>0){
- longer = widthRate;
- shorter = heightRate;
- }else{
- longer = image.getWidth();
- shorter = image.getHeight();
- }
-
-
- double factor = 160/(double)image.getWidth();
- double factor2 =(160* (double)shorter)/((double)longer*image.getHeight());
- AffineTransform tx = new AffineTransform();
- tx.scale(factor, factor2);
- AffineTransformOp affineOp = new AffineTransformOp(tx, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
- image = affineOp.filter(image, null);
-
-
- ByteArrayOutputStream byteStream = new ByteArrayOutputStream(2048);
- String format = "JPG";
- ImageIO.write(image, format, byteStream);
- System.out.println(byteStream.toByteArray());
- return byteStream.toByteArray();
- }
- public byte[] extractThumbnail(String fileStr){
- return extractThumbnail(fileStr,0,0);
- }
-
-
- private byte[] extractThumbnail(String fileStr,int widthRate,int heightRate) {
- byte newThumbnail[]=null;
- try{
- InputStream fip = new FileInputStream(fileStr);
- SplitInputStream sip = new SplitInputStream(fip);
-
- InputStream subIp = sip.createSubStream();
- LLJTran llj = new LLJTran(subIp);
- llj.initRead(LLJTran.READ_HEADER, true, true);
- sip.attachSubReader(llj, subIp);
- newThumbnail= getThumbnailImage(sip,widthRate,heightRate);
- sip.wrapup();
- fip.close();
- llj.freeMemory();
- String msg = llj.getErrorMsg();
- if(msg != null){
- System.out.println("Error in LLJTran While Loading Image: " + msg);
- Exception e = llj.getException();
- if(e != null){
- System.out.println("Got an Exception, throwing it..");
- throw e;
- }
- System.exit(1);
- }
- }catch(Exception e){System.out.println("extractThumbnail"+e);}
- return newThumbnail;
- }
-
- public void writeThumbnail(byte newThumbnail[],String fileStr){
- try{
- InputStream fip = new FileInputStream(fileStr);
- LLJTran llj = new LLJTran(fip);
- llj.read(LLJTran.READ_ALL,true);
-
- AbstractImageInfo imageInfo = llj.getImageInfo();
-
-
- if(!(imageInfo instanceof Exif)){
- System.out.println("Adding a Dummy Exif Header");
- llj.addAppx(LLJTran.dummyExifHeader, 0,
- LLJTran.dummyExifHeader.length, true);
- }
-
-
- if(llj.setThumbnail(newThumbnail, 0, newThumbnail.length,ImageResources.EXT_JPG))
- System.out.println("Successfully Set New Thumbnail");
- fip = new BufferedInputStream(new FileInputStream(fileStr));
- OutputStream out = new BufferedOutputStream(new FileOutputStream("3.jpg"));
-
- llj.xferInfo(fip, out, LLJTran.REPLACE, LLJTran.REPLACE);
- fip.close();
- out.close();
-
- llj.freeMemory();
- }catch(Exception e){System.out.println("writeThumbnail"+e);}
- }
-
- public BufferedImage readImage(InputStream in,String type)throws IOException{
- Iterator readers = ImageIO.getImageReadersByFormatName(type);
- ImageReader reader = (ImageReader)readers.next();
- ImageInputStream iis = ImageIO.createImageInputStream(in);
- reader.setInput(iis,true);
- BufferedImage img = reader.read(0);
- return img;
- }
- public BufferedImage readImage(String fileName) throws IOException{
- String type = fileName.substring(fileName.lastIndexOf(".")+1);
- return readImage(new FileInputStream(fileName), type);
- }
-
- public void test(String thumbnailFile,String destfile){ BufferedImage buf=null;
- int wRate=0;
- int hRate=0;
- try{
- buf=readImage(destfile);
- wRate=buf.getWidth();
- hRate=buf.getHeight();
- }catch(Exception e){e.printStackTrace();}
- finally{
- byte[] bt=extractThumbnail(thumbnailFile,wRate,hRate);
- writeThumbnail(bt,destfile);
- }
- }
-
- public static void main(String arg[]){
- TestExif t= new TestExif();
- t.test("11.jpg", "22.jpg");
- }
- }
Java架构俱乐部,QQ群2826942 ,交流Java架构,领域模型,设计模式,AOP,IOC,轻量级,DDD,项目管理,设计思想等问题,聚集经验丰富的高级程序员,架构师,项目经理等交流以上层面较高的问题。欢迎各位有识之士加入,共同探讨、发表高见、广结精英。为了使各位成员免受无聊信息和低端问题的打扰,请尽量避免讨论代码实现等入门级问题,维护本群的氛围和讨论质量。

- 描述:
- 大小: 3.8 KB

- 描述:
- 大小: 43.4 KB

- 描述:
- 大小: 15.2 KB
声明:JavaEye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
|
| 返回顶楼 |
|
|
- billbai
- 等级: 初级会员

- 文章: 3
- 积分: 0

|
第一次发现这样的情况,见识了!
|
| 返回顶楼 |
|
|
- hama
- 等级: 初级会员

- 文章: 73
- 积分: 36

|
用imageMagick随便搞
|
| 返回顶楼 |
|
|
- laiseeme
- 等级: 初级会员

- 性别:

- 文章: 1205
- 积分: 0
- 来自: 沈阳

|
这个挺好玩的,以前只是知道原理
|
| 返回顶楼 |
|
|
- peacess
- 等级: 初级会员

- 文章: 8
- 积分: 0

|
很好的文章,原理与代码结合
|
| 返回顶楼 |
|
|
- wq163
- 等级: 初级会员

- 性别:

- 文章: 33
- 积分: 10
- 来自: 上海

|
hama 写道 用imageMagick随便搞
我也知道用图像编辑工具可以搞,本文主要说的是java的编程实现
|
| 返回顶楼 |
|
|
- xuelange
- 等级: 初级会员

- 性别:

- 文章: 19
- 积分: 0
- 来自: 深圳

|
用到mediautil库哪个库?好象metadata-extractor-2.2.1.jar等版本都没有该包.
import mediautil.image.jpeg.LLJTran;
import mediautil.image.jpeg.AbstractImageInfo;
import mediautil.image.jpeg.Exif;
import mediautil.image.jpeg.Entry;
import mediautil.image.jpeg.LLJTranException;
|
| 返回顶楼 |
|
|
- wq163
- 等级: 初级会员

- 性别:

- 文章: 33
- 积分: 10
- 来自: 上海

|
xuelange 写道 用到mediautil库哪个库?好象metadata-extractor-2.2.1.jar等版本都没有该包.
import mediautil.image.jpeg.LLJTran;
import mediautil.image.jpeg.AbstractImageInfo;
import mediautil.image.jpeg.Exif;
import mediautil.image.jpeg.Entry;
import mediautil.image.jpeg.LLJTranException;
这个库,metadata-extractor听说是只能读不能写的,我没试过
|
| 返回顶楼 |
|
|
- xiaoyu
- 等级:


- 性别:

- 文章: 774
- 积分: 1319
- 来自: 广东

|
JPEG的标准里面说得很清楚的.
|
| 返回顶楼 |
|
|
- kirin
- 等级: 初级会员

- 文章: 17
- 积分: 8

|
我用了两张.jpg图片做实验
也用了你文中这两张图(载下来,也是.jpg)做实验,程序也跑通了,不知道为何没有看到效果(即图片缩略图没改变)?
System.out.println
- Frame, precision 8
- X= 800, Y= 600
- Components 3 (null)
- Size in MCU 50x38
- [B@1827284
- Frame, precision 8
- X= 600, Y= 450
- Components 3 (null)
- Size in MCU 38x29
- 0xad94(44436) byte(s) read in Unknown/Stream
- Successfully Set New Thumbnail
|
| 返回顶楼 |
|
|