zoukankan      html  css  js  c++  java
  • JPEG格式 介绍

    JPEG格式

    1. jpeg是有损压缩格式, 将像素信息用jpeg保存成文件再读取出来,其中某些像素值会有少许变化。在保存时有个质量参数可在[0,100]之间选择,参数越大图片就越保真,但图片的体积也就越大。一般情况下选择70或80就足够了。
    2. jpeg没有透明信息。
    3. jpeg比较适合用来存储相机拍出来的照片,这类图像用jpeg压缩后的体积比较小。其使用的具体算法核心是离散余弦变换、Huffman编码、算术编码等技术,有兴趣的同学可以在网上找一大堆资料,本文就不详细介绍了。

    接下来要介绍一个有关jpeg非常实用的技术——
    jpeg格式支持不完全读取整张图片,即可以选择读取原图、1/2、1/4、1/8大小的图片
    比如5000*5000的一张大图,可以只读取将其缩小成1/8后即625*625大小的图片。 这样比先完全读取5000*5000的图像,再用算法缩小成625*625大小不知快多少倍。
    如果应用需求只需要一张小图时,这种读取方式就可以大显身手了。

    在c代码中读取jpeg一般是使用libjpeg, 这个库提供了不完全读取图片的功能。

    给ln::LBitmap添加有关jpeg的接口,如下ReadJpeg()第三个参数fraction可取值为1,2,4,8,分别对应1/1,1/2,1/4,1/8

    JpegAPI

    具体的实现在JpegDemo
    用上面的函数进行jpeg的读取和保存的测试

    复制代码
    ```
    ln::LBitmap bmp;
    bmp.ReadBmp(L"one.bmp");
    unsigned char *p = bmp.Pixel(0, 0);
    printf("%d, %d, %d
    ", p[0], p[1], p[2]);
    bmp.WriteJpeg(L"one.jpg", 90);
    ```
    复制代码

    读取one.bmp图片,然后保存成jpeg格式,one.jpg放大后显示如下

    发现左上角的颜色发生了变化,并且也影响到周围的像素,就算将上面WriteJpeg()第二个参数换成100,也还是这种效果,这是Jpeg格式无法避免的问题
    但如果读取一张风景照,再保存成Jpeg,就几乎看不出有什么差别了。

    android平台下实现jpeg预读

    复制代码
    BitmapFactory.Options opt = new BitmapFactory.Options();
    opt.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(info.fullPath, opt); //这里仅仅只读取jpeg的大小
    opt.inJustDecodeBounds = false;
    if (opt.outWidth > opt.outHeight) {
        opt.inSampleSize = opt.outWidth / phSize;//hpSize是允许的图片宽高的最大值
    } else {
        opt.inSampleSize = opt.outHeight / phSize;
    }
    Bitmap b = BitmapFactory.decodeFile(info.fullPath, opt); 
    复制代码

     将BitmapFactory.Options的inJustDecodeBounds 设置为true后,就只会读取Jpeg的大小,而不会去解析像素数据。然后再设置inSampleSize后,就可以根据这个值来读取适当大小的图片,研究Android的源码后可以发现底层也是调用的libjpeg库来实现。

    ios,mac

    本人还没有在iOS/mac中发现如何预读jpeg的官方API。Apple对图形、图像、多媒体领域提供了丰富接口,如果这个功能真没实现就太令我惊讶了! 不过ObjectC完全兼容C,可以调用libjpeg库来实现这个功能。

    .NET下仅读取jpeg的大小

    下面是用c#仅仅读取jpeg宽高(没有解析像素数据), 直接用C#读取1/2,1/4,1/8还不知道如何实现

    FileStream stream = new FileStream(path, FileMode.Open);
    Image img = Image.FromStream(stream, false, false);  //关键是将第三个参数设置为false
    Console.WriteLine("size: {0},{1}", img.Width, img.Height);

    jpeg批量转化工具

    用相机拍出来的原始jpeg图片是高保真质量, 所占文件体积非常大,本人写了一个批量转化的工具,可以将jpeg的质量都转化成80, 图像的宽高不变, 这时人眼几乎看不出有什么差别, 但其体积只有原来的1/3. 如果有大量的照片需要保存时, 节约的空间就很客观了。实现原理很简单, 就是读取jpeg文件, 然后再保存. 
    用c#实现的,代码量非常少,在此贴出全部源码

    JpegBatchConvert

    Exif信息

    另外jpeg文件一般有一个附属的exif信息,这个信息中有图像大小,拍摄时间,拍摄的相关参数,照片方向,图像缩略图等信息。

    用相机拍出来的jpeg都会有这个信息。如果照片方向不是正立的话,在读取到像素取后,还得按exif所指明的方向将图像旋转下。mspaint程序就没有做这个处理,有些图片用picasa查看和用mspaint查看方向就不一样。当然为了简单起见,上面的LBitmap中也自动忽略了exif信息及其图像拍摄时的方向。

    如果不用读取1/2,1/4,1/8的方法,也可以从exif中来读取缩略图,但这个缩略图一般很小。

    说到exif,不得不说一款用perl实现的命令行工具:exiftool。几乎所有的多媒体文件(图像、音乐、视频)都可以用这个工具来查看其有关信息,当然如果不是jpeg文件就是指广义上的"exif"。在git中有已经编译好可执行文件exiftool.exe。使用方法是将这个文件放到系统路径下,然后在想查看的文件路径下执行 exiftool filename

    在实现BatchJpeg工具时如果仅仅用上面实现的LBitmap来读取,保存, 将会失去exif信息, 而相片的拍摄时间等信息又很重要, 所以还得用另一个库exiv2来读取写入exif。如果用c#, 用上面的代码exif信息会自动保留下来。默默地向c#致敬。

    intelJpeg库

    如果在win32环境下对jpeg IO速度有很高的要求,可以使用interlJpeg库,不开源,但提供有*.h,*.lib文件。这个库可以大大提高jpg读取、保存速度。

    当时分别用c#和c实现了jpeg批量转化工具, 在处理大量图片时发现c#用时居然只有c的一半。太奇怪了,按理说,c的速度比c#应该快才对啊, 而实事是c慢了这么多。 最后发现问题就在libjpeg上,用了intetJpeg后速度就和c#差不多了(猜想.NET内部也是用intelJpeg来处理jpeg)。

  • 相关阅读:
    Android 使用EventBus进行Fragment和Activity通信
    Android 实现对多个EditText的监听
    Retrofit2.0动态url遇到的坑
    Android 轻松实现语音朗读
    Android 7.0 因为file://引起的FileUriExposedException异常
    Android拍照得到全尺寸图片并进行压缩/拍照或者图库选择 压缩后 图片 上传
    Toolbar自定义布局
    [致歉]2:05-6:35部分站点出现故障,给您带来麻烦,请谅解团队
    上周热点回顾(8.11-8.17)团队
    [网站公告]8月17日14:00-15:00(周日下午)发布新版站内短消息团队
  • 原文地址:https://www.cnblogs.com/mamamia/p/8583482.html
Copyright © 2011-2022 走看看