Как обнаружить и конвертировать прогрессивные JPEG с Python - PullRequest
2 голосов
/ 23 октября 2010

Я хотел бы иметь возможность обнаруживать прогрессивные jpeg-файлы с помощью python и преобразовывать их в непрогрессивные.

(я пишу инструмент для управления изображениями для android, и прогрессивные jpegs, похоже, ломают его.)

1 Ответ

2 голосов
/ 16 марта 2013

Я заранее прошу прощения за предоставление ответа на основе php, тогда как вопрос был задан о python.Тем не менее, я думаю, что это добавляет ценность и может быть полезным.Прежде чем пытаться преобразовать прогрессивное изображение в непрогрессивное, хорошо бы иметь метод обнаружения для прогрессивного JPEG.

Вот функция php, которая делает это, может быть легко переписана на других языкахкандидат), так как он читает двоичные данные и маркеры 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;
}
...