2012-11-15 3 views
8

ich eine Anforderung bekam keine Bilder hochgeladen weniger als 500kb in der Dateigröße zu komprimieren, ich habe auf Google gesucht und alles, was ich sehen kann:Python-Image-Bibliothek (PIL), wie wird das Bild in die gewünschte Dateigröße komprimiert?

>>> foo = foo.resize((160,300),Image.ANTIALIAS) 
>>> foo.save("path\\to\\save\\image_scaled.jpg",quality=95) 

Wenn ich mit diesem Ansatz gehen werde ich prüfen muss, ob die Bild ist weniger als 500 kb nach der Komprimierung, wenn nicht, dann für niedrigere Qualität und Größe gehen.

Gibt es einen besseren Weg, es zu tun?

+1

Eine bessere Möglichkeit, es zu tun ist, um die Qualität binärer Suche. Beginnen Sie also mit 50% Qualität, dann überprüfen Sie die Größe, wenn es zu klein ist, dann versuchen Sie 75%, sonst versuchen Sie 25%, etc. Sie werden so nah wie möglich an 500KB kommen, können Sie zusätzlich einige zusätzliche Parameter, z. Mindestqualität oder Größentoleranz. Sie sollten in der Lage sein, auf die korrekte Komprimierungsstufe in maximal 7 Iterationen auf Null zu setzen. –

Antwort

9

Die JPEG-Komprimierung ist vorher nicht vorhersehbar. Die Methode, die Sie beschrieben, komprimieren & Maßnahme & versuchen Sie es erneut, ist der einzige Weg, den ich kenne.

Sie können versuchen, eine Anzahl typischer Bilder mit unterschiedlichen Qualitätseinstellungen zu komprimieren, um eine Vorstellung von dem optimalen Startpunkt zu erhalten. Außerdem können Sie erraten, wie sich Änderungen an der Einstellung auf die Größe auswirken. Das bringt Sie auf die optimale Größe ohne zu viele Iterationen.

Sie können auch ein dateiähnliches Objekt an die save-Funktion übergeben, die nicht auf die Festplatte schreibt, sondern nur die Bytes zählt. Sobald Sie die besten Einstellungen festgelegt haben, können Sie sie erneut in einer tatsächlichen Datei speichern.

Edit: Hier ist eine Implementierung eines geeigneten Bytezählung Dateiobjekt. Überprüfen Sie einfach size nach dem Speichern.

class file_counter(object): 
    def __init__(self): 
     self.position = self.size = 0 

    def seek(self, offset, whence=0): 
     if whence == 1: 
      offset += self.position 
     elif whence == 2: 
      offset += self.size 
     self.position = min(offset, self.size) 

    def tell(self): 
     return self.position 

    def write(self, string): 
     self.position += len(string) 
     self.size = max(self.size, self.position) 

Edit 2: Hier ist eine binäre Suche, die oben mit der optimalen bekommen quality in der geringsten Anzahl von Versuchen.

def smaller_than(im, size, guess=70, subsampling=1, low=1, high=100): 
    while low < high: 
     counter = file_counter() 
     im.save(counter, format='JPEG', subsampling=subsampling, quality=guess) 
     if counter.size < size: 
      low = guess 
     else: 
      high = guess - 1 
     guess = (low + high + 1) // 2 
    return low 
3

Raten werde ich meinen Code hier bieten, so dass es hilfreich jemand das gleiche Problem sein könnte

class PhotoField(forms.FileField, object): 

    def __init__(self, *args, **kwargs): 
     super(PhotoField, self).__init__(*args, **kwargs) 
     self.help_text = "Images over 500kb will be resized to keep under 500kb limit, which may result in some loss of quality" 

    def validate(self,image): 
     if not str(image).split('.')[-1].lower() in ["jpg","jpeg","png","gif"]: 
      raise ValidationError("File format not supported, please try again and upload a JPG/PNG/GIF file") 

    def to_python(self, image): 
     limit = 500000 
     img = Image.open(image.file) 
     width, height = img.size 
     ratio = float(width)/float(height) 
     quality = 100 
     while len(image.file.read()) > limit: 
      width -= 100 
      quality -= 10 
      height = int(width/ratio) 
      img.resize((width, height), Image.ANTIALIAS) 
      img.save(image.file.name, "JPEG", quality=quality) 
      image.file = open(image.file.name) 
      # reset the file pointer to the beginning so the while loop can read properly 
      image.file.seek(0) 
     return image 

http://james.lin.net.nz/2012/11/19/django-snippet-reduce-image-size-during-upload/

Verwandte Themen