2015-08-15 7 views
1

Im пытается сделать вид Grahpics.DrawImage реализация с использованием небезопасный код и указатели конечно.C# Draw image implementation

В этом случае я пытаюсь нарисовать небольшое растровое изображение на большей ширине (оба 32bppArgb).

Это мой код

private static unsafe void Draw(Bitmap bmp, Bitmap bmp2, int xPoint, int yPoint) 
    { 

     BitmapData bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, bmp.PixelFormat); 
     BitmapData bmData2 = bmp2.LockBits(new Rectangle(0, 0, bmp2.Width, bmp2.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp2.PixelFormat); 

     IntPtr scan0 = bmData.Scan0; 
     IntPtr scan02 = bmData2.Scan0; 

     int stride = bmData.Stride; 
     int stride2 = bmData2.Stride; 

     int nWidth = bmp2.Width; 
     int nHeight = bmp2.Height; 

     int sourceX = 0; 
     int sourceY = 0; 
     byte* p = (byte*)scan0.ToPointer(); 
     p += yPoint * stride + xPoint * 4; 
     byte* p2 = (byte*)scan02.ToPointer(); 
     p2 += sourceY * stride2 + sourceX * 4; 
     int bytes = nWidth * 4; 

     for (int y = 0; y < nHeight; y++) 
     { 

      for (int x = 0; x <nWidth; x++) 
      { 


       p[0] = p2[0]; 
       p[1] = p2[1]; 
       p[2] = p2[2]; 
       p[3] = p2[3]; 

      } 

      p += 4; 
      p2 += 4; 
     } 

     bmp.UnlockBits(bmData); 
     bmp2.UnlockBits(bmData2); 
    } 

это обновленный код

+0

Вы копируете изображение себе. Для 'b2' вы должны использовать' scan02' вместо 'scan0'. Вы также должны использовать 'stride2' для' b2'. Затем вы должны использовать 'stride' и' stride2', чтобы переместить 'b' и' b2' в следующую строку, а не предполагать, что следующая строка начинается сразу после текущей. Между линиями может быть отступы, а шаг может быть отрицательным, если изображение хранится перевернуто в памяти. – Guffa

+0

@ Guffa ohh .. не видел ... спасибо мужчине! – Slashy

+0

@Guffa wait .. теперь я получаю исключение здесь 'p [0] = p2 [0]; ** попытался прочитать или записать защищенную память ** – Slashy

ответ

2

Я сделал некоторые изменения, чтобы сделать его работу:

  • Использование ImageLockMode.WriteOnly в LockBits вызова для изображения, которое вам хочу писать.
  • Не перемещайте p2 согласно xPoint и yPoint.

Я видел, что вы устанавливаете указатели внутри внешнего контура, поэтому вам не нужно будет перемещать указатели в конце цикла. Я рекомендую вам рассчитать начальные точки за пределами внешнего цикла и переместить указатели внутри него.

Я также рекомендую эти изменения, которые я сделал:

  • Добавить чеки за пределы изображений, так что вы не случайно пытаются привлечь за пределы изображения.

  • Сделайте способ void. Возврат растрового изображения предполагает, что он создает новое растровое изображение, а не заменяет одно из битового массива, которое вы передаете ему.

Я добавил параметр pixelBytes, чтобы сделать его пригодным для использования в разных форматах пикселей. (В основном потому, что случилось у JPEGs, не PNGs испытать с.)

Код:

private static unsafe void Draw(Bitmap bmp, Bitmap bmp2, int xPoint, int yPoint, int pixelBytes) { 

    BitmapData bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, bmp.PixelFormat); 
    BitmapData bmData2 = bmp2.LockBits(new Rectangle(0, 0, bmp2.Width, bmp2.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp2.PixelFormat); 

    IntPtr scan0 = bmData.Scan0; 
    IntPtr scan02 = bmData2.Scan0; 

    int stride = bmData.Stride; 
    int stride2 = bmData2.Stride; 

    int nWidth = bmp2.Width; 
    int nHeight = bmp2.Height; 

    int sourceX = 0; 
    int sourceY = 0; 

    if (xPoint < 0) { 
    sourceX = -xPoint; 
    nWidth -= sourceX; 
    xPoint = 0; 
    } 
    if (yPoint < 0) { 
    sourceY = -yPoint; 
    nHeight -= sourceY; 
    yPoint = 0; 
    } 
    if (xPoint + nWidth > bmp.Width) { 
    nWidth = bmp.Width - xPoint; 
    } 
    if (yPoint + nHeight > bmp.Height) { 
    nHeight = bmp.Height - yPoint; 
    } 

    if (nWidth > 0 && nHeight > 0) { 

    byte* p = (byte*)scan0.ToPointer(); 
    p += yPoint * stride + xPoint * pixelBytes; 
    byte* p2 = (byte*)scan02.ToPointer(); 
    p2 += sourceY * stride2 + sourceX * pixelBytes; 

    int bytes = nWidth * pixelBytes; 

    for (int y = 0; y < nHeight; y++) { 
     for (int x = 0; x < bytes; x++) { 
     p[0] = p2[0]; 
     p++; 
     p2++; 
     } 
     p += stride - nWidth * pixelBytes; 
     p2 += stride2 - nWidth * pixelBytes; 
    } 

    } 

    bmp.UnlockBits(bmData); 
    bmp2.UnlockBits(bmData2); 
} 
+0

спасибо, что ты потрясающий! Ваш код прямо к делу!+1 – Slashy

+0

Одна последняя вещь просто измерила время исключения этого метода, и это было медленнее, чем мое (я знаю, что он не работал, но все же). Я думаю, что основным узким местом является то, что внутренний цикл работает 'bytes' time..может ли он работать быстрее? можете ли вы просто обновить somthing в моем коде, чтобы он работал? Огромное огромное спасибо брату! ты отвечаешь, это потрясающе, но это немного медленно .. спасибо заранее! – Slashy

+0

@Slashy: Если вы удалите параметр pixelBytes и сделаете его петлями вместо байтов, вы должны вернуть эту производительность. – Guffa