前段时间在做PNG的解析问题,对于PNG格式基于字节的读写有了一定了解,此文记录如何解析PNG图片的数据字段,也就是真实像素的二进制解析,PNG的data数据基本数据块的组成为 :Filter +  压缩数据。(这里除去校验头尾),二进制读取自己写即可,文件头的解析等,本文也不记录,可以参看https://www.w3.org/TR/PNG/#9Filter或者参考这里中文解释https://www.jianshu.com/p/ecacf2f60cb2,这里面有一些介绍,原理已经讲的很明白了,但是没有代码的干货,这里补充一下,下面的算法是假设我们已经将压缩的数据使用zlip压缩解压了,但是需要根据Filter 类型去还原像素值,算法如下:

     /*-------------|C | B | D |------------|A | x |   |------------Type Name    Filter Function Reconstruction Function0    None    Filt(x) = Orig(x)  Recon(x) = Filt(x)1    Sub Filt(x) = Orig(x) - Orig(a)    Recon(x) = Filt(x) + Recon(a)2    Up  Filt(x) = Orig(x) - Orig(b)    Recon(x) = Filt(x) + Recon(b)3    Average Filt(x) = Orig(x) - floor((Orig(a) + Orig(b)) / 2)    Recon(x) = Filt(x) + floor((Recon(a) + Recon(b)) / 2)4   Paeth   Filt(x) = Orig(x) - PaethPredictor(Orig(a), Orig(b), Orig(c))  Recon(x) = Filt(x) + PaethPredictor(Recon(a), Recon(b), Recon(c))x    the byte being filtered;a   the byte corresponding to x in the pixel immediately before the pixel containing x(or the byte immediately before x, when the bit depth is less than 8);b   the byte corresponding to x in the previous scanline;c  the byte corresponding to b in the pixel immediately before the pixel containing b(or the byte immediately before b, when the bit depth is less than 8).*/enum FilterTypes{eFTNone =0,eFTSub = 1,eFTUp =2,eFTAverage = 3,eFTPaeth =4,};

void GsPNG::Filtering(FilterTypes etype, unsigned char * row, int length)
{if (m_Type != eRGBA8)//先实现常用的rgba,这里其实不用管通道顺序,只需要知道几个通道即可,return; m_CacheBefore.Allocate(length);switch (etype){//原值不处理case eFTNone:break;case eFTSub:{for (int i = 4; i < length; i += 4){row[i]  += row[i - 4];row[i + 1] += row[i - 3];row[i + 2] += row[i - 2];row[i + 3] += row[i - 1];}}break;case eFTUp: {for (int i = 0; i < length; i += 4){row[i] += m_CacheBefore.BufferHead()[i];row[i + 1] += m_CacheBefore.BufferHead()[i + 1];row[i + 2] += m_CacheBefore.BufferHead()[i + 2];row[i + 3] += m_CacheBefore.BufferHead()[i + 3];}}break;case eFTAverage:{row[0] += floor((m_CacheBefore.BufferHead()[0] + 0) / 2);row[1] += floor((m_CacheBefore.BufferHead()[1] + 0) / 2);row[2] += floor((m_CacheBefore.BufferHead()[2] + 0) / 2);row[3] += floor((m_CacheBefore.BufferHead()[3] + 0) / 2);for (int i = 4; i < length; i += 4){row[i] += floor((m_CacheBefore.BufferHead()[i]+ row[i - 4])/2);row[i + 1] += floor((m_CacheBefore.BufferHead()[i+1] + row[i - 3]) / 2);row[i + 2] += floor((m_CacheBefore.BufferHead()[i+2] + row[i - 2]) / 2);row[i + 3] += floor((m_CacheBefore.BufferHead()[i+3] + row[i - 1]) / 2);}}break;case eFTPaeth:{//从0开始,超出的像素用0 代替,这里在官网有一排小字介绍row[0] += PaethPredictor(0, m_CacheBefore.BufferHead()[0], 0);row[1] += PaethPredictor(0, m_CacheBefore.BufferHead()[1], 0);row[2] += PaethPredictor(0, m_CacheBefore.BufferHead()[2], 0);row[3] += PaethPredictor(0, m_CacheBefore.BufferHead()[3], 0);for (int i = 4; i < length; i += 4){row[i] += PaethPredictor(row[i - 4], m_CacheBefore.BufferHead()[i], m_CacheBefore.BufferHead()[i - 4]);row[i + 1] += PaethPredictor(row[i - 3], m_CacheBefore.BufferHead()[i+1], m_CacheBefore.BufferHead()[i - 3]);row[i + 2] += PaethPredictor(row[i - 2], m_CacheBefore.BufferHead()[i+2], m_CacheBefore.BufferHead()[i - 2]);row[i + 3] += PaethPredictor(row[i - 1], m_CacheBefore.BufferHead()[i+3], m_CacheBefore.BufferHead()[i - 1]);}}break;default:break;}//记录一下,下次取BC的值m_CacheBefore.Copy(row, length);
}

再次重申上面的代码是将已经zlip解压后的数据使用Filtering 过滤反算后得到真实的像素值的过程,正算一样的,这里就不做过多描述

PNG-的IDAT解析相关推荐

  1. 一文了解文件上传全过程(1.8w字深度解析)「前端进阶必备」

    作者:蓝色的秋风 转发链接:https://mp.weixin.qq.com/s/cruL9JGZNZQFrMSrzJJWiQ 前言 平常在写业务的时候常常会用的到的是 GET, POST请求去请求接 ...

  2. PNG图像文件格式解析

    一.实验要求 使用 FlexHEX 对 png 图片文件进行格式解析并分析 使用图片: 二.背景介绍 PNG是20世纪90年代中期开始开发的图像文件存储格式,是一种采用无损压缩算法的位图格式,其目的是 ...

  3. png格式解析+java代码生成png图片

    查看更多java体系文档 png文件格式解析 生成一个下图示例的png图片 png图片二进制格式解析 生成png图java代码 package mao.gui.dong.png; import jav ...

  4. golang通过RSA算法生成token,go从配置文件中注入密钥文件,go从文件中读取密钥文件,go RSA算法下token生成与解析;go java token共用

    RSA算法 token生成与解析 本文演示两种方式,一种是把密钥文件放在配置文件中,一种是把密钥文件本身放入项目或者容器中. 下面两种的区别在于私钥公钥的初始化, init方法,需要哪种取哪种. 通过 ...

  5. List元素互换,List元素转换下标,Java Collections.swap()方法实例解析

    Java Collections.swap()方法解析 jdk源码: public static void swap(List<?> list, int i, int j) {// ins ...

  6. 条形码?二维码?生成、解析都在这里!

    二维码生成与解析 一.生成二维码 二.解析二维码 三.生成一维码 四.全部的代码 五.pom依赖 直接上代码: 一.生成二维码 public class demo {private static fi ...

  7. Go 学习笔记(82)— Go 第三方库之 viper(解析配置文件、热更新配置文件)

    1. viper 特点 viper 是一个完整的 Go应用程序的配置解决方案,它被设计为在应用程序中工作,并能处理所有类型的配置需求和格式.支持特性功能如下: 设置默认值 读取 JSON.TOML.Y ...

  8. Go 学习笔记(77)— Go 第三方库之 cronexpr(解析 crontab 表达式,定时任务)

    cronexpr 支持的比 Linux 自身的 crontab 更详细,可以精确到秒级别. ​ 1. 实现方式 cronexpr 表达式从前到后的顺序如下所示: 字段类型 是否为必须字段 允许的值 允 ...

  9. mybatis配置文件解析

    mybatis配置文件解析 mybatis核心配置文件`mybatis-config.xml文件. mybatis的配置文件包含了会深深影响mybatis行为的设置和属性信息. 能配置的内容: con ...

  10. 谷歌BERT预训练源码解析(二):模型构建

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/weixin_39470744/arti ...

最新文章

  1. linespace 自动生成线性向量的API
  2. VSMFC程序显示命令行窗口
  3. 深度学习笔记之使用Faster-Rcnn进行目标检测 (实践篇)
  4. 快打开《来自艾泽拉斯的一封密码信》,破译网易重大机密
  5. FCN训练自己的数据集及测试
  6. eclipse自动补全
  7. Spring系列(九):Spring属性赋值注解@Value 用法介绍
  8. 第一节: Timer的定时任务的复习、Quartz.Net的入门使用、Aop思想的体现
  9. Java封装图书信息类
  10. 炫彩流行艺术海报,品味不止一点点
  11. 移远EC20基站定位
  12. Android主备域名切换实施方案(Ping工具Demo)
  13. 伺服速度控制模式接线图_伺服控制的三种模式,接线方式与参数设置的讲解
  14. javascript基础常识问答(二)
  15. DAO 中独特的通证经济
  16. 哈罗要在网约车市场取得突破,离开补贴行不通
  17. windows快速回到桌面快捷键
  18. 关于解决爬取拉勾全网遇到的302重定向问题的一些记录
  19. facade-门面设计模式
  20. 致我那终将逝去的青春——小二的原创经典

热门文章

  1. 谷歌搜索广告如何根据国家市场定点投放
  2. Zabbix安装配置详解
  3. 前台获取model中的值,json数据,json字符串,双引号变为 ‘ quto;‘
  4. 哪上班 | 好工作近在咫尺
  5. 【转】十分钟了结MySQL information_schema
  6. 《异度神剑2》与柏拉图的精神世界略考(上)
  7. 数字藏品NFT用的国内联盟链有哪些?
  8. 软件工程师日语词汇表
  9. liteon460w服务器电源管理系统,【LITEON PS-2112-5L 1200W C6100 C6220 C6220I服务器电源】价格_厂家 - 中国供应商...
  10. 湖南省第1届职业技能大赛(经历、总结)