11

ファイルサイズが500kb未満のアップロードされた画像を圧縮する必要がありました。グーグルで検索したところ、表示されるのは次のとおりです。

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

このアプローチを使用する場合は、圧縮後に画像が500kb未満であるかどうかを確認する必要があります。そうでない場合は、品質とサイズを低くしてください。

それを行うためのより良い方法はありますか?

4

2 に答える 2

11

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)

quality編集2:最小の試行回数で最適なものを取得するために、上記を使用した二分探索を次に示します。

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
于 2012-11-15T23:08:59.520 に答える
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/

于 2012-11-19T23:49:23.487 に答える