2009-12-07 22 views
10

Tengo un problema con la escala de la imagen en .NET. Puedo usar el tipo de gráficos estándar para cambiar el tamaño de las imágenes como en este ejemplo:C# Las imágenes redimensionadas tienen bordes negros

public static Image Scale(Image sourceImage, int destWidth, int destHeight) 
{ 
     Bitmap toReturn = new Bitmap(sourceImage, destWidth, destHeight); 

     toReturn.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution); 

     using (Graphics graphics = Graphics.FromImage(toReturn)) 
     { 
      graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality; 
      graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; 
      graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; 
      graphics.DrawImage(sourceImage, 0, 0, destWidth, destHeight); 
     } 
     return toReturn; 
    } 

pero tengo un gran problema con las imágenes redimensionadas: tienen bordes grises y negras y es muy importante para hacer tiene imágenes sin ellos.

¿Por qué aparecen y qué puedo hacer para que desaparezcan? Salida

muestra:

sample output

+2

¿Cómo se ve el código HTML como si eso fuera enviado al navegador para estas imágenes? – DOK

+2

¿Cuál es el tipo original de la imagen? –

+2

publique su imagen de entrada –

Respuesta

6

Probar:

graphic.CompositingMode = CompositingMode.SourceCopy; 
+4

Lamentablemente, esta no es una solución en absoluto. No tiene efecto. El borde gris se sigue generando. Si funcionó para el OP entonces por un mero accidente. La solución consiste en especificar atributos de imagen como se señala en esta respuesta: http://stackoverflow.com/questions/2319983/resizing-an-image-in-asp-net-without-losing-the-image-quality/2324414# 2324414 –

+3

@Developer Art, ¿es su fuente de 24 bits o de 32 bits con alfa? Cambiar el tamaño de una imagen con alfa dará como resultado píxeles semitransparentes a lo largo de los bordes; al establecer este modo, los píxeles se mezclarán con el fondo, de lo contrario se mezclarán con negro, lo que provocará los bordes. No sé qué ocurre con las imágenes de 24 bits. –

+1

@Mark Ransom, vea mi respuesta, tiene razón en parte pero no dio la solución correcta. – Jeroen

2

¿Cómo funciona el siguiente trabajo para usted? Este es el código que he usado para hacer lo mismo. La principal diferencia que noto es que no utilizo SetResolution (y supongo que es una entrada y salida cuadradas, ya que ese fue el caso para mí).

/// <summary> 
/// Resizes a square image 
/// </summary> 
/// <param name="OriginalImage">Image to resize</param> 
/// <param name="Size">Width and height of new image</param> 
/// <returns>A scaled version of the image</returns> 
internal static Image ResizeImage(Image OriginalImage, int Size) 
{ 
    Image finalImage = new Bitmap(Size, Size); 

    Graphics graphic = Graphics.FromImage(finalImage); 

    graphic.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighSpeed; 
    graphic.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed; 
    graphic.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; 

    Rectangle rectangle = new Rectangle(0, 0, Size, Size); 

    graphic.DrawImage(OriginalImage, rectangle); 

    return finalImage; 
} 
+2

Creó una imagen desde cero que tiene un fondo negro predeterminado. Está cargando una imagen que podría no tener fondo. – Jeroen

3

Esto se debe a que el muestreo se tomó de los bordes de la fotografía.

1

Esto se debe al suavizado (fusión con el fondo) en los bordes al dibujar la imagen.

Puede dibujarlo dos veces, una vez sin y una con suavizado habilitado. O podrías dibujarlo un poco más grande. O si se conoce el color de fondo original, primero puede llenar la imagen con el color de fondo.

+0

@Downvoter, realmente agradecería un comentario que diga por qué mi respuesta fue tan inapropiada o mala ... – Lucero

5

El problema radica en el hecho de que el mapa de bits toReturn tiene un fondo negro por defecto. Al copiar una nueva imagen sobre ella se crean bordes negros o grises.

La solución es eliminar el fondo predeterminado negro, llamando al:

toReturn.MakeTransparent(); 

Puesto que después de esta línea que vaya a dibujar en una nueva imagen sin ningún tipo de color de fondo de las fronteras desaparecerán.

7

Esto puede deberse a que los píxeles alrededor de los bordes están interpolados incorrectamente. Yo llamaría esto un error.

Aquí está la solución, sin embargo:

graphics.CompositingMode = CompositingMode.SourceCopy; 
graphics.PixelOffsetMode = PixelOffsetMode.Half; 
graphics.InterpolationMode = InterpolationMode.NearestNeighbor; 

// Draw your image here. 

graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; 

// Draw it again. 

Lo que esto hace primero es el dibujo de un "fondo" con los bordes correctamente cumplimentados, y luego dibujar de nuevo con interpolación. Si no necesita interpolación, entonces esto no es necesario.

+0

Esto resolvió muchos problemas. ¡Muchas gracias! – Tillito

+0

@Tillito No hay problema :) Tenga en cuenta que esto es, aunque efectiva, no la solución más óptima, en cuanto al rendimiento. No debería importar mucho a menos que tenga una gran cantidad de imágenes o esté haciendo un componente personalizado para ser distribuido, reutilizado, etc., donde es posible que desee un método más complejo para solucionarlo, como usar [lockbits ] (http://msdn.microsoft.com/en-us/library/system.drawing.bitmap.lockbits.aspx) y dibujar/interpolar "manualmente". –

6

La solución real es utilizar una sobrecarga del DrawImage que le permite pasar un objeto ImageAttributes.

Por ImageAttributes ejemplo, llamar al siguiente método antes de pasarla a DrawImage:

using (var ia = new ImageAttributes()) 
{ 
    ia.SetWrapMode(WrapMode.TileFlipXY); 
    aGraphic.DrawImage(..., ia); 
} 

Ver también this answer

+0

Esto funcionó perfectamente para mí. Gracias. – user892381

+0

Esta es la verdadera solución para este problema. – kaiyaq

+0

He estado tratando de solucionar este problema durante aproximadamente 3 horas. Esta respuesta es la única que funcionó. Ojalá esta fuera la solución aceptada. – Andy

1

Ninguno de ellos trabajó para mí.

Sin embargo, cambiar el formato de

System.Drawing.Imaging.PixelFormat.Format24bppRgb 

a

System.Drawing.Imaging.PixelFormat.Format32bppArgb 

hizo resolver el problema

using (System.Drawing.Bitmap newImage = new System.Drawing.Bitmap(newWidth, newHeight, 
       // System.Drawing.Imaging.PixelFormat.Format24bppRgb // OMG bug 
        System.Drawing.Imaging.PixelFormat.Format32bppArgb 
       )) 
      { 
0

Una respuesta correcta puede ser reconstruido a partir de algunas de las otras respuestas, pero ninguno de ellos está completo y algunos presentan algunas ideas muy malas (como dibujar la imagen dos veces).

Hay tres razones por las que estamos viendo artefactos:

  1. El valor predeterminado Graphics.PixelOffsetMode configuración hace que los valores de los píxeles a muestrear de forma incorrecta, lo que resulta en una ligera distorsión de la imagen, sobre todo en los bordes.
  2. InterpolationMode.HighQualityBicubic muestras píxeles más allá del borde de la imagen, que son transparentes de forma predeterminada. Esos píxeles transparentes se mezclan con los píxeles del borde por la muestra, lo que da como resultado bordes semitransparentes.
  3. Cuando guarda una imagen semitransparente en un formato que no admite transparencias (por ejemplo, JPEG), los valores transparentes se reemplazan por negro.

Todo eso se suma a los bordes semi-negros (es decir, grises).

La forma correcta para eliminar esos artefactos es utilizar PixelOffsetMode.Half y utilizar un objeto ImageAttributes para especificar suelo de baldosas de borde de modo que el HighQualityBicubic muestreador tiene algo distinto de los píxeles transparentes a muestra.

Hay algunos otros problemas con el código que envió, así:

El Bitmap constructor que se utiliza es inicializar el nuevo Bitmap cambiando el tamaño de la imagen original, por lo que está haciendo la operación de cambio de tamaño dos veces. Debe usar una sobrecarga de constructor con solo las dimensiones deseadas para crear un lienzo en blanco.

Recuerde que la clase Bitmap representa una copia no administrada de la imagen en la memoria. Debe eliminarse para que se le pueda decir a GDI + que libere esa memoria cuando haya terminado con ella. Supongo que está haciendo eso en el código que recibe el retorno Image, pero lo señalo en caso de que alguien más tome prestado este código.

La configuración CompositingQuality.HighQuality utilizada en su código no tendrá ningún efecto visual si obtiene las otras configuraciones correctas y perjudicará el rendimiento bastante significativamente en combinación con el valor predeterminado de CompositingMode.SourceOver. Puede omitir la configuración CompositingQuality y establecer CompositingMode.SourceCopy para obtener los mismos resultados con un mejor rendimiento.

La configuración SmoothingMode utilizada en el código no tiene ningún impacto en DrawImage(), por lo que se puede quitar.

Puede leer más acerca de la configuración Graphics clase y su impacto en la calidad de imagen y rendimiento aquí: http://photosauce.net/blog/post/image-scaling-with-gdi-part-3-drawimage-and-the-settings-that-affect-it

El código revisado debería ser algo como esto:

public static Image Scale(Image sourceImage, int destWidth, int destHeight) 
{ 
    var toReturn = new Bitmap(destWidth, destHeight); 

    using (var graphics = Graphics.FromImage(toReturn)) 
    using (var attributes = new ImageAttributes()) 
    { 
     toReturn.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution); 

     attributes.SetWrapMode(WrapMode.TileFlipXY); 

     graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; 
     graphics.PixelOffsetMode = PixelOffsetMode.Half; 
     graphics.CompositingMode = CompositingMode.SourceCopy; 
     graphics.DrawImage(sourceImage, Rectangle.FromLTRB(0, 0, destWidth, destHeight), 0, 0, sourceImage.Width, sourceImage.Height, GraphicsUnit.Pixel, attributes); 
    } 

    return toReturn; 
} 
Cuestiones relacionadas