缩略图与原图不一致的java实现


网站: JavaEye 作者: wq163 发表时间: 2007-07-29 13:17 此文章来自于 http://www.iteye.com
声明:本文系JavaEye网站原创文章,未经JavaEye网站或者作者本人书面许可,任何其他网站严禁擅自发表本文,否则必将追究法律责任!
原文链接: http://www.iteye.com/topic/106639

        昨天早上朋友传给我一张图片,曾被此君的一些恶作剧图片吓倒过,这次刚开始也不敢打开。这张图片在winxp下缩略图显示与打开后的内容不一样,让几个同学看了一下,他们都说看过了。就是前段时间网上流传的‘一张令所有人吃惊的图片’,是一张椅子的图片,但是,如果你的系统是XP,把它下载后保存到任意一个文件夹中,打开文件夹,用缩略图的方式查看,会看到图片的缩略图是一个机器女人坐在地上。

原图:缩略图与原图不一致的java实现_第1张图片缩略图:缩略图与原图不一致的java实现_第2张图片



很惊奇,但直觉的反映就是这张图片可能被存储了别的信息或修改了头文件信息。

        经过一番研究之后,知道了原理:JPEG标准在文件中记录了一些EXIF信息,缩略图是一幅较小的JPEG图片,存储在EXIF信息段。而Windows在第一次显示缩略图时先读当前目录中的"Thumbs.db"这个文件,其实这是一个缩略图数据库,从而来判断是否有该图片的缩略图。如果不存在"Thumbs.db"文件或者该库中不存在该图片的缩略图,那么Windows会尝试取图片中的EXIF信息,判断是否存在缩略图数据。如果图片中EXIF信息中不存在缩略图信息或信息错误,那么Windows就会用插值的方法重新生成缩略图(如果可能则保存到当前目录中的"Thumbs.db"缩略图数据库中)。 对于修改缩略图方法有用ultraEdit直接编辑文件替换EXIF信息或用exifer这样的工具,这不是本文关心的内容,本文介绍用java实现的方法。

        程序把一张jpg格式图片的缩略图用另一张图的内容替换,实现的效果跟上面一样

原图:缩略图与原图不一致的java实现_第3张图片缩略图:缩略图与原图不一致的java实现_第4张图片



        实现原理就是抽取一张图片的信息,然后替换掉另一张图片EXIF的Thumbnail。注意抽取的图片长宽比例要与原图一致,否则没有效果,在程序中我已经自动判断并调整了。下面是抽取信息的一个主要方法:


java 代码




  1. public static byte[] getThumbnailImage(InputStream ip,int widthRate,int heightRate) throws IOException    

  2.   

  3. //根据文件名字符串,按长宽比例放缩抽取该文件的ThumbnailImage,此方法调用到getThumbnailImage(),返回byte数组    

  4. private byte[] extractThumbnail(String fileStr,int widthRate,int heightRate)    

  5.   

  6. 向另一张图片写入Thumbnail的方法,用到mediautil库:    

  7. public void writeThumbnail(byte newThumbnail[],String fileStr)    

  8.   

  9. 主方法,thumbnailFile为要抽取缩略图信息的图片,destfile为目标图片也就是把它的缩略图用thumbnailFile信息替换掉    

  10. public void test(String thumbnailFile,String destfile){    

  11.      BufferedImage buf=null;    

  12.      int wRate=0;    

  13.      int hRate=0;    

  14.      try{    

  15.          //获取destfile的长和宽,供放缩thumbnailFile使用    

  16.          buf=readImage(destfile);    

  17.          wRate=buf.getWidth();    

  18.          hRate=buf.getHeight();    

  19.      }catch(Exception e){e.printStackTrace();}    

  20.      finally{    

  21.          byte[] bt=extractThumbnail(thumbnailFile,wRate,hRate);//抽取thumbnailFile数据,存入bt中    

  22.          writeThumbnail(bt,destfile);//向文件名为destfile的图片中写入bt中的thumbnail数据    

  23.      }    

  24. ———————————————下面是全部源代码(小实验,代码写得很乱)———————————————    

  25. import java.io.*;    

  26. import java.util.Date;    

  27. import java.awt.*;    

  28. import java.awt.image.*;    

  29. import java.util.*;    

  30. import javax.imageio.*;    

  31. import javax.imageio.stream.ImageInputStream;    

  32. import mediautil.gen.directio.*;    

  33. import mediautil.gen.Log;    

  34. import java.awt.geom.AffineTransform;    

  35. import mediautil.image.ImageResources;    

  36. import mediautil.image.jpeg.LLJTran;    

  37. import mediautil.image.jpeg.AbstractImageInfo;    

  38. import mediautil.image.jpeg.Exif;    

  39. import mediautil.image.jpeg.Entry;    

  40. import mediautil.image.jpeg.LLJTranException;    

  41. public class TestExif {    

  42. /**   

  43.      * Utility Method to get a Thumbnail Image in a byte array from an   

  44.      * InputStream to a full size image. The full size image is read and scaled   

  45.      * to a Thumbnail size using Java API.   

  46.      */    

  47.     private static byte[] getThumbnailImage(InputStream ip) throws IOException{    

  48.         return getThumbnailImage(ip,0,0);    

  49.     }    

  50.     

  51. public static byte[] getThumbnailImage(InputStream ip,int widthRate,int heightRate) throws IOException {    

  52.         ImageReader reader;    

  53.         ImageInputStream iis = ImageIO.createImageInputStream(ip);    

  54.         reader = (ImageReader) ImageIO.getImageReaders(iis).next();    

  55.         reader.setInput(iis);    

  56.         BufferedImage image = reader.read(0);    

  57.         iis.close();    

  58.   

  59.         int t, longer, shorter;    

  60.         if(widthRate>0&&heightRate>0){    

  61.              longer = widthRate;    

  62.              shorter = heightRate;    

  63.         }else{    

  64.              longer = image.getWidth();    

  65.              shorter = image.getHeight();    

  66.         }    

  67.                   

  68.        //按传入参数的长宽比例放缩    

  69.        double factor = 160/(double)image.getWidth();    

  70.         double factor2 =(160* (double)shorter)/((double)longer*image.getHeight());    

  71.         AffineTransform tx = new AffineTransform();    

  72.         tx.scale(factor, factor2);    

  73.         AffineTransformOp affineOp = new AffineTransformOp(tx, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);    

  74.         image = affineOp.filter(image, null);   

  75.     

  76.          // Write Out the Scaled Image to a ByteArrayOutputStream and return the bytes    

  77.          ByteArrayOutputStream byteStream = new ByteArrayOutputStream(2048);    

  78.          String format = "JPG";    

  79.          ImageIO.write(image, format, byteStream);    

  80.          System.out.println(byteStream.toByteArray());    

  81.          return byteStream.toByteArray();    

  82. }    

  83.     public byte[] extractThumbnail(String fileStr){    

  84.      return extractThumbnail(fileStr,0,0);    

  85.     }    

  86.     

  87. //根据文件名字符串,按长宽比例放缩抽取该文件的ThumbnailImage,返回byte数组    

  88. private byte[] extractThumbnail(String fileStr,int widthRate,int heightRate) {    

  89.   byte newThumbnail[]=null;    

  90.      try{    

  91.       InputStream fip = new FileInputStream(fileStr); // No need to buffer    

  92.       SplitInputStream sip = new SplitInputStream(fip);    

  93.       //Create a substream for LLJTran to use    

  94.       InputStream subIp = sip.createSubStream();    

  95.       LLJTran llj = new LLJTran(subIp);    

  96.       llj.initRead(LLJTran.READ_HEADER, truetrue);      

  97.       sip.attachSubReader(llj, subIp);    

  98.       newThumbnail= getThumbnailImage(sip,widthRate,heightRate);    

  99.       sip.wrapup();    

  100.       fip.close();    

  101.       llj.freeMemory();    

  102.       String msg = llj.getErrorMsg();    

  103.       if(msg != null){    

  104.          System.out.println("Error in LLJTran While Loading Image: " + msg);    

  105.          Exception e = llj.getException();    

  106.          if(e != null){    

  107.             System.out.println("Got an Exception, throwing it..");    

  108.              throw e;    

  109.           }    

  110.              System.exit(1);    

  111.       }    

  112.      }catch(Exception e){System.out.println("extractThumbnail"+e);}    

  113.       return newThumbnail;    

  114. }    

  115. //向另一张图片写入Thumbnail的方法,用到mediautil库:    

  116. public void writeThumbnail(byte newThumbnail[],String fileStr){    

  117.      try{    

  118.       InputStream fip = new FileInputStream(fileStr);    

  119.       LLJTran llj = new LLJTran(fip);    

  120.       llj.read(LLJTran.READ_ALL,true);    

  121.           

  122.       AbstractImageInfo imageInfo = llj.getImageInfo();    

  123.       //important!!!!  If the Image does not have an Exif Header create a dummy Exif    

  124.       //Header    

  125.       if(!(imageInfo instanceof Exif)){    

  126.                 System.out.println("Adding a Dummy Exif Header");    

  127.                 llj.addAppx(LLJTran.dummyExifHeader, 0,    

  128.                             LLJTran.dummyExifHeader.length, true);    

  129.       }    

  130.   

  131.       //  Set the new Thumbnail    

  132.       if(llj.setThumbnail(newThumbnail, 0, newThumbnail.length,ImageResources.EXT_JPG))    

  133.        System.out.println("Successfully Set New Thumbnail");    

  134.       fip = new BufferedInputStream(new FileInputStream(fileStr));    

  135.       OutputStream out = new BufferedOutputStream(new FileOutputStream("3.jpg"));    

  136.       //   

  137.       llj.xferInfo(fip, out, LLJTran.REPLACE, LLJTran.REPLACE);    

  138.       fip.close();    

  139.       out.close();    

  140.       // Cleanup    

  141.       llj.freeMemory();    

  142.      }catch(Exception e){System.out.println("writeThumbnail"+e);}    

  143.     }    

  144.         

  145.   public BufferedImage readImage(InputStream in,String type)throws IOException{    

  146.        Iterator readers = ImageIO.getImageReadersByFormatName(type);    

  147.        ImageReader reader = (ImageReader)readers.next();    

  148.        ImageInputStream iis = ImageIO.createImageInputStream(in);    

  149.        reader.setInput(iis,true);    

  150.        BufferedImage img = reader.read(0);      

  151.        return img;    

  152.   }    

  153.   public BufferedImage readImage(String fileName) throws IOException{    

  154.        String type = fileName.substring(fileName.lastIndexOf(".")+1);    

  155.        return readImage(new FileInputStream(fileName), type);    

  156.   }    

  157.         

  158.    public void test(String thumbnailFile,String destfile){         BufferedImage buf=null;    

  159.         int wRate=0;    

  160.         int hRate=0;    

  161.         try{    

  162.          buf=readImage(destfile);    

  163.          wRate=buf.getWidth();    

  164.          hRate=buf.getHeight();    

  165.      }catch(Exception e){e.printStackTrace();}    

  166.      finally{    

  167.          byte[] bt=extractThumbnail(thumbnailFile,wRate,hRate);    

  168.          writeThumbnail(bt,destfile);    

  169.       }      

  170.     }    

  171.             

  172.     public static void main(String arg[]){    

  173.       TestExif t= new TestExif();    

  174.        t.test("11.jpg""22.jpg"); //用11.jpg的数据替换22.jpg的缩略图   

  175.     }    

  176. }    








《 缩略图与原图不一致的java实现 》 的评论也很精彩,欢迎您也添加评论。查看详细 >>

推荐相关文章:
   浅谈一下java API设法的一个错误带来的后果引以为戒
   基于hibernate的开源通用查询框架 -- bba96介绍




JavaEye推荐
上海乐福狗信息技术有限公司:诚聘技术经理和开发工程师
免费下载IBM社区版软件--它基于开放的标准,支持广泛的开发类型,让您的开发高效自主!
京沪穗蓉四地免费注册,SOA技术高手汇聚交锋.
上海:优秀公司德比:高薪诚聘 资深Java工程师
广州:优易公司:诚聘Java工程师,开发经理
上海:尤恩斯国际集团:诚聘开发工程师
北京:优秀公司NHNChina招聘:WEB开发,系统管理,JAVA开发, DBA


你可能感兴趣的:(java,windows,XP,招聘,IIS)