想要向
png
隐写数据,需求来源于想将图片上传于
csdn
并获得
url
,实现将印象笔记中的
.enex
文件格式中的图片url替换成csdn提供的链接。
PNG文件格式解析
* 利用文件类型判断文件头
一、PNG描述
百度百科
体积小
网络通讯中因受带宽制约,在保证图片清晰、逼真的前提下,网页中不可能大范围的使用文件较大的bmp格式文件。无损压缩
PNG文件采用LZ77算法的派生算法进行压缩,其结果是获得高的压缩比,不损失数据。它利用特殊的编码方法标记重复出现的数据,因而对图像的颜色没有影响,也不可能产生颜色的损失,这样就可以重复保存而不降低图像质量。索引彩色模式
PNG-8格式与GIF图像类似,同样采用8位调色板将RGB彩色图像转换为索引彩色图像。图像中保存的不再是各个像素的彩色信息,而是从图像中挑选出来的具有代表性的颜色编号,每一编号对应一种颜色,图像的数据量也因此减少,这对彩色图像的传播非常有利。更优化的网络传输显示
PNG图像在浏览器上采用流式浏览,即使经过交错处理的图像会在完全下载之前提供浏览者一个基本的图像内容,然后再逐渐清晰起来。它允许连续读出和写入图像数据,这个特性很适合于在通信过程中显示和生成图像。支持透明效果
PNG可以为原图像定义256个透明层次,使得彩色图像的边缘能与任何背景平滑地融合,从而彻底地消除锯齿边缘。这种功能是GIF和JPEG没有的。
1.1 格式
详细的各种辅助块的介绍见PNG文件格式解析
1.2 rgba
色相环(rgb之和加起来是255所形成的一个圆,比如R到G的线就是:B=255,R+G=255)
每一个像素由三原色和明暗表示:Red
(红色)Green
(绿色)Blue
(蓝色)和Alpha
(亮度)。
所以rgba就是这个4个byte
组成,每个byte有255个值。
所以用8个16进制表示比如#7FFF0000
二、隐写数据
上面介绍的chunk中我们可以使用
tEXt
加信息
png decoder
png_encoder
2.1 写入数据&解析 text chunk
三个类
PNG
封装png格式信息ImageInfo
图片的信息:id=UUID,name=图片名称,path=图片路径transformer类
有两个核心方法1 .
transorm(srcDir,targetDir)
,接受srcDir下所有png图片,写入targetDir中。写入的过程中,插入tExt
chunk—ImageInfo
的key和value。
具体为" imageInfo uuid_name "
praseInfoFrom(String srcDir)
,解析tExtCunk,被还原成ImageInfo
png图片格式
package com.pngimage;
import java.util.UUID;
/**
* <code>ImageInfo</code> description
*
* @author sunqiyuan
* @date 2020-06-05
*/
public class ImageInfo {
private String id;
private String name;
private String path;
public ImageInfo(String name, String path) {
this.id = UUID.randomUUID().toString().replace("-", "");
this.name = name;
this.path = path;
}
public ImageInfo(String id, String name, String path) {
this.id = id;
this.name = name;
this.path = path;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
@Override
public String toString() {
return "ImageInfo{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", path='" + path + '\'' +
'}';
}
}
package com.pngimage;
import java.io.IOException;
import java.util.zip.CRC32;
import sun.security.krb5.internal.crypto.crc32;
/**
* <code>PNG</code> PNG模型信息
*
* @author sunqiyuan
* @date 2020-06-05
*/
public class PNG {
final byte[] identifier = {
-119, 80, 78, 71, 13, 10, 26, 10};
private static final int bKGDChunk = 0x624B4744;
private static final int cHRMChunk = 0x6348524D;
private static final int gAMAChunk = 0x67414D41;
private static final int hISTChunk = 0x68495354;
private static final int IDATChunk = 0x49444154;
public static final int IENDChunk = 0x49454E44;
private static final int IHDRChunk = 0x49484452;
private static final int PLTEChunk = 0x504C5445;
private static final int pHYsChunk = 0x70485973;
private static final int sBITChunk = 0x73424954;
public static final int tEXtChunk = 0x74455874;
private static final int tIMEChunk = 0x74494D45;
private static final int tRNSChunk = 0x74524E53;
private static final int zTXtChunk = 0x7A545874;
public int pos;
/**
* png的chunk格式
*/
public static class Chunk {
/**
* 总长度
* 4 个字节
*/
int length;
/**
* 4 个字节 标识chunk类型
*/
int type;
/**
* 可变长度, chunk块格式长度,属于每个chunk的长度
*/
byte[] chunkData;
/**
* 4个字节的冗余校验码
*/
int crc;
public Chunk(int length, int type, byte[] chunkData, int pos) {
this.length = length;
this.type = type;
this.chunkData = chunkData;
this.crc = readInt(chunkData, pos + length - 4);
}
public Chunk(byte[] chunk, int pos) {
this.length = readInt(chunk, pos);
this.type = readInt(chunk, pos + 4);
}
public Chunk() {
}
}
/**
* IHDR_Chunk
*/
class IHDR_Chunk extends Chunk {
int width = 0;
int height = 0;
int bitdepth