2012-04-06 57 views
1

我正在從一個1bpp索引圖像剪切並粘貼到新圖像。Lockbits跨越1bpp索引圖像字節邊界

所有的效果都很好,直到起始像素是8的除數。在下面的代碼中,stride等於相對於矩形寬度的值,直到達到字節邊界。然後步幅等於整個頁面的寬度。

var croppedRect = new Rectangle((int)left, (int)top, (int)width, (int)height); 
BitmapData croppedSource = _bitmapImage.LockBits(croppedRect, ImageLockMode.ReadWrite, BitmapImage.PixelFormat); 
int stride = croppedSource.Stride; 

這是一個問題,因爲不是我的選擇區域粘貼到新的圖像,元帥副本的橫截面,選定區域的高度,頁面的整個寬度的。

int numBytes = stride * (int)height; 
var srcData = new byte[numBytes]; 

Marshal.Copy(croppedSource.Scan0, srcData, 0, numBytes); 
Marshal.Copy(srcData, 0, croppedDest.Scan0, numBytes); 
destBmp.UnlockBits(croppedDest); 
+0

爲什麼這是一個問題? GDI +使用* croppedRect *來優化像素內存映射。有時候可以。只需使用返回的步幅來索引位圖中的掃描線。 – 2012-04-06 15:14:40

+0

漢斯,看我的編輯。 – strattonn 2012-04-06 16:19:22

+1

是的,那是行不通的。它不像裁剪區域。您一次只能複製不超過* width *位,因此您需要一個循環來索引掃描線。由於您正在訪問* croppedRect *以外的字節,因此您的原始代碼也會拋出AccessViolation的可能性很高。如果左和/或左+寬度不是8的倍數,則需要特別處理一行的第一個和最後一個字節。 – 2012-04-06 16:23:45

回答

4

這是我的代碼,任何有興趣的人。可能有一個更優化的解決方案,但這是有效的。我用白色創建整個頁面,並在新頁面中複製所選區域時將其覆蓋。感謝Bob Powell的SetIndexedPixel例程。

protected int GetIndexedPixel(int x, int y, BitmapData bmd) 
{ 
    var index = y * bmd.Stride + (x >> 3); 
    var p = Marshal.ReadByte(bmd.Scan0, index); 
    var mask = (byte)(0x80 >> (x & 0x7)); 
    return p &= mask; 
} 

protected void SetIndexedPixel(int x, int y, BitmapData bmd, bool pixel) 
{ 
    int index = y * bmd.Stride + (x >> 3); 
    byte p = Marshal.ReadByte(bmd.Scan0, index); 
    byte mask = (byte)(0x80 >> (x & 0x7)); 
    if (pixel) 
     p &= (byte)(mask^0xff); 
    else 
     p |= mask; 
    Marshal.WriteByte(bmd.Scan0, index, p); 
} 

public DocAppImage CutToNew(int left, int top, int width, int height, int pageWidth, int pageHeight) 
{ 
    var destBmp = new Bitmap(pageWidth, pageHeight, BitmapImage.PixelFormat); 
    var pageRect = new Rectangle(0, 0, pageWidth, pageHeight); 

    var pageData = destBmp.LockBits(pageRect, ImageLockMode.WriteOnly, BitmapImage.PixelFormat); 
    var croppedRect = new Rectangle(left, top, width, height); 
    var croppedSource = BitmapImage.LockBits(croppedRect, ImageLockMode.ReadWrite, BitmapImage.PixelFormat); 

    for (var y = 0; y < pageHeight; y++) 
     for (var x = 0; x < pageWidth; x++) 
     { 
      if (y >= top && y <= top + height && x >= left && x <= width + left) 
      { 
       SetIndexedPixel(x, y, pageData, 
           GetIndexedPixel(x - left, y - top, croppedSource) == 0 ? true : false); 
       SetIndexedPixel(x - left, y - top, croppedSource, false); //Blank area in original 
      } 
      else 
       SetIndexedPixel(x, y, pageData, false); //Fill the remainder of the page with white. 
     } 

    destBmp.UnlockBits(pageData); 

    var retVal = new DocAppImage { BitmapImage = destBmp }; 
    destBmp.Dispose(); 

    BitmapImage.UnlockBits(croppedSource); 
    SaveBitmapToFileImage(BitmapImage); 

    return retVal; 
}