Problem cropping an image. SOLVED
-
Sorry for so much code but I think you need to see all of it. The below code works for a 32 bpp image but using a 24 bpp image. The resulting 24 bpp image is skewed; it looks like by 1 pixel. The skewing starts at the top an skews to the right down the image. I've tried messing with indices and widths but can not get a clue as to what's happening. Am I missing something really simple? Public Sub CropImage() 'Source image in a PictureBox Dim _arRGBValues() As Byte Dim _BMPData As Imaging.BitmapData Dim _BMPPtr As IntPtr Dim bmSrc As Bitmap = Me.Image.Clone() Dim rect As New Rectangle(0, 0, bmSrc.Width, bmSrc.Height) _BMPData = bmSrc.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bmSrc.PixelFormat) _BMPPtr = _BMPData.Scan0 If bmSrc.PixelFormat = Imaging.PixelFormat.Format24bppRgb Then ' 24bpp Dim bytes As Integer = (bmSrc.Width * bmSrc.Height) * 3 ReDim _arRGBValues(bytes - 1) System.Runtime.InteropServices.Marshal.Copy(_BMPPtr, _arRGBValues, 0, _arRGBValues.Length) Else ' 32bpp Dim bytes As Integer = (bmSrc.Width * bmSrc.Height) * 4 ReDim _arRGBValues(bytes - 1) System.Runtime.InteropServices.Marshal.Copy(_BMPPtr, _arRGBValues, 0, _arRGBValues.Length) End If ' Destination image Dim arCropValues() As Byte Dim cropData As Imaging.BitmapData Dim cropPtr As IntPtr ' Size to src bm above - 1 pixel in width to allow for 1 pixel offset; height is the same. Dim bmCrop As Bitmap = New Bitmap(bmSrc.Width - 1, bmSrc.Height, bmSrc.PixelFormat) Dim cropRect As New Rectangle(0, 0, bmCrop.Width, bmCrop.Height) cropData = bmCrop.LockBits(cropRect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bmCrop.PixelFormat) cropPtr = cropData.Scan0 If bmCrop.PixelFormat = Imaging.PixelFormat.Format24bppRgb Then ' 24bpp Dim bytes As Integer = (bmCrop.Width * bmCrop.Height) * 3 ReDim arCropValues(bytes - 1) System.Runtime.InteropServices.Marshal.Copy(cropPtr, arCropValues, 0, arCropValues.Length) Else ' 32bpp Dim bytes As Integer = (bmCrop.Width * bmCrop.Height) * 4 ReDim arCropValues(bytes - 1) System.Runtime.InteropServices.Marshal.Copy(cropPtr, arCropValues, 0, arCropValues.Length) End If
-
Sorry for so much code but I think you need to see all of it. The below code works for a 32 bpp image but using a 24 bpp image. The resulting 24 bpp image is skewed; it looks like by 1 pixel. The skewing starts at the top an skews to the right down the image. I've tried messing with indices and widths but can not get a clue as to what's happening. Am I missing something really simple? Public Sub CropImage() 'Source image in a PictureBox Dim _arRGBValues() As Byte Dim _BMPData As Imaging.BitmapData Dim _BMPPtr As IntPtr Dim bmSrc As Bitmap = Me.Image.Clone() Dim rect As New Rectangle(0, 0, bmSrc.Width, bmSrc.Height) _BMPData = bmSrc.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bmSrc.PixelFormat) _BMPPtr = _BMPData.Scan0 If bmSrc.PixelFormat = Imaging.PixelFormat.Format24bppRgb Then ' 24bpp Dim bytes As Integer = (bmSrc.Width * bmSrc.Height) * 3 ReDim _arRGBValues(bytes - 1) System.Runtime.InteropServices.Marshal.Copy(_BMPPtr, _arRGBValues, 0, _arRGBValues.Length) Else ' 32bpp Dim bytes As Integer = (bmSrc.Width * bmSrc.Height) * 4 ReDim _arRGBValues(bytes - 1) System.Runtime.InteropServices.Marshal.Copy(_BMPPtr, _arRGBValues, 0, _arRGBValues.Length) End If ' Destination image Dim arCropValues() As Byte Dim cropData As Imaging.BitmapData Dim cropPtr As IntPtr ' Size to src bm above - 1 pixel in width to allow for 1 pixel offset; height is the same. Dim bmCrop As Bitmap = New Bitmap(bmSrc.Width - 1, bmSrc.Height, bmSrc.PixelFormat) Dim cropRect As New Rectangle(0, 0, bmCrop.Width, bmCrop.Height) cropData = bmCrop.LockBits(cropRect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bmCrop.PixelFormat) cropPtr = cropData.Scan0 If bmCrop.PixelFormat = Imaging.PixelFormat.Format24bppRgb Then ' 24bpp Dim bytes As Integer = (bmCrop.Width * bmCrop.Height) * 3 ReDim arCropValues(bytes - 1) System.Runtime.InteropServices.Marshal.Copy(cropPtr, arCropValues, 0, arCropValues.Length) Else ' 32bpp Dim bytes As Integer = (bmCrop.Width * bmCrop.Height) * 4 ReDim arCropValues(bytes - 1) System.Runtime.InteropServices.Marshal.Copy(cropPtr, arCropValues, 0, arCropValues.Length) End If
After further testing I have found this. It looks like the data return by LockBits() for the source image is not correct. Below is a portion of data I dumped for Scan0 returned from LockBits(). The test image is 38 x 38 pixels with a single pixel vertical line in column 0. It was generated in Paint and saved as .jpg. The Scan0 data shown below shows that the output is being shifted right which is what the resulting image shows. Is this some quirk with LockBits() and 24bbp? Also, I'm still on Windows 7. Thanks. Dim bmSrc As Bitmap = Me.Image.Clone() ' The PictureBox image Dim rect As New Rectangle(0, 0, bmSrc.Width, bmSrc.Height) Dim _BMPData As Imaging.BitmapData = bmSrc.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bmSrc.PixelFormat) ' bmSrc.PixelFormat = Format24bppRgb {137224} Dim _BMPPtr As IntPtr = _BMPData.Scan0 Dump: This is the first 2 pixels of col 0 , scanline 0 index(0) - 0 - Col 0 Black index(1) - 0 index(2) - 0 index(3) - 255 - Col 1 White index(4) - 255 index(5) - 255 index(x) = 255 from here to next scanline. This is the first 2 pixels at col 0, scanline 1; pixel 38 * 3 = 114 index(114) - 0 - Col 0 index(115) - 0 index(116) - 0 index(117) - 0 - Col 1 should be 255 index(118) - 0 - ditto index(119) - 255 index(x) = 255 from here to next scanline. This is the first 3 pixels of col 0, scanline 2; pixel 76 * 3 = 228 index(228) - 255 - Col 0 should be 0 index(229) - 255 - ditto index(230) - 0 index(231) - 0 - Col 1 should be 255 index(232) - 0 - ditto index(233) - 0 - ditto index(234) - 0 - ditto index(235) - 255 index(236) - 255
-
Sorry for so much code but I think you need to see all of it. The below code works for a 32 bpp image but using a 24 bpp image. The resulting 24 bpp image is skewed; it looks like by 1 pixel. The skewing starts at the top an skews to the right down the image. I've tried messing with indices and widths but can not get a clue as to what's happening. Am I missing something really simple? Public Sub CropImage() 'Source image in a PictureBox Dim _arRGBValues() As Byte Dim _BMPData As Imaging.BitmapData Dim _BMPPtr As IntPtr Dim bmSrc As Bitmap = Me.Image.Clone() Dim rect As New Rectangle(0, 0, bmSrc.Width, bmSrc.Height) _BMPData = bmSrc.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bmSrc.PixelFormat) _BMPPtr = _BMPData.Scan0 If bmSrc.PixelFormat = Imaging.PixelFormat.Format24bppRgb Then ' 24bpp Dim bytes As Integer = (bmSrc.Width * bmSrc.Height) * 3 ReDim _arRGBValues(bytes - 1) System.Runtime.InteropServices.Marshal.Copy(_BMPPtr, _arRGBValues, 0, _arRGBValues.Length) Else ' 32bpp Dim bytes As Integer = (bmSrc.Width * bmSrc.Height) * 4 ReDim _arRGBValues(bytes - 1) System.Runtime.InteropServices.Marshal.Copy(_BMPPtr, _arRGBValues, 0, _arRGBValues.Length) End If ' Destination image Dim arCropValues() As Byte Dim cropData As Imaging.BitmapData Dim cropPtr As IntPtr ' Size to src bm above - 1 pixel in width to allow for 1 pixel offset; height is the same. Dim bmCrop As Bitmap = New Bitmap(bmSrc.Width - 1, bmSrc.Height, bmSrc.PixelFormat) Dim cropRect As New Rectangle(0, 0, bmCrop.Width, bmCrop.Height) cropData = bmCrop.LockBits(cropRect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bmCrop.PixelFormat) cropPtr = cropData.Scan0 If bmCrop.PixelFormat = Imaging.PixelFormat.Format24bppRgb Then ' 24bpp Dim bytes As Integer = (bmCrop.Width * bmCrop.Height) * 3 ReDim arCropValues(bytes - 1) System.Runtime.InteropServices.Marshal.Copy(cropPtr, arCropValues, 0, arCropValues.Length) Else ' 32bpp Dim bytes As Integer = (bmCrop.Width * bmCrop.Height) * 4 ReDim arCropValues(bytes - 1) System.Runtime.InteropServices.Marshal.Copy(cropPtr, arCropValues, 0, arCropValues.Length) End If
Skewed.
Quote:
' Size to src bm above - 1 pixel in width to allow for 1 pixel offset; height is the same. Dim bmCrop As Bitmap = New Bitmap(bmSrc.Width - 1, bmSrc.Height, bmSrc.PixelFormat)
The Master said, 'Am I indeed possessed of knowledge? I am not knowing. But if a mean person, who appears quite empty-like, ask anything of me, I set it forth from one end to the other, and exhaust it.' ― Confucian Analects
-
After further testing I have found this. It looks like the data return by LockBits() for the source image is not correct. Below is a portion of data I dumped for Scan0 returned from LockBits(). The test image is 38 x 38 pixels with a single pixel vertical line in column 0. It was generated in Paint and saved as .jpg. The Scan0 data shown below shows that the output is being shifted right which is what the resulting image shows. Is this some quirk with LockBits() and 24bbp? Also, I'm still on Windows 7. Thanks. Dim bmSrc As Bitmap = Me.Image.Clone() ' The PictureBox image Dim rect As New Rectangle(0, 0, bmSrc.Width, bmSrc.Height) Dim _BMPData As Imaging.BitmapData = bmSrc.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bmSrc.PixelFormat) ' bmSrc.PixelFormat = Format24bppRgb {137224} Dim _BMPPtr As IntPtr = _BMPData.Scan0 Dump: This is the first 2 pixels of col 0 , scanline 0 index(0) - 0 - Col 0 Black index(1) - 0 index(2) - 0 index(3) - 255 - Col 1 White index(4) - 255 index(5) - 255 index(x) = 255 from here to next scanline. This is the first 2 pixels at col 0, scanline 1; pixel 38 * 3 = 114 index(114) - 0 - Col 0 index(115) - 0 index(116) - 0 index(117) - 0 - Col 1 should be 255 index(118) - 0 - ditto index(119) - 255 index(x) = 255 from here to next scanline. This is the first 3 pixels of col 0, scanline 2; pixel 76 * 3 = 228 index(228) - 255 - Col 0 should be 0 index(229) - 255 - ditto index(230) - 0 index(231) - 0 - Col 1 should be 255 index(232) - 0 - ditto index(233) - 0 - ditto index(234) - 0 - ditto index(235) - 255 index(236) - 255
It's not the LockBits that's returning what you think is bad data. What's wrong is what you think the good data is. The stride is not a perfect 38 pixels * 3 bytes per pixel for each line in your image. It's going to be rounded up to the next 4 byte boundary. The Bitmap object has a Stride property that will tell you how many bytes are in each scan line.
Asking questions is a skill CodeProject Forum Guidelines Google: C# How to debug code Seriously, go read these articles.
Dave Kreskowiak -
It's not the LockBits that's returning what you think is bad data. What's wrong is what you think the good data is. The stride is not a perfect 38 pixels * 3 bytes per pixel for each line in your image. It's going to be rounded up to the next 4 byte boundary. The Bitmap object has a Stride property that will tell you how many bytes are in each scan line.
Asking questions is a skill CodeProject Forum Guidelines Google: C# How to debug code Seriously, go read these articles.
Dave Kreskowiak