gdi + Графика:: DrawImage действительно замедляют ~~

Если вы используете метод AppendHeader для отправки заголовков, специфичных для кеша, и в то же время используйте модель объекта кэша (Cache) для установки политики кэширования, заголовки HTTP-ответов, относящиеся к кешированию, могут быть удалены при использовании модели объекта кэша , Такое поведение позволяет ASP.NET поддерживать самые ограничительные настройки. Например, рассмотрите страницу, содержащую пользовательские элементы управления. Если эти элементы управления имеют конфликтующие политики кэширования, будет использоваться наиболее ограничительная политика кэширования. Если один пользовательский элемент управления устанавливает заголовок «Cache-Control: Public», а другой пользовательский элемент управления устанавливает более ограничительный заголовок «Cache-Control: Private» через вызовы SetCacheability, тогда заголовок «Cache-Control: Private» будет отправлен с response.

Вы можете создать httpProtocol в веб-конфигурации для customHeaders.

<httpProtocol>
     <customHeaders>
       <add name="Access-Control-Allow-Methods" values="*" />        
     </customHeaders>
   <httpProtocol>
17
задан Ian Boyd 24 October 2009 в 12:49
поделиться

6 ответов

У Вас есть экран 4000 x 3 000 разрешений? Ничего себе!

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

[РЕДАКТИРОВАНИЕ после первого комментария] Мой комментарий действительно немного глуп, я предполагаю, что DrawImage будет маскировать/пропускать ненужные пиксели.

После Вашего редактирования (показывая StretchDIBits), я предполагаю, что возможный источник разности оборотов мог бы прибыть из того, что StretchDIBits аппаратно ускорен (" , Если драйвер не может поддерживать JPEG, или изображение файла PNG " является подсказкой...), в то время как DrawImage мог бы быть (у меня нет доказательства для этого!) кодированный в C, полагаясь на мощность ЦП вместо одной GPU...

, Если я вспоминаю правильно, изображения DIB быстры (несмотря на то, чтобы быть "независимым от устройств"). См. Высокая скорость Анимация Win32 : " использование CreateDIBSection, чтобы сделать высокоскоростную анимацию ". Хорошо, это относится к DIB по сравнению с GDI в старой версии Windows (1996!), но я думаю, что это все еще верно.

[РЕДАКТИРОВАНИЕ], Возможно Битовый массив:: функция GetHBITMAP могла бы помочь Вам использовать StretchDIBits (не протестированный...).

3
ответ дан 30 November 2019 в 12:51
поделиться

При использовании GDI + класс TextureBrush - то, в чем Вы нуждаетесь для рендеринга изображений быстро. Я записал несколько 2-х игр с ним, обойдя 30 кадр/с или около этого.

я никогда не писал код.NET в C++, таким образом, вот пример C#-ish:

Bitmap bmp = new Bitmap(...)
TextureBrush myBrush = new TextureBrush(bmp)

private void Paint(object sender, PaintEventArgs e):
{
    //Don't draw the bitmap directly. 
    //Only draw TextureBrush inside the Paint event.
    e.Graphics.FillRectangle(myBrush, ...)
}
15
ответ дан 30 November 2019 в 12:51
поделиться

Просто мысль; вместо того, чтобы получить ширину и высоту изображения перед рисунком, почему не кэшируют эти значения, когда Вы загружаете изображение?

2
ответ дан 30 November 2019 в 12:51
поделиться

Исследуйте влияние явной установки режима интерполяции к NearestNeighbor (где в Вашем примере похоже, что интерполяция не на самом деле необходима! Но 300 мс являются видом стоимости выполнения высококачественной интерполяции, когда никакая интерполяция не необходима, таким образом, стоящий попытки)

Другая вещь исследовать изменяет глубину цвета битового массива.

2
ответ дан 30 November 2019 в 12:51
поделиться

К сожалению, когда у меня была подобная проблема, я нашел, что GDI +, как известно, намного медленнее, чем GDI и не обычно аппаратно ускоряется, но теперь Microsoft шла дальше к WPF, они не возвратятся для улучшения GDI +!

Все производители видеокарт перешли на 3D производительность и не кажутся интересующимися 2D ускорением, и нет никакого ясного источника информации, на котором функции или могут быть аппаратно ускорены или нет. Очень печальный, потому что записавший приложение в.NET с помощью GDI +, я не рад измениться на совершенно другую технологию для ускорения его до разумных уровней.

2
ответ дан 30 November 2019 в 12:51
поделиться

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

DrawImage(bitmap,0,0);

Как я уже сказал, я сомневаюсь, что это будет иметь какое-либо значение, потому что я уверен , что DrawImage проверяет Ширина и Высота растрового изображения, и, если изменение размера не требуется, просто вызывает эту перегрузку. (Надеюсь, он не потрудится просмотреть все 12 миллионов пикселей, не выполняя никакой реальной работы).

Обновление: Мои размышления ошибочны. С тех пор я узнал, но комментарий ребят напомнил мне мой старый ответ: вы хотите указать размер назначения; даже если он совпадает с размером источника:

DrawImage(bitmap, 0, 0, bitmap.GetWidth, bitmap.GetHeight);

Причина заключается в различии dpi между разрешением точечного рисунка и dpi места назначения. GDI + выполнит масштабирование, чтобы изображение получилось нужного «размера» (например, в дюймах)


С октября прошлого года я самостоятельно узнал, что вы действительно хотите нарисовать «кэшированный» версия вашего растрового изображения. В GDI + есть класс CachedBitmap . Есть несколько уловок по его использованию. Но, в конце концов, у меня есть функциональный бит (Delphi) кода, который это делает.

Предостережение состоит в том, что CachedBitmap может стать недействительным, то есть его нельзя использовать для рисования. Это происходит, если пользователь меняет разрешение или глубину цвета (например, удаленный рабочий стол). В этом случае DrawImage завершится ошибкой, и вам придется заново создать CachedBitmap :

class procedure TGDIPlusHelper.DrawCachedBitmap(image: TGPImage;
      var cachedBitmap: TGPCachedBitmap;
      Graphics: TGPGraphics; x, y: Integer; width, height: Integer);
var
   b: TGPBitmap;
begin
   if (image = nil) then
   begin
      //i've chosen to not throw exceptions during paint code - it gets very nasty
      Exit;
   end;

   if (graphics = nil) then
   begin
      //i've chosen to not throw exceptions during paint code - it gets very nasty
      Exit;
   end;

   //Check if we have to invalidate the cached image because of size mismatch
   //i.e. if the user has "zoomed" the UI
   if (CachedBitmap <> nil) then
   begin
      if (CachedBitmap.BitmapWidth <> width) or (CachedBitmap.BitmapHeight <> height) then
         FreeAndNil(CachedBitmap); //nil'ing it will force it to be re-created down below
   end;

   //Check if we need to create the "cached" version of the bitmap
   if CachedBitmap = nil then
   begin
      b := TGDIPlusHelper.ResizeImage(image, width, height);
      try
         CachedBitmap := TGPCachedBitmap.Create(b, graphics);
      finally
         b.Free;
      end;
end;

    if (graphics.DrawCachedBitmap(cachedBitmap, x, y) <> Ok) then
begin
       //The calls to DrawCachedBitmap failed
       //The API is telling us we have to recreate the cached bitmap
       FreeAndNil(cachedBitmap);
       b := TGDIPlusHelper.ResizeImage(image, width, height);
       try
          CachedBitmap := TGPCachedBitmap.Create(b, graphics);
       finally
          b.Free;
       end;

       graphics.DrawCachedBitmap(cachedBitmap, x, y);
    end;
 end;

cachedBitmap передается по ссылке. Будет создан первый вызов DrawCachedBitmap его кэшированная версия. Затем вы передаете его в последующих вызовах, например:

Image imgPrintInvoice = new Image.FromFile("printer.png");
CachedBitmap imgPrintInvoiceCached = null;

...

int glyphSize = 16 * (GetCurrentDpi() / 96);

DrawCachedBitmap(imgPrintInvoice , ref imgPrintInvoiceCached , graphics, 
      0, 0, glyphSize, glyphSize);

Я использую процедуру для рисования глифов на кнопках с учетом текущего DPI. То же самое могло быть использовано командой Internet Explorer для рисования изображений, когда пользователь работает с высоким разрешением (т. Е. Очень медленно рисует увеличенные изображения, потому что они используют GDI +).

и вам необходимо заново создать CachedBitmap :

class procedure TGDIPlusHelper.DrawCachedBitmap(image: TGPImage;
      var cachedBitmap: TGPCachedBitmap;
      Graphics: TGPGraphics; x, y: Integer; width, height: Integer);
var
   b: TGPBitmap;
begin
   if (image = nil) then
   begin
      //i've chosen to not throw exceptions during paint code - it gets very nasty
      Exit;
   end;

   if (graphics = nil) then
   begin
      //i've chosen to not throw exceptions during paint code - it gets very nasty
      Exit;
   end;

   //Check if we have to invalidate the cached image because of size mismatch
   //i.e. if the user has "zoomed" the UI
   if (CachedBitmap <> nil) then
   begin
      if (CachedBitmap.BitmapWidth <> width) or (CachedBitmap.BitmapHeight <> height) then
         FreeAndNil(CachedBitmap); //nil'ing it will force it to be re-created down below
   end;

   //Check if we need to create the "cached" version of the bitmap
   if CachedBitmap = nil then
   begin
      b := TGDIPlusHelper.ResizeImage(image, width, height);
      try
         CachedBitmap := TGPCachedBitmap.Create(b, graphics);
      finally
         b.Free;
      end;
end;

    if (graphics.DrawCachedBitmap(cachedBitmap, x, y) <> Ok) then
begin
       //The calls to DrawCachedBitmap failed
       //The API is telling us we have to recreate the cached bitmap
       FreeAndNil(cachedBitmap);
       b := TGDIPlusHelper.ResizeImage(image, width, height);
       try
          CachedBitmap := TGPCachedBitmap.Create(b, graphics);
       finally
          b.Free;
       end;

       graphics.DrawCachedBitmap(cachedBitmap, x, y);
    end;
 end;

cachedBitmap передается по ссылке. Будет создан первый вызов DrawCachedBitmap его кэшированная версия. Затем вы передаете его в последующих вызовах, например:

Image imgPrintInvoice = new Image.FromFile("printer.png");
CachedBitmap imgPrintInvoiceCached = null;

...

int glyphSize = 16 * (GetCurrentDpi() / 96);

DrawCachedBitmap(imgPrintInvoice , ref imgPrintInvoiceCached , graphics, 
      0, 0, glyphSize, glyphSize);

Я использую процедуру для рисования глифов на кнопках с учетом текущего DPI. То же самое могло быть использовано командой Internet Explorer для рисования изображений, когда пользователь работает с высоким разрешением (т. Е. Очень медленно рисует увеличенные изображения, потому что они используют GDI +).

и вам необходимо заново создать CachedBitmap :

class procedure TGDIPlusHelper.DrawCachedBitmap(image: TGPImage;
      var cachedBitmap: TGPCachedBitmap;
      Graphics: TGPGraphics; x, y: Integer; width, height: Integer);
var
   b: TGPBitmap;
begin
   if (image = nil) then
   begin
      //i've chosen to not throw exceptions during paint code - it gets very nasty
      Exit;
   end;

   if (graphics = nil) then
   begin
      //i've chosen to not throw exceptions during paint code - it gets very nasty
      Exit;
   end;

   //Check if we have to invalidate the cached image because of size mismatch
   //i.e. if the user has "zoomed" the UI
   if (CachedBitmap <> nil) then
   begin
      if (CachedBitmap.BitmapWidth <> width) or (CachedBitmap.BitmapHeight <> height) then
         FreeAndNil(CachedBitmap); //nil'ing it will force it to be re-created down below
   end;

   //Check if we need to create the "cached" version of the bitmap
   if CachedBitmap = nil then
   begin
      b := TGDIPlusHelper.ResizeImage(image, width, height);
      try
         CachedBitmap := TGPCachedBitmap.Create(b, graphics);
      finally
         b.Free;
      end;
end;

    if (graphics.DrawCachedBitmap(cachedBitmap, x, y) <> Ok) then
begin
       //The calls to DrawCachedBitmap failed
       //The API is telling us we have to recreate the cached bitmap
       FreeAndNil(cachedBitmap);
       b := TGDIPlusHelper.ResizeImage(image, width, height);
       try
          CachedBitmap := TGPCachedBitmap.Create(b, graphics);
       finally
          b.Free;
       end;

       graphics.DrawCachedBitmap(cachedBitmap, x, y);
    end;
 end;

cachedBitmap передается по ссылке. Будет создан первый вызов DrawCachedBitmap его кэшированная версия. Затем вы передаете его в последующих вызовах, например:

Image imgPrintInvoice = new Image.FromFile("printer.png");
CachedBitmap imgPrintInvoiceCached = null;

...

int glyphSize = 16 * (GetCurrentDpi() / 96);

DrawCachedBitmap(imgPrintInvoice , ref imgPrintInvoiceCached , graphics, 
      0, 0, glyphSize, glyphSize);

Я использую процедуру для рисования глифов на кнопках с учетом текущего DPI. То же самое могло быть использовано командой Internet Explorer для рисования изображений, когда пользователь работает с высоким разрешением (т. Е. Очень медленно рисует увеличенные изображения, потому что они используют GDI +).

с учетом текущего DPI. То же самое могло быть использовано командой Internet Explorer для рисования изображений, когда пользователь работает с высоким разрешением (т. Е. Очень медленно рисует увеличенные изображения, потому что они используют GDI +).

с учетом текущего DPI. То же самое могло быть использовано командой Internet Explorer для рисования изображений, когда пользователь работает с высоким разрешением (т. Е. Очень медленно рисует увеличенные изображения, потому что они используют GDI +).

2
ответ дан 30 November 2019 в 12:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: