2009-05-28 5 views
11

Я использую классы System.Drawing для создания эскизов и изображений с водяными знаками из загруженных пользователем фотографий. Пользователи также могут обрезать изображения с помощью jCrop после загрузки оригинала. Я взял этот код у кого-то еще, и я хочу упростить и оптимизировать его (он используется на веб-сайте с высоким трафиком).Эффективное манипулирование изображениями в C#

Предыдущий парень имел статические методы, которые получили растровое изображение в качестве параметра и также возвратили его, внутренне выделяя и удаляя объект Graphics. Я понимаю, что экземпляр Bitmap содержит все изображение в памяти, а Graphics - это, в основном, очередь операций рисования, и это идемпотент.

Процесс в настоящее время работает следующим образом:

  • Получить изображение и сохранить его во временный файл.
  • Получить координаты посева.
  • Загрузите исходное растровое изображение в память.
  • Создайте новое растровое изображение с оригинала, применяя обрезку.
  • Сделайте немного сумасшедшей регулировки яркости на новом растровом изображении, возможно (?), Возвращающем новый растровый рисунок (я бы предпочел не трогать это, арифметика указателей изобилует!), Позволяет называть это A.
  • Создайте еще одно растровое изображение с в результате один, применяя водяной знак (позволяет называть этот B1)
  • Создание растрового изображения с 175x175 миниатюру из А.
  • Создание растрового изображения 45x45 миниатюр из А.

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

Любые мысли или идеи?

О, и я должен, вероятно, упомянуть, что это первый раз, когда я действительно работаю с .NET, поэтому, если что-то, что я говорю, кажется смущенным, пожалуйста, несите меня и дайте мне несколько советов.

+0

Очень печально, что это ваше первое взаимодействие с .NET. Образец IDisposable - это мое реальное единственное неудовлетворение фреймворком. Этот «используемый» бизнес является самой эзотерической регулярно используемой функцией - большинство вещей очень просты. – overslacked

+0

Хороший вопрос, говорю! +1 – Cerebrus

+1

Мне пришлось искать «идемпотент» ... доброе слово. – JasonRShaver

ответ

3

Многократное Графические объекты, вероятно, не приведет к значительному увеличению производительности.

Основополагающий код GDI просто создает контекст устройства для растрового изображения, которое вы загрузили в ОЗУ (DC).

Узкое место вашей операции, похоже, загружает изображение с диска.

Зачем загружать изображение с диска? Если он уже находится в массиве байтов в ОЗУ, который должен быть при его загрузке, вы можете просто создать поток памяти в массиве байтов, а затем создать растровое изображение из этого потока памяти.

Другими словами, сохраните его на диске, но не перезагружайте его, просто используйте его из ОЗУ.

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

Вы должны профиль операцию, чтобы увидеть, где она нуждается в улучшении (или даже если это должно быть улучшено.)

3

Процесс кажется разумным. Каждое изображение должно существовать в памяти до того, как оно будет сохранено на диске, поэтому каждая версия ваших эскизов будет в первую очередь в памяти. Ключом к тому, чтобы обеспечить эффективную работу, является удаление объектов Graphics и Bitmap. Самый простой способ сделать это - с помощью инструкции using.

using(Bitmap b = new Bitmap(175, 175)) 
using(Graphics g = Graphics.FromBitmap(b)) 
{ 
    ... 
} 
+0

Мой настоящий вопрос больше похож: даст ли он увеличение производительности, если я снова использую объект «Graphics»? –

0

Я только собираюсь бросить это там случайно, но если вы хотите быстро «руководство» для наилучшей практики для работы с изображениями, посмотрите на проект Paint.NET. Для бесплатных инструментов высокой производительности для обработки изображений просмотрите AForge.NET.

Преимущество AForge заключается в том, чтобы позволить вам делать много шагов без создания нового растрового изображения каждый раз. Если это для веб-сайта, я могу почти гарантировать, что код, с которым вы работаете, будет узким местом производительности для приложения.

2

Я завершил аналогичный проект некоторое время назад и провел несколько практических испытаний, чтобы увидеть, есть ли разница в производительности, если я повторно использовал объект Graphics, а не разворачивал новый для каждого изображения. В моем случае я работал над постоянным потоком большого количества изображений (> 10000 в «партии»). Я обнаружил, что я получил небольшое увеличение производительности за счет повторного использования объекта Graphics.

Я также обнаружил, что с помощью GraphicsContainers в объекте Graphics я получил небольшое увеличение, чтобы легко менять различные состояния в/из объекта, поскольку он использовался для выполнения различных действий. (В частности, мне пришлось применить обрезку и нарисовать текст и прямоугольник на каждом изображении.) Я не знаю, имеет ли это смысл для того, что вам нужно делать. Вы можете посмотреть методы BeginContainer и EndContainer в объекте Graphics.

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

Некоторые ссылки могут оказаться полезными:

Using Nested Graphics Containers
GraphicsContainer Class

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