如何用Python检测和转换渐进式JPEG图片

2 投票
1 回答
1987 浏览
提问于 2025-04-16 05:57

我想用Python来检测渐进式JPEG图片,并把它们转换成非渐进式的。

(我正在写一个工具来管理安卓上的图片,而渐进式JPEG似乎会导致一些问题。)

1 个回答

2

我提前道个歉,因为我提供的是一个基于PHP的答案,而问题是关于Python的。不过,我觉得这个内容还是有价值的,可能会对你有帮助。

在尝试把渐进式图片转换为非渐进式之前,最好先有一个检测渐进式JPEG的办法。

下面是一个PHP函数,它可以做到这一点,实际上可以很容易地用其他语言重写(Python就是一个不错的选择),因为它读取的是二进制数据和JPEG标记,所以不依赖于特定语言的库。

    public function checkProgressiveJPEG($filepath) {
    $result = false;
    // $this->log = 'started analysis...';

    // http://en.wikipedia.org/wiki/Jpeg 
    // for more details on JPEG structure

    // SOI  [0xFF, 0xD8] = Start Of Image
    // SOF0 [0xFF, 0xC0] = Start Of Frame (Baseline DCT)
    // SOF2 [0xFF, 0xC2] = Start Of Frame (Progressive DCT)
    // SOS  [0xFF, 0xDA] = Start Of Scan

    if(file_exists($filepath)) {
        $fs = @fopen($filepath, "rb");

        $bytecount = 0;
        $byte_last = 0;
        $buffer = 0;
        $buffer_length = 4*1024;
        $begins_with_SOI = false;

        while($buffer = fread($fs, $buffer_length)) {

            // always carry over previous ending byte
            // just in case the buffer is read after a 0xFF marker
            if($byte_last) {
                $buffer = $byte_last.$buffer;
            }
            $byte_last = 0;
            preg_match("/\.$/", $buffer, $matches); 
            if(count($matches)) { 
                $byte_last = $matches[0];
            }

            // check if it begins with SOI marker
            if(!$begins_with_SOI) {
                preg_match("/^\\xff\\xd8/", $buffer, $matches); 
                if(count($matches)) { 
                    $begins_with_SOI = true;
                } else {
                    // $this->log = 'does not start with SOI marker';
                    $result = false;
                    break;
                }
            }

            // check if SOS or SOF2 is reached
            preg_match("/\\xff(\\xda|\\xc2)/", $buffer, $matches); 
            if(count($matches)) {
                if(bin2hex($matches[0]) == 'ffda') {
                    // $this->log = 'SOS is reached and SOF2 has not been detected, so image is not progressive.';
                    $result = false;
                    break;
                } else if(bin2hex($matches[0]) == 'ffc2') {
                    // $this->log = 'SOF2 is reached, so image is progressive.';
                    $result = true;
                    break;
                }

            } 
        } // end while

        fclose($fs);
    } // end if
    return $result;
}

撰写回答