2011-01-21 27 views
7

Tengo que seguir la función que se llama para cambiar la resolución de una imagen. Quiero hacer esto para que la imagen cargada, por ejemplo, 300dpi se modifique a 72dpi (para web). Esta pregunta está relacionada con another question aquí en SO donde estoy trabajando.C# cambio de dpi de una imagen cargada

Estoy creando un método de extensión para que esto pueda usar esta función en más lugares en mi aplicación, en lugar de solo cuando cargue nuevos archivos. (Consulte la pregunta mencionada anteriormente)

public static byte[] SetDpiTo72(this byte[] imageToFit, string mimeType, Size newSize) 
{  
    using (MemoryStream memoryStream = new MemoryStream(), newMemoryStream = new MemoryStream()) 
    { 
     memoryStream.Write(imageToFit, 0, imageToFit.Length); 
     var originalImage = new Bitmap(memoryStream); 

     using (var canvas = Graphics.FromImage(originalImage)) 
     { 
      canvas.SmoothingMode = SmoothingMode.AntiAlias; 
      canvas.InterpolationMode = InterpolationMode.HighQualityBicubic; 
      canvas.PixelOffsetMode = PixelOffsetMode.HighQuality; 
      canvas.DrawImage((Image)originalImage,0,0, newSize.Width, newSize.Height); 

      newBitmap.SetResolution(72, 72); 
      newBitmap.Save(newMemoryStream, ImageFunctions.GetEncoderInfo(mimeType), null); 
     } 
     return newMemoryStream.ToArray(); 
    } 
} 

El método de extensión mencionado se está llamando en una función similar a la situación siguiente;

if (newSize.Width > originalImage.Width && newSize.Height > originalImage.Height) 
{ 
    newSize.Width = originalImage.Width; 
    newSize.Height = originalImage.Height; 

    uploadedFileBuffer = uploadedFileBuffer.SetDpiTo72(uploadedFile.ContentType, newSize); 

    return CreateFile(newSize, uploadedFile, uploadedFileBuffer); 
} 

El bytearray que entra es el archivo como bytearray. Ya tiene el tamaño correcto, pero quiero cambiar la resolución a 72 ppp. Sin embargo, después de la ejecución y guardar la imagen, la resolución sigue siendo la resolución original introducida, que es de 300 ppp. ¿Cómo puedo hacer esto?

ACTUALIZACIÓN DESPUÉS DE VARIAS RESPUESTAS:

public static byte[] SetDpiTo72(this byte[] imageToFit, string mimeType, Size newSize) 
     { 
      using (MemoryStream memoryStream = new MemoryStream(), newMemoryStream = new MemoryStream()) 
      { 
       memoryStream.Write(imageToFit, 0, imageToFit.Length); 
       var originalImage = new Bitmap(memoryStream); 

       using (var canvas = Graphics.FromImage(originalImage)) 
       { 
        canvas.SmoothingMode = SmoothingMode.AntiAlias; 
        canvas.InterpolationMode = InterpolationMode.HighQualityBicubic; 
        canvas.PixelOffsetMode = PixelOffsetMode.HighQuality; 
        canvas.DrawImage((Image)originalImage,0,0, newSize.Width, newSize.Height); 

        originalImage.SetResolution(72, 72); 

        var epQuality = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 75); 
        var epParameters = new EncoderParameters(1); 
        epParameters.Param[0] = epQuality; 

        Image newimg = Image.FromStream(memoryStream); 

        //Getting an GDI+ exception after the execution of this line. 
        newimg.Save("C:\\test1234.jpg", ImageFunctions.GetEncoderInfo(mimeType), epParameters); 

        originalImage.Save("test.jpg", ImageFormat.Jpeg); 

        //This line give me an Argumentexception - Parameter is not valid. 
        //originalImage.Save(newMemoryStream, ImageFunctions.GetEncoderInfo(mimeType), epParameters); 
        //newMemoryStream.Close(); 
       } 
       return newMemoryStream.ToArray(); 
      } 
     } 

El stackstrace que viene con la excepción de mí Esta está diciendo;

at System.Drawing.Image.Save(String filename, ImageCodecInfo encoder, EncoderParameters encoderParams) 
    at Extensions.ByteArrayExtensions.SetDpiTo72(Byte[] imageToFit, String mimeType, Size newSize) in C:\Website\Project\Extensions\ByteArrayExtensions.cs:line 356 
    at CMS.Presentation.FileFunctions.CreateFullsizeImage(HttpPostedFileBase uploadedFile, Size newSize, Byte[] uploadedFileBuffer) in C:\Website\Project\CMS.Presentation\FileFunctions.cs:line 197 
    at CMS.Presentation.FileFunctions.CreateFile(HttpPostedFileBase uploadedFile, INodeService nodeservice, Guid userId, Node parentNode) in C:\Website\Project\CMS.Presentation\FileFunctions.cs:line 53 

Mientras tanto, también desarrollé otra función (ver a continuación) cambiando el tamaño de solo un mapa de bits. Y esto parece funcionar correctamente. No puedo usar esta función con mi implementación actual porque devuelve solo un mapa de bits. ¿O debería cambiar todo para trabajar con bitmaps?

private static Bitmap ResizeImage(Image image, int width, int height) 
     { 
      var frameCount = image.GetFrameCount(new FrameDimension(image.FrameDimensionsList[0])); 
      var newDimensions = ImageFunctions.GenerateImageDimensions(image.Width, image.Height, width, height); 
      Bitmap resizedImage; 

      if (frameCount > 1) 
      { 
       //we have a animated GIF 
       resizedImage = ResizeAnimatedGifImage(image, width, height); 
      } 
      else 
      { 
       resizedImage = (Bitmap)image.GetThumbnailImage(newDimensions.Width, newDimensions.Height, null, IntPtr.Zero); 
      } 

      resizedImage.SetResolution(72,72); 

      return resizedImage; 
     } 
+1

¿Sabía que tiene un buen código circular allí? newBitmap = originalImage NO está COPYING. Es la única referencia a la misma imagen. Es curioso cómo todavía puede funcionar. – Euphoric

+0

jaja bueno! Se cambia ;-) – Rob

+0

Espera ... ¿realmente resolvió tu problema? – Euphoric

Respuesta

3

Me tomó un tiempo, pero finalmente encontré el problema. El problema mintió en la función ResizeImage que utilicé. En la 'GetThumbnailImage' para ser específico. Me encontré con otro problema con imágenes borrosas, que fue explicable porque GetThumbnailImage estiraría la ThumbNail creada al tamaño deseado. Y la resolución de la miniatura nunca cambia.

private static Bitmap ResizeImage(Image image, int width, int height) 
     { 
      var frameCount = image.GetFrameCount(new FrameDimension(image.FrameDimensionsList[0])); 
      var newDimensions = ImageFunctions.GenerateImageDimensions(image.Width, image.Height, width, height); 
      Bitmap resizedImage; 

      if (frameCount > 1) 
      { 
       //we have a animated GIF 
       resizedImage = ResizeAnimatedGifImage(image, width, height); 
      } 
      else 
      { 
       resizedImage = (Bitmap)image.GetThumbnailImage(newDimensions.Width, newDimensions.Height, null, IntPtr.Zero); 
      } 

      resizedImage.SetResolution(72,72); 

      return resizedImage; 
     } 

Mediante la modificación de la función de arriba a abajo la función pude resolver el problema con Graphics.DrawImage para volver a dibujar la nueva imagen antes de mostrarlos. También GenerateImageDimensions se modificó ligeramente. Esto tomado en conjunto, el problema fue resuelto.

private static Bitmap ResizeImage(Image image, int width, int height) 
     { 
      var frameCount = image.GetFrameCount(new FrameDimension(image.FrameDimensionsList[0])); 
      var newDimensions = ImageFunctions.GenerateImageDimensions(image.Width, image.Height, width, height); 

      var resizedImage = new Bitmap(newDimensions.Width, newDimensions.Height); 
      if (frameCount > 1) 
      { 
       //we have a animated GIF 
       resizedImage = ResizeAnimatedGifImage(image, width, height); 
      } 
      else 
      { 

       //we have a normal image 
       using (var gfx = Graphics.FromImage(resizedImage)) 
       { 
        gfx.SmoothingMode = SmoothingMode.HighQuality; 
        gfx.InterpolationMode = InterpolationMode.HighQualityBicubic; 
        gfx.PixelOffsetMode = PixelOffsetMode.HighQuality; 

        var targRectangle = new Rectangle(0, 0, newDimensions.Width, newDimensions.Height); 
        var srcRectangle = new Rectangle(0, 0, image.Width, image.Height); 

        gfx.DrawImage(image, targRectangle, srcRectangle, GraphicsUnit.Pixel); 
       } 
      } 

      return resizedImage; 
     } 
1

Al "cambiar la resolución", ¿realmente quiere decir que quiere reducir el número de píxeles de la imagen en 72/300? Es decir. cambiar una imagen de 4000x3000 a 960x720?

Si es así, no puedo ver dónde lo hace realmente tu código. El overload of DrawImage() you're using hace esto:

Dibuja la imagen especificada, utilizando su tamaño físico original, en la ubicación especificada por un par de coordenadas.

Que es exactamente lo que está sucediendo.

Trate one of the other overloads como this one:

dibuja la imagen especificada en la ubicación especificada y con el tamaño especificado.

por ejemplo:

// Create image. 
Image newImage = Image.FromFile("SampImag.jpg"); 

// Create coordinates for upper-left corner of image and for size of image. 
int x = 0; 
int y = 0; 
int width = 450; 
int height = 150; 

// Draw image to screen. 
e.Graphics.DrawImage(newImage, x, y, width, height); 

EDIT: por los comentarios, entiendo que el PO quiere reducir el tamaño del archivo sin reducir el número de píxeles. Por lo tanto, los archivos deben ser recomprimidos.

me ha pedido prestado un código de ejemplo de here:

ImageCodecInfo iciJpegCodec = null; 

// This will specify the image quality to the encoder. Change the value of 75 from 0 to 100, where 100 is best quality, but highest file size. 
EncoderParameter epQuality = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 75); 

// Get all image codecs that are available 
ImageCodecInfo[] iciCodecs = ImageCodecInfo.GetImageEncoders(); 

// Store the quality parameter in the list of encoder parameters 
EncoderParameters epParameters = new EncoderParameters(1); 
epParameters.Param[0] = epQuality; 

// Loop through all the image codecs 
for (int i = 0; i < iciCodecs.Length; i++) 
{ 
    // Until the one that we are interested in is found, which is image/jpeg 
    if (iciCodecs[i].MimeType == "image/jpeg") 
    { 
     iciJpegCodec = iciCodecs[i]; 
     break; 
    } 
} 

// Create a new Image object from the current file 
Image newImage = Image.FromFile(strFile); 

// Get the file information again, this time we want to find out the extension 
FileInfo fiPicture = new FileInfo(strFile); 

// Save the new file at the selected path with the specified encoder parameters, and reuse the same file name 
newImage.Save(outputPath + "\\" + fiPicture.Name, iciJpegCodec, epParameters); 
+0

Lo que realmente quiero es reducir el número de píxeles por pulgada en la imagen. Por ejemplo, si subo una imagen con el tamaño de 1181 x 1181 en 300 ppp, quiero que se guarde con el tamaño original de 1181 x 1181 pero con 72 ppp en lugar del original 300 – Rob

+0

. Acabo de ver que no estaba dando la imagen requerida. tamaño cuando se llama a la función drawimage. Intentaremos modificar esto ... – Rob

+0

Ah, reduciendo el valor de DPI en el archivo, en lugar del número total real de píxeles en la imagen. Lo siento, no estoy seguro de cuál es el problema entonces. Tenga en cuenta que el valor de "resolución" guardado en el archivo de imagen realmente no tiene ningún concepto significativo cuando la imagen se almacena digitalmente, esto solo entra en juego cuando se reproduce la imagen, ¿está seguro de que realmente necesita hacer esto? – tomfanning

0

Rob, creo que la cuestión con su código está en guardar la imagen - los datos de imagen digital real sería cierto número de puntos/píxeles es decir, (mxn) y la resolución de ajuste en mapa de bits no/no debería cambiar los puntos de número (y por lo tanto el tamaño de byte físico de la imagen). La información de resolución será almacenado en el encabezado de la imagen (para ser utilizado por los programas mientras que las imágenes de impresión/edición) - ¿Qué sucede si almacena el nuevo mapa de bits a presentar en lugar de mem transmitir

newBitmap.Save("c:\test.png", ImageFormat.Png); 

Comprobar dpi para archivos anterior de archivo -> propiedades -> resumen (avanzado). Debe ser de 72 dpi.

+0

Se intentará guardar el archivo en el sistema de archivos. Pero esta no puede ser una solución final. Necesito que se guarde en la base de datos porque al final del desarrollo de la aplicación – Rob

+0

he intentado su sugerencia, pero recibo una excepción GDI +. He actualizado la pregunta – Rob

2

Ok, lo intenté solo en archivos en disco duro, pero debería funcionar con transmisiones también.

 Bitmap bitmap = new Bitmap(loadFrom); 
     Bitmap newBitmap = new Bitmap(bitmap); 
     newBitmap.SetResolution(72, 72); 
     newBitmap.Save(saveTo); 
Cuestiones relacionadas