2014-10-09 215 views
0
// load pixels into an image 
     this.image = new BufferedImage(this.width, 
             this.height, 
             BufferedImage.TYPE_INT_RGB); 

     // get actual image data for easier pixel loading 
     byte[] iData = new byte[this.size - 54]; 
     for(int i = 0; i < this.size - 54; i++) { 
      iData[i] = this.data[i+54]; 
     } 

     // start from bottom row 
     for(int y = this.height-1; y >= 0; y--) { 
      for(int x = 0; x < this.width; x++) { 
       int index = (this.width*y + x) * 3; 
       int b = iData[index]; 
       int g = iData[index+1]; 
       int r = iData[index+2]; 

       //System.out.format("R: %s\nG: %s\nB: %s\n\n", r, g, b); 

       // merge rgb values to single int 
       int rgb = ((r&0x0ff)<<16)|((g&0x0ff)<<8)|(b&0x0ff); 

       // build image from bottom up 
       this.image.setRGB(x, this.height-1-y, rgb); 
      } 
     } 

我正在讀取位圖中的RGB值。我的iData字節數組是正確的,因爲我使用十六進制編輯器對其進行了檢查。但是,當我運行這個循環時,我的輸出圖像被扭曲(見圖片)。爲了解決這個問題,我一直在困擾我的大腦幾個小時,爲什麼會這樣呢?扭曲的位圖圖像

輸入圖像是加拿大國旗。

輸出圖像:

warped canada flag

+2

您的輸入文件是否有4字節對齊的行?有些格式將填充添加到每行的末尾,以使每行長度爲4個字節的倍數。 – immibis 2014-10-09 04:25:58

+0

是的,它的確如此!爲什麼? – Tetramputechture 2014-10-09 04:29:22

+1

因爲你可能沒有考慮到這一點。 – immibis 2014-10-09 04:30:09

回答

0

我不佔上的寬度的零字節填充,其中式是

WidthWithPadding =天花板((W *顏色質量彙總)/ 32)* 32。

0

圖像通常具有寬度,深度(每像素位數)和步幅。通常,步幅不僅僅是寬度*深度,而是填充了一定量(通常用於將每行對齊到16位邊界以用於內存訪問原因)。

您的代碼看起來並沒有考慮步幅或任何填充,這將解釋圖像中的偏移量。我很驚訝顏色沒有被切換(暗示填充與像素大小相同),但是那些未定義的值導致圖像中的黑色條紋。

爲了得到您的索引,您應該使用(this.stride*y + x) * 3,而不是乘以(this.width*y + x) * 3以獲得適合的步幅值。 BufferedImage class似乎沒有提供任何明顯的方式,所以你需要計算或獲取否則。

0

發生的一般問題是,您的代碼將寬度(行中的字節數)與stride(以字節爲單位的行之間的距離)混合在一起;在對齊的數據格式中,這些不一定是相同的東西。這樣做的一般結果就是出現了你所看到的歪斜,因爲第二行從第一行的最後一個字節開始,第三行從倒數第二個字節開始,第二排,等等。

您需要做的第一件事是計算數據的步幅,並將其用作該行的乘法因子。下面是一個簡化的循環,也就是一定程度上比在每個像素的基礎上相乘更有效:

int stride = (this.width + 3) & ~3; // rounds up to the nearest multiple of 4 
for (int y = 0; y < this.height; y++) { 
    int idx = y*stride; 
    for (int x = 0; x < this.width; x++) { 
     int b = iData[idx++]; 
     int g = iData[idx++]; 
     int a = iData[idx++]; 
     // etc. 
    } 
} 

注意,舍入特技上述((w + a - 1) & ~(a - 1))僅適用於冪的兩個值;舍入招的更一般的形式是:

int stride = (width + stride - 1)/stride*stride; 

雖然這是非常罕見的發現,是不是2擺在首位的功率比對。