Pregunta

¿Alguien tiene la fórmula secreta para cambiar el tamaño de imágenes transparentes (principalmente GIF)? sin CUALQUIER pérdida de calidad, ¿qué pasa?

He probado un montón de cosas, lo más cerca que estoy no es lo suficientemente bueno.

Echa un vistazo a mi imagen principal:

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

Y luego la imagen escalada:

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

Estoy usando el código anterior para hacer el cambio de tamaño indexado.

¿Alguien tiene ideas de mejora?

¿Fue útil?

Solución

Si no es necesario conservar el tipo de archivo después de escalar, recomendaría el siguiente enfoque.

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

El resultado tendrá bordes suavizados realmente bonitos.

  • Imagen eliminada de la cabaña de imágenes que había sido reemplazada por un anuncio.

Si debes exportar la imagen en formato gif, te espera un viaje;GDI+ no funciona bien con gif.Ver esta publicación de blog al respecto para más información

Editar: Olvidé eliminar los mapas de bits del ejemplo;ha sido corregido

Otros consejos

Esta es una función básica de cambio de tamaño que he usado para algunas de mis aplicaciones y que aprovecha 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; 
}

No recuerdo muy bien si funcionará con GIF, pero puedes intentarlo.

Nota:No puedo atribuirme todo el crédito por esta función.Reuní algunas cosas a partir de otras muestras en línea y las hice funcionar según mis necesidades 8^D

Creo que el problema es que estás haciendo un cambio de tamaño basado en líneas de escaneo, lo que generará irregularidades sin importar cuánto lo modifiques.Una buena calidad de cambio de tamaño de imagen requiere que usted trabaje un poco más para determinar el color promedio de los píxeles previamente redimensionados que cubre su píxel redimensionado.

El chico que dirige este sitio web tiene una publicación en el blog que analiza algunos algoritmos de cambio de tamaño de imágenes.Probablemente quieras un algoritmo de escalado de imágenes bicúbicas.

Mejor cambio de tamaño de imagen

Para cualquiera que esté intentando utilizar la solución de Markus Olsson para cambiar el tamaño de las imágenes dinámicamente y escribirlas en el flujo de respuesta.

Esto no funcionará:

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

Pero esto:

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

    stream.WriteTo( Response.OutputStream );
}

Si bien PNG es definitivamente mejor que GIF, ocasionalmente existe un caso de uso en el que es necesario permanecer en formato GIF.

Con GIF o PNG de 8 bits, hay que abordar el problema de la cuantización.

La cuantización es donde usted elige qué 256 (o menos) colores conservarán y representarán mejor la imagen, y luego convierte los valores RGB nuevamente en índices.Cuando realiza una operación de cambio de tamaño, la paleta de colores ideal cambia a medida que mezcla colores y cambia los equilibrios.

Para cambios de tamaño leves, como del 10 al 30 %, es posible que le convenga conservar la paleta de colores original.

Sin embargo, en la mayoría de los casos será necesario volver a cuantificar.

Los dos algoritmos principales para elegir son Octree y nQuant.Octree es muy rápido y hace un muy buen trabajo, especialmente si puedes superponer un algoritmo de tramado inteligente.nQuant requiere al menos 80 MB de RAM para realizar una codificación (construye un histograma completo) y suele ser entre 20 y 30 veces más lento (de 1 a 5 segundos por codificación en una imagen promedio).Sin embargo, a veces produce una calidad de imagen mayor que Octree, ya que no "redondea" los valores para mantener un rendimiento constante.

Al implementar compatibilidad con GIF transparentes y GIF animados en el imageresizing.net proyecto, elegí Octree.La compatibilidad con la transparencia no es difícil una vez que tienes el control de la paleta de imágenes.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top