关于png文件的编辑疑问(质量问题)

发布网友 发布时间:2022-04-24 00:58

我来回答

1个回答

热心网友 时间:2023-10-16 17:50

1。PNG是LZ77无损压缩派生的一种位图格式。
2。编辑多次看你做的是什么样的编辑,有的时候是会改变的。
3。多次编辑转换,原图肉眼看不见或者不察觉,但是是有改变的。
4。压缩原理很复杂。我告诉你,你愿意看吗?
1.1 索引图与 RGB 图 对于 PNG 图像,可以分为索引(Index)图和 RGB 图两种,索引图只包含固定数量的颜 色,而 RGB 图的颜色数量是不受*的. RGB 图的每一个象素都保存一个 RGB 值,代表这个象素的颜色,因此,一张 RGB 图有多 少个象素,文件中就保存多少个 RGB 值. 而索引图会将其固定数量的颜色,按照顺序排列起来,作为颜色的索引保存在文件头中,被 称为调色板(palette).每一个象素只保存其颜色在调色板中的索引. 如一个 32 色的索引图,在文件头中保存了 32 个颜色,索引值从 0 到 31.图中每一个象 素只记录其颜色的索引. 因此,对于一般的 PNG 图,索引图文件的大小总是小于 RGB 图的.
1.2 行程压缩原理 当我们把一张索引图的所有象素(N 个) ,按照从上到下,从左至右,即按行扫描的顺序排 列起来的时候,我们得到一个队列.如果我们用 1 个字节来存储一个象素 的索引值(调色板颜色不超过 256) ,那么数据的大小为 N 字节.这段数据的格式我们表示 为 [I1][I2]…[In] 共 N 个. 在上面的队列中,可能会出现很多连续相同的索引值,最多的就是透明色.如果我们在每个 索引值前用 1 个字节保存这个值连续出现的数量(最多可以表示 256 个 ) ,那数据的格式变为 [C1][I1][C2][I2]…[Cm][Im] 共 M 个.那么一张 256 个象素的 单色图的所有数据,只需要 2 个字节来保存.通常,我们所需的图中总 是有大片连续的颜色,包括透明色,因此按照这个格式保存的图像,其文件大小可以大大降 低,这就是行程的压缩原理.
1.3 USI 压缩原理 如果一张索引图的颜色数为 32,那么在[C1][I1][C2][I2]…[Cm][Im] 格式中,I 的数值 都小于 32,那么每个字节前 3 bits 始终为 0.为了充分利用这 3 bits,我们可以将 C 的值保存在这 3bits 中,这样我们的格式变为 [G1][G2]….[Gk] 共 K 个(G 的高位为数量,低位为颜色索引) .这样,对于 32 色的图, 每个字节最多可以保存 8 个象素的信息, 对于 色的图, 每个字节最多可以保存 4 个象素 的信息,对于 16 色的图,每个字节最多可以保存 16 个象素的信息. 在 [G1][G2]….[Gk] 这 K 个字节前,再加上调色板数据和其它本图的必要信息,就得到 了 USI 格式的文件.
conan(29842977) 15:03:01 1.1 载入文件
private void load(String file) {
try {
DataInputStream din = new
DataInputStream(getClass().getResourceAsStream(file));
m_flags = din.readInt();
//格式标志
/** 读取调色板信息 */
m_count = din.readByte() & 0xff; //调色板位数
m_mask = 0xff >> (8 - m_count); //计算 取色板索引的掩码
int pal_count = din.readByte() & 0xff; //调色板数量
int pal_len = din.readByte() & 0xff; //调色板长度 即颜色数
m_pal = new int[pal_count][pal_len]; //初始化调色板容器
int pal; //读取调色板信息
for (int i = 0; i < pal_count; i++) { for (int j = 0; j < pal_len; j++) { pal = din.readShort() & 0xffff; m_pal[i][j] = ( ( ( ( (pal & 0xF000) >>> 12) * (17 << 24)) & 0xFF000000) | ( ( ( (pal & 0x0F00) >>> 8) * (17 << 16)) & 0x00FF0000) | ( ( ( (pal & 0x00F0) >>> 4) * (17 << 8)) & 0x0000FF00) | ( ( ( (pal & 0x000F) * 17))) ); } } /** 读取图块信息 */ m_modelCount = din.readShort() & 0xffff; //图块数量 //读取图块尺寸 if ( (m_flags & FLAG_REBUILD_SIZE) != 0) { //基于尺寸的转换方式 m_rebuildWidth = din.readByte() & 0xff; m_rebuildHeight = din.readByte() & 0xff; } else if ( (m_flags & FLAG_REBUILD_MODULE) != 0) { //基于动画 model 的转换方式 m_models = new byte[m_modelCount * 2]; din.read(m_models); } /** 读取像素数据 */ m_dataSize = din.readInt(); //像素数据大小(压缩数据) m_data = new byte[m_dataSize]; din.read(m_data); //读取像素数据(压缩数据) //读取每个图块数据的起始偏移量 int offset = 0; m_dataOffset = new int[m_modelCount]; for (int i = 0; i < m_modelCount; i++) { m_dataOffset[i] = offset; if ( (m_flags & FLAG_16BIT_4_LEN) != 0) { offset += din.readShort(); } else { offset += din.readByte() & 0xff; } } } catch (Exception ex) {} } 1.2 解压缩 /****************************************** * 解压缩指定图块像素数据 * @param model_id int 图块号 * @param pal_id int 调色板号 * @return int[] 解压缩图块像素数据(ARPG 值) ******************************************/ private int[] BuildRle8bFrm(int model_id, int pal_id) { //计算解压后,像素数据的大小(图块 W*图块 H) int size; if ( (m_flags & FLAG_REBUILD_SIZE) != 0) { size = m_rebuildWidth * m_rebuildHeight; } else { size = (m_models[model_id * 2] & 0xff) * (m_models[model_id * 2 + 1] & 0xff); } //初始化像素 buf int[] m_bufB = new int[size]; int pal[] = m_pal[pal_id]; //获取当前调色板 int offset = m_dataOffset[model_id]; //获取压缩数据起点 //解压缩 int count, index, pos = 0; while (pos < size) { count = ( (m_data[offset] & 0xFF) >> m_count) + 1; index = pal[m_data[offset] & m_mask]; offset++; while (--count >= 0) { m_bufB[pos++] = index; } } return m_bufB; } /********************************** * 获取指定图块 Image * @param model_id int 图块号 * @param pal_id int 调色板号 * @return Image 图块 Image 对象 **********************************/ public Image GetImage(int model_id, int pal_id) { //获得指定图块解压数据(ARPG 颜色数据) int[] m_bufB = BuildRle8bFrm(model_id, pal_id); //计算图块尺寸 int w, h; if ( (m_flags & FLAG_REBUILD_SIZE) != 0) { w = m_rebuildWidth; h = m_rebuildHeight; } else { w = m_models[model_id * 2] & 0xff; h = m_models[model_id * 2 + 1] & 0xff; } //生成 Image 图片 Image m_image = Image.createRGBImage(m_bufB, w, h, true); m_bufB = null; return m_image; }

热心网友 时间:2023-10-16 17:50

1。PNG是LZ77无损压缩派生的一种位图格式。
2。编辑多次看你做的是什么样的编辑,有的时候是会改变的。
3。多次编辑转换,原图肉眼看不见或者不察觉,但是是有改变的。
4。压缩原理很复杂。我告诉你,你愿意看吗?
1.1 索引图与 RGB 图 对于 PNG 图像,可以分为索引(Index)图和 RGB 图两种,索引图只包含固定数量的颜 色,而 RGB 图的颜色数量是不受*的. RGB 图的每一个象素都保存一个 RGB 值,代表这个象素的颜色,因此,一张 RGB 图有多 少个象素,文件中就保存多少个 RGB 值. 而索引图会将其固定数量的颜色,按照顺序排列起来,作为颜色的索引保存在文件头中,被 称为调色板(palette).每一个象素只保存其颜色在调色板中的索引. 如一个 32 色的索引图,在文件头中保存了 32 个颜色,索引值从 0 到 31.图中每一个象 素只记录其颜色的索引. 因此,对于一般的 PNG 图,索引图文件的大小总是小于 RGB 图的.
1.2 行程压缩原理 当我们把一张索引图的所有象素(N 个) ,按照从上到下,从左至右,即按行扫描的顺序排 列起来的时候,我们得到一个队列.如果我们用 1 个字节来存储一个象素 的索引值(调色板颜色不超过 256) ,那么数据的大小为 N 字节.这段数据的格式我们表示 为 [I1][I2]…[In] 共 N 个. 在上面的队列中,可能会出现很多连续相同的索引值,最多的就是透明色.如果我们在每个 索引值前用 1 个字节保存这个值连续出现的数量(最多可以表示 256 个 ) ,那数据的格式变为 [C1][I1][C2][I2]…[Cm][Im] 共 M 个.那么一张 256 个象素的 单色图的所有数据,只需要 2 个字节来保存.通常,我们所需的图中总 是有大片连续的颜色,包括透明色,因此按照这个格式保存的图像,其文件大小可以大大降 低,这就是行程的压缩原理.
1.3 USI 压缩原理 如果一张索引图的颜色数为 32,那么在[C1][I1][C2][I2]…[Cm][Im] 格式中,I 的数值 都小于 32,那么每个字节前 3 bits 始终为 0.为了充分利用这 3 bits,我们可以将 C 的值保存在这 3bits 中,这样我们的格式变为 [G1][G2]….[Gk] 共 K 个(G 的高位为数量,低位为颜色索引) .这样,对于 32 色的图, 每个字节最多可以保存 8 个象素的信息, 对于 色的图, 每个字节最多可以保存 4 个象素 的信息,对于 16 色的图,每个字节最多可以保存 16 个象素的信息. 在 [G1][G2]….[Gk] 这 K 个字节前,再加上调色板数据和其它本图的必要信息,就得到 了 USI 格式的文件.
conan(29842977) 15:03:01 1.1 载入文件
private void load(String file) {
try {
DataInputStream din = new
DataInputStream(getClass().getResourceAsStream(file));
m_flags = din.readInt();
//格式标志
/** 读取调色板信息 */
m_count = din.readByte() & 0xff; //调色板位数
m_mask = 0xff >> (8 - m_count); //计算 取色板索引的掩码
int pal_count = din.readByte() & 0xff; //调色板数量
int pal_len = din.readByte() & 0xff; //调色板长度 即颜色数
m_pal = new int[pal_count][pal_len]; //初始化调色板容器
int pal; //读取调色板信息
for (int i = 0; i < pal_count; i++) { for (int j = 0; j < pal_len; j++) { pal = din.readShort() & 0xffff; m_pal[i][j] = ( ( ( ( (pal & 0xF000) >>> 12) * (17 << 24)) & 0xFF000000) | ( ( ( (pal & 0x0F00) >>> 8) * (17 << 16)) & 0x00FF0000) | ( ( ( (pal & 0x00F0) >>> 4) * (17 << 8)) & 0x0000FF00) | ( ( ( (pal & 0x000F) * 17))) ); } } /** 读取图块信息 */ m_modelCount = din.readShort() & 0xffff; //图块数量 //读取图块尺寸 if ( (m_flags & FLAG_REBUILD_SIZE) != 0) { //基于尺寸的转换方式 m_rebuildWidth = din.readByte() & 0xff; m_rebuildHeight = din.readByte() & 0xff; } else if ( (m_flags & FLAG_REBUILD_MODULE) != 0) { //基于动画 model 的转换方式 m_models = new byte[m_modelCount * 2]; din.read(m_models); } /** 读取像素数据 */ m_dataSize = din.readInt(); //像素数据大小(压缩数据) m_data = new byte[m_dataSize]; din.read(m_data); //读取像素数据(压缩数据) //读取每个图块数据的起始偏移量 int offset = 0; m_dataOffset = new int[m_modelCount]; for (int i = 0; i < m_modelCount; i++) { m_dataOffset[i] = offset; if ( (m_flags & FLAG_16BIT_4_LEN) != 0) { offset += din.readShort(); } else { offset += din.readByte() & 0xff; } } } catch (Exception ex) {} } 1.2 解压缩 /****************************************** * 解压缩指定图块像素数据 * @param model_id int 图块号 * @param pal_id int 调色板号 * @return int[] 解压缩图块像素数据(ARPG 值) ******************************************/ private int[] BuildRle8bFrm(int model_id, int pal_id) { //计算解压后,像素数据的大小(图块 W*图块 H) int size; if ( (m_flags & FLAG_REBUILD_SIZE) != 0) { size = m_rebuildWidth * m_rebuildHeight; } else { size = (m_models[model_id * 2] & 0xff) * (m_models[model_id * 2 + 1] & 0xff); } //初始化像素 buf int[] m_bufB = new int[size]; int pal[] = m_pal[pal_id]; //获取当前调色板 int offset = m_dataOffset[model_id]; //获取压缩数据起点 //解压缩 int count, index, pos = 0; while (pos < size) { count = ( (m_data[offset] & 0xFF) >> m_count) + 1; index = pal[m_data[offset] & m_mask]; offset++; while (--count >= 0) { m_bufB[pos++] = index; } } return m_bufB; } /********************************** * 获取指定图块 Image * @param model_id int 图块号 * @param pal_id int 调色板号 * @return Image 图块 Image 对象 **********************************/ public Image GetImage(int model_id, int pal_id) { //获得指定图块解压数据(ARPG 颜色数据) int[] m_bufB = BuildRle8bFrm(model_id, pal_id); //计算图块尺寸 int w, h; if ( (m_flags & FLAG_REBUILD_SIZE) != 0) { w = m_rebuildWidth; h = m_rebuildHeight; } else { w = m_models[model_id * 2] & 0xff; h = m_models[model_id * 2 + 1] & 0xff; } //生成 Image 图片 Image m_image = Image.createRGBImage(m_bufB, w, h, true); m_bufB = null; return m_image; }

声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com