Respuesta

0

Depende de lo que están dispuestos a cambiar

  1. hacer que el tamaño de la imagen más pequeña
  2. cambiar el formato de la imagen
  3. Si el formato es compatible con una compresión con pérdida, disminución de la calidad
  4. Si va a guardar los meta-datos que no es necesario, y eliminar
  5. Reducir el número de colores (y bits por píxel)
  6. cambio a un formato de paleta
  7. cambio a un formato de paleta y reducir los colores

Es difícil de adivinar cuál será el tamaño del disco final, pero si se sabe que un punto de partida se puede obtener una muy buena estimación . La reducción del tamaño probablemente será proporcional, la reducción de los bits por píxel también será proporcional.

Si cambia el formato, la compresión o la calidad, es solo una suposición: depende en gran medida del contenido de la imagen.Probablemente puedas obtener un buen rango probándolo en un corpus de imágenes que coincida con lo que crees que estarás viendo.

7

Se puede calcular un nivel de información aproximada de la imagen al tomar el tamaño de la imagen original dividida por el número de píxeles:

info = fileSize/(width * height); 

tengo una imagen que es 369636 bytes y 1200x800 píxeles, por lo que utiliza ~ 0.385 bytes por pixel

Tengo una versión más pequeña que tiene 101111 bytes y 600x400 píxeles, por lo que usa ~ 0.4213 bytes por píxel.

Al reducir una imagen, verá que generalmente contendrá un poco más de información por píxel, en este caso aproximadamente un 9% más. Dependiendo de su tipo de imágenes y la cantidad que reducir su tamaño, debe ser capaz de calcular un promedio de la cantidad de la ración de la información/píxel aumenta (c), por lo que se puede calcular un tamaño aproximado:

newFileSize = (fileSize/(width * height)) * (newWidth * newHeight) * c 

de esto se puede extraer una fórmula para el tamaño que tiene que hacer una imagen para llegar a un tamaño de archivo específico:

newWidth * newHeight = (newFileSize/fileSize) * (width * height)/c 

esto le dará bastante cerca del tamaño de archivo deseado. Si desea acercarse, puede cambiar el tamaño de la imagen al tamaño calculado, comprimirla y calcular un nuevo valor de bytes por píxel a partir del tamaño del archivo que obtuvo.

1

Si se trata de una de 24 bits BMP creo que tendría que hacer algo como esto:

//initial size = WxH 
long bitsperpixel = 24; //for 24 bit BMP 
double ratio; 
long size = 2 * 1 << 20;//2MB = 2 * 2^20 
size -= 0x35;//subtract the BMP header size from it 
long newH, newW, left, right, middle,BMProwsize; 
left = 1; 
right = size;//binary search for new width and height 
while (left < right) 
{ 
    middle = (left + right + 1)/2; 
    newW = middle; 
    ratio = Convert.ToDouble(newW)/Convert.ToDouble(W); 
    newH = Convert.ToInt64(ratio * Convert.ToDouble(H)); 
    BMProwsize = 4 * ((newW * bitsperpixel + 31)/32); 
    //row size must be multiple of 4 
    if (BMProwsize * newH <= size) 
     left = middle; 
    else 
     right = middle-1;     
} 

newW = left; 
ratio = Convert.ToDouble(newW)/Convert.ToDouble(W); 
newH = Convert.ToInt64(ratio * Convert.ToDouble(H)); 
//resize image to newW x newH and it should fit in <= 2 MB 

Si se trata de un tipo BMP diferente como 8 bits BMP también en la sección de encabezado habrá más datos que especifican la el color real de cada valor de 0 a 255, por lo que deberá restar más del tamaño total del archivo antes de la búsqueda binaria.

2

Logré esto reduciendo la calidad hasta que alcancé mi tamaño deseado.

NB: Requiere que agregue la referencia de System.Drawing.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.IO; 
using System.Drawing; 
using System.Drawing.Imaging; 
using System.Drawing.Drawing2D; 

namespace PhotoShrinker 
{ 
class Program 
{ 
/// <summary> 
/// Max photo size in bytes 
/// </summary> 
const long MAX_PHOTO_SIZE = 409600; 

static void Main(string[] args) 
{ 
    var photos = Directory.EnumerateFiles(Directory.GetCurrentDirectory(), "*.jpg"); 

    foreach (var photo in photos) 
    { 
     var photoName = Path.GetFileNameWithoutExtension(photo); 

     var fi = new FileInfo(photo); 
     Console.WriteLine("Photo: " + photo); 
     Console.WriteLine(fi.Length); 

     if (fi.Length > MAX_PHOTO_SIZE) 
     { 
      using (var image = Image.FromFile(photo)) 
      { 
        using (var stream = DownscaleImage(image)) 
        { 
         using (var file = File.Create(photoName + "-smaller.jpg")) 
         { 
          stream.CopyTo(file); 
         } 
        } 
      } 
      Console.WriteLine("File resized."); 
     } 
     Console.WriteLine("Done.") 
     Console.ReadLine(); 
    } 

} 

private static MemoryStream DownscaleImage(Image photo) 
{ 
    MemoryStream resizedPhotoStream = new MemoryStream(); 

    long resizedSize = 0; 
    var quality = 93; 
    //long lastSizeDifference = 0; 
    do 
    { 
     resizedPhotoStream.SetLength(0); 

     EncoderParameters eps = new EncoderParameters(1); 
     eps.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)quality); 
     ImageCodecInfo ici = GetEncoderInfo("image/jpeg"); 

     photo.Save(resizedPhotoStream, ici, eps); 
     resizedSize = resizedPhotoStream.Length; 

     //long sizeDifference = resizedSize - MAX_PHOTO_SIZE; 
     //Console.WriteLine(resizedSize + "(" + sizeDifference + " " + (lastSizeDifference - sizeDifference) + ")"); 
     //lastSizeDifference = sizeDifference; 
     quality--; 

    } while (resizedSize > MAX_PHOTO_SIZE); 

    resizedPhotoStream.Seek(0, SeekOrigin.Begin); 

    return resizedPhotoStream; 
} 

private static ImageCodecInfo GetEncoderInfo(String mimeType) 
{ 
    int j; 
    ImageCodecInfo[] encoders; 
    encoders = ImageCodecInfo.GetImageEncoders(); 
    for (j = 0; j < encoders.Length; ++j) 
    { 
     if (encoders[j].MimeType == mimeType) 
      return encoders[j]; 
    } 
    return null; 
} 
} 
} 
+0

gracias, gran muestra de trabajo. Lo cambié para bajar la calidad 5 unidades a la vez y lo usé en mi asp.net –

+1

¡Me alegra poder ayudar a alguien más! ¡Noté que el Image.FromFile (foto) no se estaba desechando correctamente! Actualicé mi código para desecharlo correctamente. –

Cuestiones relacionadas