Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 304|回复: 0

[图像处理学习]原图与缩略图不一致的java实现

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

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

    原图:



    缩略图:


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

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

    原图:缩略图:

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

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


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

           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...{
             //获取destfile的长和宽,供放缩thumbnailFile使用
             buf=readImage(destfile);
             wRate=buf.getWidth();
             hRate=buf.getHeight();
         }catch(Exception e)...{e.printStackTrace();}
         finally...{
             byte[] bt=extractThumbnail(thumbnailFile,wRate,hRate);//抽取thumbnailFile数据,存入bt中
             writeThumbnail(bt,destfile);//向文件名为destfile的图片中写入bt中的thumbnail数据
         }
    ―――――――――――――――下面是全部源代码―――――――――――――――
    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 ...{
    /** *//**
         * Utility Method to get a Thumbnail Image in a byte array from an
         * InputStream to a full size image. The full size image is read and scaled
         * to a Thumbnail size using Java API.
         */
        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);

             // Write Out the Scaled Image to a ByteArrayOutputStream and return the bytes
             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);
        }

    //根据文件名字符串,按长宽比例放缩抽取该文件的ThumbnailImage,返回byte数组
    private byte[] extractThumbnail(String fileStr,int widthRate,int heightRate) ...{
      byte newThumbnail[]=null;
         try...{
          InputStream fip = new FileInputStream(fileStr); // No need to buffer
          SplitInputStream sip = new SplitInputStream(fip);
          //Create a substream for LLJTran to use
          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;
    }
    //向另一张图片写入Thumbnail的方法,用到mediautil库:
    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();
          //important!!!!  If the Image does not have an Exif Header create a dummy Exif
          //Header
          if(!(imageInfo instanceof Exif))...{
                    System.out.println("Adding a Dummy Exif Header");
                    llj.addAppx(LLJTran.dummyExifHeader, 0,
                                LLJTran.dummyExifHeader.length, true);
          }

          //  Set the new Thumbnail
          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();
          // Cleanup
          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"); //用11.jpg的数据替换22.jpg的缩略图
        }
    }
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-5-18 23:21 , Processed in 0.437719 second(s), 48 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表