2015-04-21 3 views
4

Я использую следующий код, чтобы заблокировать прямоугольник область растрового изображенияКопирование rectangluar часть растрового изображения с использованием LockBits

Recangle rect = new rect(X,Y,width,height); 
BitmapData bitmapData = bitmap.LockBits(rect, ImageLockMode.ReadOnly, 
         bitmap.PixelFormat); 

Что, кажется, проблема bitmapData.Scan0 дает мне IntPtr верхнего левого угла прямоугольник. Когда я использую memcpy, он копирует смежную область в памяти до указанной длины.

memcpy(bitmapdest.Scan0, bitmapData.Scan0, 
      new UIntPtr((uint (rect.Width*rect.Height*3))); 

Если следующее мои данные растрового изображения,

a b c d e 
f g h i j 
k l m n o 
p q r s t 

и если прямоугольник (2, 1, 3 ,3) т.е. область

g h i 
l m n 
q r s 

с помощью memcpy дает мне растровый со следующей области

g h i 
j k l 
m n o 

Я могу понять, почему он копирует смежную область памяти. В нижней строке я хочу скопировать область прямоугольника, используя Lockbits.

Edit: Я Bitmap.Clone,

using (Bitmap bitmap= (Bitmap)Image.FromFile(@"Data\Edge.bmp")) 
{ 
    bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY); 
    Rectangle cropRect = new Rectangle(new Point(i * croppedWidth, 0),new Size(croppedWidth, _original.Height)); 
    _croppedBitmap= bitmap.Clone(cropRect, bitmap.PixelFormat); 
} 

но это было быстрее, когда я перевернул Y (менее 500ms)

bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY); 

, но это было очень медленно, когда я не сделал flip Y (30 секунд)

Изображение размер б/у был 60000x1500.

+2

Без [хороший, _minimal_, _complete_ примера кода] (HTTP://stackoverflow.com/help/mcve), который надежно воспроизводит проблему, ответить на нее невозможно. Тем не менее, 'LockBits()' не может магически переформатировать данные за вашим растровым изображением, поэтому я не вижу причин ожидать, что работает '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '. Вероятно, вам придется скопировать строку сканирования данных с помощью scanline; вы проверили свойство BitmapData.Stride? Он должен сказать вам, что вам нужно добавить в 'Scan0' для каждой следующей строки. –

+0

@PeterDuniho Я понимаю, почему memcpy не будет работать. Значит, вы подразумеваете, что копирование scanline с помощью scanline - единственный способ сделать это? Можете ли вы объяснить, почему Bitmap.Clone принимает разные времена в этих двух случаях? – Dinesh

+0

Есть ли причина, по которой не используется DrawImage? – TaW

ответ

0

Не понимайте, в чем проблема. Следующие копии коды правильной область битовой карты в управляемом массив (я использовал 32bpp, альфа всегда 255 для 24bpp битовой карты, конечно):

int x = 1; 
int y = 1; 
int w = 2; 
int h = 2; 

Bitmap bmp = new Bitmap(@"path\to\bitmap.bmp"); 

Rectangle rect = new Rectangle(x, y, w, h); 
System.Drawing.Imaging.BitmapData bmpData = 
    bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, 
    System.Drawing.Imaging.PixelFormat.Format32bppArgb); 

IntPtr ptr = bmpData.Scan0; 

int bytes = 4 * w * h; 
byte[] rgbValues = new byte[bytes]; 

System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes); 

bmp.UnlockBits(bmpData); 
+0

У вашего решения может возникнуть проблема при попытке скопировать прямоугольную область на растровое изображение, как обсуждалось [здесь] (http://stackoverflow.com/questions/10771300/bitmap-lockbits-confusion). Я узнал, что с помощью «LockBits» единственный способ сделать это - перебрать по всему растровому изображению смещение шага, как и решение, обсуждаемое в ссылке выше. – Dinesh

+0

Я протестировал код с растровым изображением 4x4 пикселей. Вышеупомянутый код без проблем копирует правильный внутренний 2x2-пиксельный блок. Вы также можете без проблем изменить и повторно вставить этот блок 2x2 в растровое изображение. Аналогичный пример кода можно найти в MSDN. Вы можете выбрать нужный формат пикселей в вызове 'LockBits', который также повлияет на шаг. Честно говоря, я не знаю, почему это работает. Может быть, 'Marshal.Copy' делает какую-то магию внутри? –

+0

Он не будет работать, если stride/"bytes per pixel" == "ширина изображения". Обычно это правда, поэтому ваш тест работает. В противном случае вы скопируете данные реального изображения в «мусор памяти оптимизации границ» и наоборот. – Pedro77

Смежные вопросы