两个字节合一
Two bytes into one
首先,如果这是重复的,我深表歉意;但我的谷歌功夫今天似乎让我失望了。
我正在为Photoshop编写一个图像格式模块,该格式的一个保存选项包括一个4位alpha通道。当然,我必须转换的数据是8位/1字节的alpha,所以我基本上需要取每两个字节的alpha,并将其合并为一个。
我的尝试(如下),我相信还有很大的改进空间:
for(int x=0,w=0;x < alphaData.size();x+=2,w++)
{
short ashort=(alphaData[x] << 8)+alphaData[x+1];
alphaFinal[w]=(unsigned char)ashort;
}
alphaData和alphaFinal是分别包含8位阿尔法数据和4位阿尔法数据的矢量。我意识到,将两个字节减少为一的值,势必会导致"分辨率"的损失,但我忍不住认为有更好的方法可以做到这一点。
为了获得更多信息,这里有一个反向循环(将Photoshop格式的4位alpha转换为8位)
alphaData的作用与上述相同,imgData是一个无符号的char向量,用于保存原始图像数据。(阿尔法数据被附加在该格式的特定变体中的图像的实际rgb数据之后)
for(int b=alphaOffset,x2=0;b < (alphaOffset+dataLength); b++,x2+=2)
{
unsigned char lo = (imgData[b] & 15);
unsigned char hi = ((imgData[b] >> 4) & 15);
alphaData[x2]=lo*17;
alphaData[x2+1]=hi*17;
}
你确定它是吗
alphaData[x2]=lo*17;
alphaData[x2+1]=hi*17;
而不是
alphaData[x2]=lo*16;
alphaData[x2+1]=hi*16;
在任何情况下,要生成与您发布的解码函数一起工作的值,您只需要反转操作即可。因此,乘以17就变成了除以17,移位和掩码被重新排序为这样:
for(int x=0,w=0;x < alphaData.size();x+=2,w++)
{
unsigned char alpha1 = alphaData[x] / 17;
unsigned char alpha2 = alphaData[x+1] / 17;
Assert(alpha1 < 16 && alpha2 < 16);
alphaFinal[w]=(alpha2 << 4) | alpha1;
}
short ashort=(alphaData[x] << 8)+alphaData[x+1];
alphaFinal[w]=(unsigned char)ashort;
实际上,您在alphaFinal中丢失了alphaData[x]。将alphaData[x]向左移位8位,然后分配8个低位。
此外,for循环是不安全的,如果由于某种原因alphaData.size()是奇数,则会超出范围。
我认为,您想要做的是将8位值截断为4位值;而不是组合两个8位值。换句话说,您希望删除每个alpha值的四个最低有效位,而不是组合两个不同的alpha值。所以,基本上,你想右移4。
output = (input >> 4); /* truncate four bits */
如果你不熟悉二进制移位,可以用这个随机的8位数字:
10110110
>> 1
= 01011011
>> 1
= 00101101
>> 1
= 00010110
>> 1
= 00001011
所以,
10110110
>> 4
= 00001011
而要倒车,请改为左移。。。
input = (output << 4); /* expand four bits */
使用与以前相同的随机8位数字的结果,它将是
00001011
>> 4
= 10110000
很明显,正如您所指出的,丢失了4位精度。但你会感到惊讶的是,在一部完全合成的作品中,它很少被注意到。
此代码为
for(int x=0,w=0;x < alphaData.size();x+=2,w++)
{
short ashort=(alphaData[x] << 8)+alphaData[x+1];
alphaFinal[w]=(unsigned char)ashort;
}
坏了。给定
#include <iostream>
using std::cout;
using std::endl;
typedef unsigned char uchar;
int main() {
uchar x0 = 1; // for alphaData[x]
uchar x1 = 2; // for alphaData[x+1]
short ashort = (x0 << 8) + x1; // The value 0x0102
uchar afinal = (uchar)ashort; // truncates to 0x02.
cout << std::hex
<< "x0 = 0x" << x0 << " << 8 = 0x" << (x0 << 8) << endl
<< "x1 = 0x" << x1 << endl
<< "ashort = 0x" << ashort << endl
<< "afinal = 0x" << (unsigned int)afinal << endl
;
}
如果你说你的源流包含存储在8位存储值中的4位对序列,你需要将其重新存储为单个8位值,那么你想要的是:
for(int x=0,w=0;x < alphaData.size();x+=2,w++)
{
unsigned char aleft = alphaData[x] & 0x0f; // 4 bits.
unsigned char aright = alphaData[x + 1] & 0x0f; // 4 bits.
alphaFinal[w] = (aleft << 4) | (aright);
}
"<<4"相当于"*16",而">>4"则相当于"/16"。
- 从不同线程使用int64的不同字节安全吗
- 将Integer转换为4字节的unsined字符矢量(按大端字节顺序)
- 在UNIX系统中使用DIR查找文件的字节大小
- 如何使用Crypto++并为RSA返回可打印的字节/字符数组
- std::当在256字节边界上写入整数时,流的奇怪行为
- 当比特(而不是字节)的顺序至关重要时的持久性
- 从文件中读取多个字节,并将它们存储在C++中进行比较
- 如何在文件中查找字节序列
- luaL_dofile在已知良好的字节码上失败,可以使用未编译的版本
- 字节到位运算符重载C++
- 在java中读取c++字节的位字段
- 使用 std::vector::reverse_iterator 将 int 序列化为字节向量?
- 字节真的是最小可寻址单元吗
- struct.error:解压缩 C++ 结构时,解包需要 288 字节的缓冲区
- 读取文件中所有可能的十六进制 16 字节序列并打印每个序列
- 如何使用 OpenCV 解码在两个 UWP 应用之间发送的图像字节?
- 如何将字节数组元素替换为修改的十六进制 ASCII 符号?
- asn1c 不会从 asn.1 模块中提取八位字节字符串的默认值
- 如何将原始字节附加到 std::vector?
- 两个字节合一