2008-08-27 5 views
24

Есть ли у кого-нибудь секретная формула для изменения прозрачных изображений (в основном GIF) без ЛЮБАЯ потеря качества - что такое когда-либо?Изменение размера прозрачных изображений с использованием C#

Я пробовал кучу вещей, ближе всего я получаю недостаточно.

Посмотрите на мое основное изображение:

http://www.thewallcompany.dk/test/main.gif

А затем масштабируемого изображения:

http://www.thewallcompany.dk/test/ScaledImage.gif

//Internal resize for indexed colored images 
void IndexedRezise(int xSize, int ySize) 
{ 
    BitmapData sourceData; 
    BitmapData targetData; 

    AdjustSizes(ref xSize, ref ySize); 

    scaledBitmap = new Bitmap(xSize, ySize, bitmap.PixelFormat); 
    scaledBitmap.Palette = bitmap.Palette; 
    sourceData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), 
    ImageLockMode.ReadOnly, bitmap.PixelFormat); 
    try 
    { 
    targetData = scaledBitmap.LockBits(new Rectangle(0, 0, xSize, ySize), 
     ImageLockMode.WriteOnly, scaledBitmap.PixelFormat); 
    try 
    { 
     xFactor = (Double)bitmap.Width/(Double)scaledBitmap.Width; 
     yFactor = (Double)bitmap.Height/(Double)scaledBitmap.Height; 
     sourceStride = sourceData.Stride; 
     sourceScan0 = sourceData.Scan0; 
     int targetStride = targetData.Stride; 
     System.IntPtr targetScan0 = targetData.Scan0; 
     unsafe 
     { 
     byte* p = (byte*)(void*)targetScan0; 
     int nOffset = targetStride - scaledBitmap.Width; 
     int nWidth = scaledBitmap.Width; 
     for (int y = 0; y < scaledBitmap.Height; ++y) 
     { 
      for (int x = 0; x < nWidth; ++x) 
      { 
      p[0] = GetSourceByteAt(x, y); 
      ++p; 
      } 
      p += nOffset; 
     } 
     } 
    } 
    finally 
    { 
     scaledBitmap.UnlockBits(targetData); 
    } 
    } 
    finally 
    { 
    bitmap.UnlockBits(sourceData); 
    } 
} 

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

Есть ли идеи улучшения?

+0

Предлагаю использовать библиотеку, которая исправляет GDI-поддержку GIF. Как и мой, http://imageresizing.net. Он существует уже 4 года и поддерживается и поддерживается. –

ответ

47

Если нет необходимости сохранять тип файла после масштабирования, я бы рекомендовал следующий подход.

using (Image src = Image.FromFile("main.gif")) 
using (Bitmap dst = new Bitmap(100, 129)) 
using (Graphics g = Graphics.FromImage(dst)) 
{ 
    g.SmoothingMode = SmoothingMode.AntiAlias; 
    g.InterpolationMode = InterpolationMode.HighQualityBicubic; 
    g.DrawImage(src, 0, 0, dst.Width, dst.Height); 
    dst.Save("scale.png", ImageFormat.Png); 
} 

Результат будет иметь очень хорошие анти псевдонимами края

  • удалили изображение будка изображение, которое было заменено на объявление

Если необходимо экспортировать изображение в формате GIF вы «за поездку; GDI + плохо работает с gif. См. this blog post об этом для получения дополнительной информации.

Редактировать: Я забыл избавиться от растровых изображений в примере; исправлено

+0

он работает только с квадратными изображениями и не пропорционален пропорциям – eKek0

+1

Вот список предметов TODO при изменении размера изображений: http://nathanaeljones.com/163/20- image-resizing-pitfalls/ Кроме того, я реализовал квантование GIF с поддержкой прозрачности, если кому-то это нужно (Google «ASP.NET-модуль изменения размера изображения») –

+0

Вау, Маркус - это очень приятно. Я разместил образец в Интернете: [http://www.thewallcompany.dk/test/](http://www.thewallcompany.dk/test/) Насколько я вижу - нет абсолютно никакой потери по сравнению с измененным вручную gif изображение. Большое спасибо. – MartinHN

3

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

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

Better Image Resizing

+3

Хех, «парень, который управляет этим сайтом» :) –

4

Это основная функция изменения размера, я использовал для некоторых из моих приложений, которые использует GDI +

/// <summary> 
/// Resize image with GDI+ so that image is nice and clear with required size. 
/// </summary> 
/// <param name="SourceImage">Image to resize</param> 
/// <param name="NewHeight">New height to resize to.</param> 
/// <param name="NewWidth">New width to resize to.</param> 
/// <returns>Image object resized to new dimensions.</returns> 
/// <remarks></remarks> 
public static Image ImageResize(Image SourceImage, Int32 NewHeight, Int32 NewWidth) 
{ 
    System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(NewWidth, NewHeight, SourceImage.PixelFormat); 

    if (bitmap.PixelFormat == Drawing.Imaging.PixelFormat.Format1bppIndexed | bitmap.PixelFormat == Drawing.Imaging.PixelFormat.Format4bppIndexed | bitmap.PixelFormat == Drawing.Imaging.PixelFormat.Format8bppIndexed | bitmap.PixelFormat == Drawing.Imaging.PixelFormat.Undefined | bitmap.PixelFormat == Drawing.Imaging.PixelFormat.DontCare | bitmap.PixelFormat == Drawing.Imaging.PixelFormat.Format16bppArgb1555 | bitmap.PixelFormat == Drawing.Imaging.PixelFormat.Format16bppGrayScale) 
    { 
     throw new NotSupportedException("Pixel format of the image is not supported."); 
    } 

    System.Drawing.Graphics graphicsImage = System.Drawing.Graphics.FromImage(bitmap); 

    graphicsImage.SmoothingMode = Drawing.Drawing2D.SmoothingMode.HighQuality; 
    graphicsImage.InterpolationMode = Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; 
    graphicsImage.DrawImage(SourceImage, 0, 0, bitmap.Width, bitmap.Height); 
    graphicsImage.Dispose(); 
    return bitmap; 
} 

Я не помню, с верхней части моей головы, если он будет работать с GIF, но вы можете попробовать.

Примечание: я не могу в полной мере воспользоваться этой функцией. Я собрал несколько вещей из нескольких других образцов в Интернете и сделал это для моих нужд 8^D

1

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

Это не будет работать:

Response.ContentType = "image/png"; 
dst.Save(Response.OutputStream, ImageFormat.Png); 

Но это будет:

Response.ContentType = "image/png"; 
using (MemoryStream stream = new MemoryStream()) 
{ 
    dst.Save(stream, ImageFormat.Png); 

    stream.WriteTo(Response.OutputStream); 
} 
+0

Почему вторая работа, но не первая? (просто любопытно) –

+0

Эта ссылка объясняет вещи. http://www.west-wind.com/Weblog/posts/6008.aspx – Bela

0

Хотя PNG, безусловно, лучше, GIF, иногда есть случай использования для необходимости оставаться в формате GIF.

С GIF или 8-битным PNG вы должны решить проблему квантования.

Квантование позволяет выбрать, какие 256 (или меньше) цветов лучше всего сохранить и представить изображение, а затем снова включить значения RGB в индексы. Когда вы выполняете операцию изменения размера, идеальная цветовая палитра изменяется, когда вы смешиваете цвета и меняете весы.

Для небольших размеров, например 10-30%, вы можете быть в порядке, сохраняя исходную цветовую палитру.

Однако в большинстве случаев вам необходимо повторно квантовать.

Первыми двумя алгоритмами выбора являются Octree и nQuant. Octree очень быстр и делает очень хорошую работу, особенно если вы можете наложить алгоритм интеллектуального сглаживания. nQuant требует по меньшей мере 80 МБ ОЗУ для выполнения кодирования (он строит полную гистограмму) и, как правило, на 20-30X медленнее (1-5 секунд на каждый код на среднем изображении). Тем не менее, это иногда приводит к более высокому качеству изображения, так как Octree не имеет значения «round» для поддержания постоянной производительности.

При реализации прозрачной GIF и анимированной поддержки GIF в проекте imageresizing.net я выбрал Octree. Поддержка прозрачности не является трудной, если вы контролируете палитру изображений.