如何使用python检测和转换渐进式jpeg

时间:2010-10-23 00:02:15

标签: python image image-manipulation jpeg

我希望能够使用python检测渐进式jpeg并将它们转换为非渐进式。

(我正在编写一个管理Android图像的工具,渐进式jpegs似乎打破了它。)

1 个答案:

答案 0 :(得分: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;
}