Редактирование растровых изображений в небезопасном контексте - как избежать нестабильности? - PullRequest
0 голосов
/ 03 апреля 2009

Я пытаюсь использовать растровое изображение в небезопасном контексте и наблюдаю нестабильность, например, когда программа запускается первый раз, а второй - нет. Вот код:

private static void RenderBitmap(Graphics g)
{
  const int width = 150, height = 150;
  using (Bitmap bmp = new Bitmap(width, height, 
    System.Drawing.Imaging.PixelFormat.Format24bppRgb))
  {
    Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
    System.Drawing.Imaging.BitmapData bmpData =
      bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, 
        bmp.PixelFormat);
    NativeMethods.RenderText(Graphics.FromImage(bmp).GetHdc(), bmpData.Scan0,
      "This works only first time round", "Segoe", 10, 
      new RGBA(255, 0, 0, 255), width, height);
    bmp.UnlockBits(bmpData);
    g.DrawImage(bmp, new Rectangle(width, height, width, -height));
  }
}

Видя, как это не работает, у меня есть несколько вопросов. Является ли то, что я делаю, безопасно и правильно, при условии, что нативный метод RenderText напрямую манипулирует растровой памятью? Является ли мой способ получения HDC из растрового изображения правильным, или я должен использовать параметр g, который был передан из метода рисования?

Я получаю следующую ошибку:

System.AccessViolationException было unhandled Message = "Попытка чтения или запишите защищенную память. Это часто указание на то, что другая память поврежден. "

Ответы [ 3 ]

3 голосов
/ 03 апреля 2009

Метод NativeMethods.RenderRext не может безопасно работать с данными растрового изображения, поскольку он не знает, насколько широки строки сканирования растрового изображения, и хранится ли он в памяти вверх ногами или нет. Симптомы говорят о том, что метод записывает в память вне растрового изображения, перезаписывая что-то еще, что вам нужно в вашем приложении.

Свойство BitmapData.Stride содержит информацию, необходимую методу для работы с данными. Он содержит ширину строки сканирования в байтах, и если она отрицательна, это означает, что растровое изображение хранится в памяти в обратном порядке. Просто Scan0 - это адрес первой строки сканирования, а Scan0 + Stride - адрес второй строки сканирования.

1 голос
/ 04 апреля 2009

Что ж, после большой боли и страданий я нашел решение: вместо передачи в буфер памяти для заполнения, я передал контекст устройства (HDC) для рендеринга. Кажется, до сих пор работает!

Спасибо всем, кто ответил.

1 голос
/ 03 апреля 2009

Возможно, это глупый вопрос, но почему бы вам не использовать класс TextRenderer, поставляемый с .NET, вместо использования p / invoke?

TextRenderer::DrawText Method (IDeviceContext, String, Font, Point, Color)

http://msdn.microsoft.com/en-us/library/4ftkekek.aspx

-Oisin

...