2013-08-07 186 views
1

首先,我很抱歉如果這是重複的;但我的Google-fu似乎在今天讓我失望。將兩個字節合併爲一個

我正在爲Photoshop編寫一個圖像格式模塊,並且此格式的保存選項之一包含一個4位Alpha通道。當然,我必須轉換的數據是8位/ 1字節的阿爾法 - 所以我需要基本上採用阿爾法的每兩個字節,併合併成一個。

我嘗試(見下文),相信具有改進很大的空間:

,其分別包含8位alpha數據和4位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是矢量。我意識到將兩個字節減少到一個值必然會導致「分辨率」的損失,但我不禁想到有更好的方法來做到這一點。

對於額外的信息,下面的做相反的迴路(從格式轉換4位alpha到8位的Photoshop)

alphaData服務於相同的目的的上方,並且imgData是一個無符號的字符向量保存原始圖像數據。 (alpha的數據格式的這個變體的圖像的實際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; 
} 
+0

+1僅用於Google-Fu文字遊戲。 – WhozCraig

回答

1

你確定它的

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; 
} 
+0

起初我以爲它會是* 16,除此之外,我測試的第一個圖像最終是半透明的。回想起來,我注意到15(半字節的最高值)* 16 = 240,而不是255. 無論如何,我似乎有一種忽略明顯的習慣。謝謝,它效果很好! –

+0

我認爲你應該用四捨五入的方法做分割,即'(alphaData [x] + 8)/ 17'。 – starblue

0
short ashort=(alphaData[x] << 8)+alphaData[x+1]; 
    alphaFinal[w]=(unsigned char)ashort; 

你實際上是在alphaFinal [X]失去alphaData。您將alphaData [x]向左移8位,然後分配8位低位。

另外你的for循環是不安全的,如果由於某種原因alphaData.size()很奇怪,你會跑出範圍。

+0

是的,我知道。這是不好的做法 - 但這是我做一個「草稿」的奇怪方式。但是感謝關於第一部分的解釋 - 它肯定有助於解釋我得到的結果。 –

0

你想要做什麼,我認爲是將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位中丟失。但是,如果在完全合成的作品中注意到這一點,你會感到驚訝。

0

此代碼

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」。