Изменение размера прозрачных изображений с использованием С#

Есть ли у кого-нибудь секретная формула для изменения прозрачных изображений (в основном 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);
  }
}

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

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

Ответ 1

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

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

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

Ответ 2

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

Ответ 3

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

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

Улучшение качества изображения

Ответ 4

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

Это не сработает:

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

Ответ 5

В то время как 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. Прозрачная поддержка не сложна, если вы контролируете палитру изображений.