纯C#实现JPEG解码器在超大图片切割中的应用

解码器+图片显示+瓦片切割+LeafLet展示完全方案

用C#实现JPEG解码器听起来也许怪怪的,因为比起C++或者芯片解码来说确实他的解码速度有点慢了。之所以用C#实现JPEG解码器是因为业务上需要对超大的分辨率(垂直或水平分辨率接近65535像素)的JPEG图片进行瓦片切割,并对切割图片做额外的处理,需要用到窗体编程索性就一起用C#实现了。开始找到一个工具,名字好像叫DeepZoom,处理常见分辨率的图片没问题,但是分辨率大了就卡死了,也不支持个性化处理。超大的图片不能一次性加载内存里处理,因为对于65535px×65535px这种极端的分辨率一次完整加载需要的内存就要达到65535×65535×3/1024/1024/1024=11.99963379185647G,即使1/4大小的图像也要接近3G的内存,伤不起啊!基于DeepZoom遇到的问题,遂决定采取分段解码的策略,也就是读取一定字节的JPEG文件到内存进行解码,然后继续这样的操作直到解码完成,下面详细谈谈这个过程。

先来回顾下JPEG标准里的顺序离散余弦编码图像解码的概要,JPEG图像编码的最小单元叫MCU,其实就是8×8的小块图片,JPEG的压缩算法就是压缩一个又一个MCU,顺序是从左到右,从上到下。压缩算法产出的数据是以位(Bit)存放的,所以一个字节内的8位就可能包含相邻像素里的数据,导致部分解码过程必须是瀑布式的走到底,也就是从文件解析数据位Bit只能在一个线程里,这样我们就无法用多线程来解析数据。从代码角度来讲,解析数据其实就是构造哈夫曼树,对哈夫曼树进行一次编码查询后获取到权重,然后查找权重表得到某个数据单元DU的数据位数N。程序目前运行到这里只能在一个线程运行, 因为从哪个字节哪个位取数据取决于前一步读取了多少位,所以多线程在这里使不上劲。 随后的流程大致是下面六个步骤:
1,读取N位后对数据做交直流信号处理;
2,反量化;
3,反Zig-zag编码;
4,反离散余弦变换;
5,YCrCb颜色空间转为RGB;
6,用RGB格式的MCU构建位图。
这六个步骤就不详细展开了,在我放出的源码里可以找到相关代码。前面说解码只能在一个线程里,但是这六个步骤可以单独放进一个线程,因为前一个MCU解码的六个步骤不会影响本次MCU解码的六个步骤。

学习完解码流程就可以考虑图片瓦片切割的问题了。假设我们有一张分辨率为25600×5000的jpg图片,一般瓦片的宽高为256像素的正方形图片,那么切割后的瓦片横向上有100个,垂直方向20个,其中水平方向上的最后一排瓦片大部分是空白图片。从解码过程我们知道,序列式离散余弦编码的JPEG图像是以8×8的MCU为最小编码单元,所以我们解码出来的图像是许多8×8像素的小块图像从左往右排列的。可以想象,水平方向一次完整解码出来的是25600×8分辨率的,而我们的瓦片是256×256的分辨率,我们要将这25600×8的图像切割成100份分别贴到水平方向的100个瓦片画布上。那么需要进行几次完整的水平方向的解码就能覆盖到一行完整的100个瓦片呢,显然是256/8=32次。重复上面的过程直到整个图像解码完毕,但这里有个问题,就是图像的高度可能不是瓦片高度的整数倍,所以最后一行瓦片图片的下面一部分是空白的,就需要用颜色或纹理图片去填充了。

第一次对大图的解码切割出来的瓦片组成的网格相当于地图的最高分辨率,为了能实现类似地图的缩放就要不同级别的缩小版。下一级的缩小瓦片在整体上相当与原始大图宽高的1/2面积则为1/4,具体到一个瓦片T的话,他的分辨率仍然是256×256,但是他的内容就等于4个上一级瓦片的内容,也就是将上一级水平方向相邻的两个瓦片AB和AB下面两个瓦片分别缩小1/4贴到瓦片T上对应的位置。下面每一级瓦片的生成方法重复上述过程,每一级都是在上一级的基础上缩小1/4。

下面的工具使用了JPEG解码器核心算法实现的图像查看和瓦片裁剪功能。

最后要说的就是,瓦片切割出来用什么组件来展示呢?我采用的方案是js地图组件-LeafLet。

  • 2
    点赞
  • 2
    收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:书香水墨 设计师:CSDN官方博客 返回首页
评论 1

打赏作者

hurst2011

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值