Odpowiedz

0

To zależy od tego, co jesteś gotów zmienić

  1. Dokonać rozmiar obrazu mniejszy
  2. zmienić format obrazu
  3. Jeśli format obsługuje kompresję stratną, obniżają jakość
  4. Jeśli przechowywania meta-danych, że nie potrzeba, należy go usunąć
  5. Zmniejsz liczbę kolorów (i bity na piksel)
  6. Zmiana do paletted formacie
  7. zmienić na paletted formacie i zmniejszyć kolory

Trudno odgadnąć, co ostateczny rozmiar dysku będzie, ale jeśli wiesz, punkt wyjścia można uzyskać bardzo dobrą ocenę . Zmniejszenie rozmiaru będzie prawdopodobnie proporcjonalne, zmniejszenie bitów na piksel będzie również prawdopodobnie proporcjonalne.

Jeśli zmienisz format, kompresję lub jakość, będzie to po prostu domysły - w dużej mierze zależy od zawartości obrazu.Prawdopodobnie możesz uzyskać dobry zasięg, próbując go na korpusie obrazów pasujących do tego, co myślisz, że zobaczysz.

7

można obliczyć przybliżony poziom informacyjny dla obrazu poprzez oryginalny rozmiar obrazu podzielonego przez liczbę pikseli:

info = fileSize/(width * height); 

Mam obrazu, który jest 369636 bajtów i 1200x800 pikseli, więc używa ~ 0,385 bajtów na piksel.

Mam mniejszą wersję, która ma 101111 bajtów i 600 x 400 pikseli, więc używa ~ 0,4213 bajtów na piksel.

Po zmniejszeniu obrazu zobaczysz, że generalnie będzie zawierać nieco więcej informacji na piksel, w tym przypadku około 9% więcej. W zależności od rodzaju obrazu i jak bardzo ich kurczyć, powinieneś być w stanie obliczyć średnią za ile wzrasta informacje/piksel racja (C), tak aby można było obliczyć przybliżoną wielkość pliku:

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

Od tego można wyodrębnić formułę jak duże trzeba zrobić zdjęcie, aby osiągnąć konkretny rozmiar pliku:

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

to będzie Ci bardzo blisko do pożądanego rozmiaru. Jeśli chcesz zbliżyć się, możesz zmienić rozmiar obrazu na wyliczony rozmiar, skompresować go i obliczyć nową liczbę bajtów na piksel z rozmiaru pliku, który masz.

1

Jeśli jest to 24bit BMP myślę, że trzeba zrobić coś takiego:

//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 

Jeśli jest to inny rodzaj BMP jak 8 bit BMP również w sekcji nagłówka nie będzie więcej danych określających rzeczywisty kolor każdej wartości od 0 do 255, więc musisz odjąć więcej od całkowitego rozmiaru pliku przed przeszukiwaniem binarnym.

2

Osiągnąłem to poprzez obniżenie jakości, aż osiągnąłem pożądany rozmiar.

NB: Wymaga dodania odniesienia do 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

dziękuję, świetnie działająca próbka. zmieniłem go, aby obniżyć jakość 5 jednostek na raz i użyłem go w moim asp.net –

+1

Cieszę się, że mogę pomóc komuś innemu! Zauważyłem, że plik Image.FromFile (zdjęcie) nie został poprawnie usunięty! Zaktualizowałem swój kod, aby prawidłowo się pozbyć. –

Powiązane problemy