Изменение размера прозрачных изображений с помощью C #

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

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

Взгляните на мое основное изображение:

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);
  }
}

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

Есть ли у кого-нибудь идеи по улучшению?


person MartinHN    schedule 27.08.2008    source источник
comment
Я предлагаю использовать библиотеку, которая исправляет ужасную поддержку GIF в GDI. Как и мой, imageresizing.net он существует уже 4 года, хорошо поддерживается и поддерживается.   -  person Lilith River    schedule 16.07.2011


Ответы (5)


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

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. См. это сообщение в блоге об этом для получения дополнительной информации

Изменить: я забыл избавиться от растровых изображений в примере; это было исправлено

person Markus Olsson    schedule 27.08.2008
comment
Вау, Маркус, это очень мило. Я разместил образец в Интернете: http://www.thewallcompany.dk/test/ Что касается Я вижу - нет абсолютно никаких потерь по сравнению с измененным вручную изображением gif. Большое спасибо. - person MartinHN; 27.08.2008
comment
он работает только с квадратными изображениями и не меняет размер пропорционально - person eKek0; 01.04.2009
comment
Вот список элементов TODO при изменении размера изображений: nathanaeljones.com/163/20-image -resizing-pitfalls Кроме того, я реализовал квантование GIF с поддержкой прозрачности, если это кому-то нужно (модуль изменения размера изображений Google ASP.NET) - person Lilith River; 04.01.2010
comment
Для удобства чтения вы можете сгруппировать оператор using в одну фигурную скобку, например using () \ n using () \ n {// ваш оператор. } - person Soul_Master; 07.11.2012
comment
Ваша ссылка на изображение, кажется, сгнила. Если у вас все еще есть исходный образ, повторно загрузите его в stack.imgur. - person Ilmari Karonen; 27.07.2015

Это базовая функция изменения размера, которую я использовал для нескольких своих приложений, использующих 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; 
}

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

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

person Dillie-O    schedule 27.08.2008

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

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

Лучшее изменение размера изображения

person Jonathan    schedule 27.08.2008
comment
Хех, парень, который управляет этим сайтом :) - person Shawn Miller; 26.06.2009

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

Так не пойдет:

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 );
}
person Bela    schedule 15.05.2009

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

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

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

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

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

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

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

person Lilith River    schedule 07.06.2012