2012-11-15 2 views
8

私は小さいファイルサイズで500キロバイトよりも、私はGoogleで検索しましたし、私が見ることができるすべてがある任意のアップロードした画像を圧縮するための要件を得た:Pythonイメージライブラリ(PIL)は、イメージを希望のファイルサイズに圧縮する方法ですか?

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

私はこの方法で行く場合は、私がいるかどうかをチェックする必要があります圧縮後の画像が500kb未満である場合は、品質とサイズが低くなります。

良い方法がありますか?

+1

を持つ有用誰かかもしれないので、私はここに私のコードを提供しますゲス。したがって、50%の品質で始まり、サイズが小さすぎる場合は75%を試し、そうでない場合は25%を試してください。可能な限り500KBに近づくでしょう。最小の品質またはサイズの許容差。最大7回の反復で正しい圧縮レベルにゼロインすることができます。 –

答えて

9

事前にJPEG圧縮を予測することはできません。あなたが説明した方法は、私が知っている唯一の方法です、再度&測定&を試してください。

さまざまな画質設定でいくつかの一般的な画像を圧縮し、最適な開始点を知り、設定の変更がどのようにサイズに影響するかを推測することができます。それは、あまりにも多くの反復をせずに最適なサイズでゼロになるでしょう。

ファイルに似たオブジェクトをsave関数に渡すこともできます。この関数は、ディスクに書き込むのに気にせず、バイト数を数えるだけです。最適な設定を決定したら、それを実際のファイルに再度保存することができます。

編集:ここには、適切なバイトカウントファイルオブジェクトの実装があります。保存後にsizeをチェックするだけです。

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) 

編集2:ここでは試行の最小回数で最適qualityを取得するために、上記を使用してバイナリ検索です。

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

は、それはそれを行うには良い方法は、高品質の検索バイナリにある同じ問題

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/

関連する問題