2016-02-15 36 views
5

Pracuję z Pillow, Django i django-imagekit.Jak przekonwertować obraz do określonego rozmiaru pliku?

Szukam, aby móc mieć pole modelu obrazu profilowego (prawdopodobnie przy użyciu klasy ProcessedImageField z imagekit), które będzie pobierać dowolny obraz, konwertować do formatu JPEG, przycinać do rozmiaru 150 x 150 i tworzyć jego rozmiar 5 KB.

Pierwsze dwa są proste:

profile_picture = imagekit.models.ProcessedImageField(upload_to=get_profile_picture_file_path, 
                 format='JPEG', 
                 processors=[ResizeToFill(height=150, width=150)] 
                ) 

Ale w jaki sposób można upewnić się, że rozmiar pliku jest 5KB? Mógłbym użyć czegoś takiego jak parametr options={'quality': 60} w ProcessedImageField, ale wydaje się, że jest to tylko względne w stosunku do oryginalnego rozmiaru pliku (według mojej wiedzy).

Rozwiązania nie muszą używać django-imagekit, ale byłoby to preferowane.

Odpowiedz

0

Może w taki sposób. Sprawdzić rozmiar obrazu po przesłanych i usunąć ją lub zmniejszać więcej w zastąpionej save metody:

class Images(models.Model): 
    profile_picture = imagekit.models.ProcessedImageField(upload_to=get_profile_picture_file_path, 
                format='JPEG', 
                processors=[ResizeToFill(height=150, width=150)] 
               ) 

    def save(self, force_insert=False, force_update=False, using=None, 
      update_fields=None): 

     if os.stat(get_profile_picture_file_path + "/" + self.profile_picture.new_name).st_size > max_size: 
      do_something_further_image_processing_to_decrease_size 

     super(Images, self).save() 
+0

jest to dobry początek na sprawdzeniu, czy plik jest zbyt duży, ale logika w 'do_something_further_image_processing_to_decrease_size' jest naprawdę odpowiednia część pytania. Jak możesz zapewnić, że zmniejszasz rozmiar pliku do określonego rozmiaru za każdym razem (nawet przy obrazach o różnych rozdzielczościach/jakości JPEG)? – dcgoss

+0

Prawdopodobnie dodaję tutaj funkcję iteracyjną, która zmniejsza rozdzielczość o 10% lub inny współczynnik odpowiadający bieżącemu rozmiarowi produkowanego obrazu w każdej iteracji. 'PIL' daje taką możliwość. – Magnar

0

Kiedyś miałem podobny problem, więc postanowiłem do optymalizacji obrazów przy użyciu narzędzi systemu operacyjnego (jpegoptim, optipng, itp) wywoływane z django po zapisaniu modelu za pomocą sygnałów (możesz też zmienić metodę zapisu). Te narzędzia optymalizują i eliminują metadane ze zdjęć. Z drugiej strony można zbadać średni współczynnik kompresji i rozmiar plików jpg o wymiarach 150x150 i spróbować odgadnąć najlepszą jakość konfiguracji: (jpeg compression ratio)

To jest mój kod do optymalizacji plików po zapisaniu ich, ja ' m przy użyciu prostych miniaturkami biblioteki, która zapewni mi sygnały po zapisać:

@receiver(saved_file) 
def optimize_file(sender, fieldfile, **kwargs): 
    optimize(fieldfile.path) 


# thumbnail optimization 
@receiver(thumbnail_created) 
def optimize_thumbnail(sender, **kwargs): 
    optimize(sender.path) 

def optimize(path): 
    """ 
    install image utilities 
    apt-get install jpegoptim optipng pngcrush advancecomp 
    :param path: 
    :return: 
    """ 
    # taken from trimage (http://trimage.org/) 
    runString = { 
     ".jpeg": u"jpegoptim -f --strip-all '%(file)s' ; chmod 644 '%(file)s'", 
     ".jpg": u"jpegoptim -f --strip-all '%(file)s' ; chmod 644 '%(file)s'", 
     ".png": u"optipng -force -o7 '%(file)s' && advpng -z4 '%(file)s' && pngcrush -rem gAMA -rem alla -rem cHRM -rem iCCP -rem sRGB -rem time '%(file)s' '%(file)s.bak' && mv '%(file)s.bak' '%(file)s' ; chmod 644 '%(file)s'" 
    } 

    ext = splitext(path)[1].lower() 
    if ext in runString: 
     subprocess.Popen(runString[ext] % {'file': path}, shell=True)