Изменение размера прозрачных изображений с помощью C # - PullRequest
25 голосов
/ 27 августа 2008

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

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

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

Ответы [ 5 ]

51 голосов
/ 27 августа 2008

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

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

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

5 голосов
/ 27 августа 2008

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

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

3 голосов
/ 27 августа 2008

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

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

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

1 голос
/ 16 мая 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 );
}
0 голосов
/ 08 июня 2012

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

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

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

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

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

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

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

...