이미지 크기를 얻는 빠른 방법 (파일 크기가 아님)


138

이미지의 높이와 너비를 픽셀 단위로 얻는 빠른 방법을 찾고 있습니다. 최소한 JPG, PNG 및 TIFF를 처리해야하지만 더 좋습니다. 내 이미지가 매우 커서 (최대 250MB) 빠르고 ImageMagick을 사용하여 크기를 얻는 데 시간이 오래 걸리므 identify로 이미지를 전체적으로 먼저 읽기 때문에 빠르게 강조 합니다.

가급적이면 Ruby 나 Rails 3에서 잘 작동하는 방식을 찾습니다.

나는 이론적 인 것들 (다양한 이미지 형식, 헤더 및 차이점 등)을 알고 있습니다. 사실, 상당히 일반적인 방식으로 문제를 해결할 수있는 일종의 라이브러리를 요청합니다.

난 그냥 발견 imagesize 개발이 죽은 것 같다하지만 약속 보인다.


8
새로운 버전의 ImageMagick에는 해당되지 않습니다. ImageMagick 6.5.4-7 사용 식별 (적어도 TIF 및 PNG의 경우)은 헤더 (최대 60KB) 만 읽고 335MB 이미지에서도 매우 빠르게 작동한다는 것을 확인했습니다.
— coderforlife

답변:


195
  • 이 file명령은 여러 이미지 형식 (예 : PNG, GIF, JPEG; 최신 버전도 PPM, WEBP)의 치수를 인쇄하고 헤더 만 읽습니다.

  • identifyImageMagick 의 명령 은 다양한 이미지에 대한 많은 이미지 정보를 인쇄합니다. 헤더 부분을 읽는 데 자제하는 것처럼 보입니다 (주석 참조). 또한 file슬프게도 부족한 통합 출력 이 있습니다.

  • exiv2EXIF 헤더가없는 경우에도 JPEG, TIFF, PNG, GIF, WEBP 등 다양한 형식의 치수를 제공합니다. 그래도 전체 데이터를 읽는지 확실하지 않습니다. 지원되는 모든 이미지 형식은 exiv2 맨 페이지를 참조하십시오.

  • head -n1 PPM, PGM 형식의 크기를 알려줍니다.

형식을 웹에 인기, 모두 exiv2와 identify일을 할 것입니다. 사용 사례에 따라 여러 도구의 출력을 결합 / 파싱하는 자체 스크립트를 작성해야 할 수도 있습니다.


3
ImageMagick 식별 명령으로 strace를 사용하여 식별 된 이미지에서 읽은 데이터 양을 확인하기 위해 open / read / mmap / close 호출을 기록하는 몇 가지 테스트를 수행했습니다. 파일 형식과 파일 크기에 따라 약간 씩 다르지만 5-335MB 이미지에 대해 "identify"로 20-60KB를 읽었습니다 (또한 모든 바이트를 읽은 것으로 표시된 "convert"에 대해 테스트했습니다). 따라서 여기에서 "identify"가 좋은 선택 인 것 같습니다 (모든 대중적인 형식을 지원하고 헤더 만 읽으므로).
— coderforlife

1
exiv2도 PNG를 사용한다고 생각합니다.
— chx

파일 명령 출력을 쉽게 구문 분석하는 방법은 무엇입니까? 확인 훌륭하지만 WebP 형식을 가진 작품은 슬프게도 파일을하지 않습니다
— 브라이언 Leishman

식별 은 WebP와 함께 작동하며 ImageMagick은 수년간 WebP를 지원합니다. 아마도 업데이트를받을 수 있습니까?
— ypnos

32

PHP가 설치되어 있는지 확실하지 않지만이 PHP 기능은 매우 편리합니다.

 php -r "print_r(getimagesize('http://www.google.com/images/logos/ps_logo2.png'));"

1
이것은 "식별"보다 훨씬 빠릅니다. 좋은 접근 방식. 감사.
— souravb

19

ImageMagick의 식별 기능을 사용할 수 있습니다 . bash에서 수행하는 방법은 다음과 같습니다 (참고 $ 0는 이미지의 경로입니다).

width=$(identify -format "%w" "$0")> /dev/null
height=$(identify -format "%h" "$0")> /dev/null

그리고 이것은 잠재적 인 오류 메시지도 숨 깁니다. 현대적인 구현은 identify전체 이미지가 아닌 헤더 만 읽으므로 빠릅니다. 그래도 다른 방법과 비교하여 확실하지 않습니다.


2
이 방법이 훨씬 더 효율적이라고 생각합니다.read width height < <(identify -format "%w %h" "${1}")
— Cromax

5

https://joseluisbz.wordpress.com/2013/08/06/obtaining-size-or-dimension-of-images/ (BMP, PNG, GIF, JPG, TIF 또는 WMF)

PNG와 JPG의 두 가지 형식이 있습니다.

내 코드는 내가 사용하도록 설계된 클래스에서 가져온 것이므로 필요에 따라 편집 할 수 있습니다.

PHP를 사용하여 이러한 기능 / 방법을 확인하십시오 .

  public function ByteStreamImageString($ByteStream,&$Formato,&$Alto,&$Ancho) {
    $Alto = 0;
    $Ancho = 0;
    $Formato = -1;
    $this->HexImageString = "Error";
    if (ord($ByteStream[0])==137 && ord($ByteStream[1])==80 && ord($ByteStream[2])==78){
      $Formato = 1; //PNG
      $Alto = $this->Byte2PosInt($ByteStream[22],$ByteStream[23]);
      $Ancho = $this->Byte2PosInt($ByteStream[18],$ByteStream[19]);
    }
    if (ord($ByteStream[0])==255 && ord($ByteStream[1])==216
        && ord($ByteStream[2])==255 && ord($ByteStream[3])==224){
      $Formato = 2; //JPG
      $PosJPG = 2;
      while ($PosJPG<strlen($ByteStream)){
        if (sprintf("%02X%02X", ord($ByteStream[$PosJPG+0]),ord($ByteStream[$PosJPG+1]))=="FFC0"){
          $Alto = $this->Byte2PosInt($ByteStream[$PosJPG+5],$ByteStream[$PosJPG+6]);
          $Ancho = $this->Byte2PosInt($ByteStream[$PosJPG+7],$ByteStream[$PosJPG+8]);
        }
        $PosJPG = $PosJPG+2+$this->Byte2PosInt($ByteStream[$PosJPG+2],$ByteStream[$PosJPG+3]);
      }
    }
    if ($Formato > 0){
      $this->HexImageString = "";
      $Salto = 0;
      for ($i=0;$i < strlen($ByteStream); $i++){
        $Salto++;
        $this->HexImageString .= sprintf("%02x", ord($ByteStream[$i]));
        if ($Salto==64){
          $this->HexImageString .= "\n";
          $Salto = 0;
        }
      }
    }
  }


  private function Byte2PosInt($Byte08,$Byte00) {
    return ((ord($Byte08) & 0xFF) << 8)|((ord($Byte00) & 0xFF) << 0);
  }

PHP 코드 사용하기 :

      $iFormato = NULL;//Format PNG or JPG
      $iAlto = NULL; //High
      $iAncho = NULL;//Wide
      ByteStreamImageString($ImageJPG,$iFormato,$iAlto,$iAncho);//The Dimensions will stored in  iFormato,iAlto,iAncho

이제 JAVA를 사용하는 이러한 함수 / 방법 :

  private void ByteStreamImageString(byte[] ByteStream,int[] Frmt,int[] High,int[] Wide) {
    High[0] = 0;
    Wide[0] = 0;
    Frmt[0] = -1;
    this.HexImageString = "Error";
    if ((int)(ByteStream[0]&0xFF)==137 && (int)(ByteStream[1]&0xFF)==80 &&(int)(ByteStream[2]&0xFF)==78){
      Frmt[0] = 1; //PNG
      High[0] = this.Byte2PosInt(ByteStream[22],ByteStream[23]);
      Wide[0] = this.Byte2PosInt(ByteStream[18],ByteStream[19]);
    }
    if ((int)(ByteStream[0]&0xFF)==255 && (int)(ByteStream[1]&0xFF)==216
        &&(int)(ByteStream[2]&0xFF)==255 && (int)(ByteStream[3]&0xFF)==224){
      Frmt[0] = 2; //JPG
      int PosJPG = 2;
      while (PosJPG<ByteStream.length){
        if (String.format("%02X%02X", ByteStream[PosJPG+0],ByteStream[PosJPG+1]).equals("FFC0")){
          High[0] = this.Byte2PosInt(ByteStream[PosJPG+5],ByteStream[PosJPG+6]);
          Wide[0] = this.Byte2PosInt(ByteStream[PosJPG+7],ByteStream[PosJPG+8]);
        }
        PosJPG = PosJPG+2+this.Byte2PosInt(ByteStream[PosJPG+2],ByteStream[PosJPG+3]);
      }
    }
    if (Frmt[0] > 0){
      this.HexImageString = "";
      int Salto = 0;
      for (int i=0;i < ByteStream.length; i++){
        Salto++;
        this.HexImageString += String.format("%02x", ByteStream[i]);
        if (Salto==64){
          this.HexImageString += "\n";
          Salto = 0;
        }
      }
    }
  }


  private Integer Byte2PosInt(byte Byte08, byte Byte00) {
    return new Integer (((Byte08 & 0xFF) << 8)|((Byte00 & 0xFF) << 0));
  }

자바 코드 사용하기 :

        int[] iFormato = new int[1]; //Format PNG or JPG
        int[] iAlto = new int[1]; //High
        int[] iAncho = new int[1]; //Wide
        ByteStreamImageString(ImageJPG,iFormato,iAlto,iAncho); //The Dimensions will stored in  iFormato[0],iAlto[0],iAncho[0]

난 당신이 얻을 수있는 해킹으로 인수 배열을 사용하고 참조 ref/ out모범 사례 간주됩니다 - 자바에서 매개 변수를?
— Dai

이 답변은 매우 오래되었으므로 지금은 기꺼이 업데이트하지 않지만 (많은 것을 잊어 버리고 시간이 없었습니다) 코드를 확인하고 편집 할 수 있습니다.
— joseluisbz


이 예제에서는 Format, High 및 Width라는 3 개의 필드가있는 새 클래스를 구현하여이 클래스의 인스턴스를 반환하는 것이 좋습니다.
— joseluisbz 1

1

원하는 픽셀 크기 (너비와 높이)입니다.

대부분의 파일 형식에는 크기를 정의하는 헤더 정보가 있으므로 파일을 읽는 소프트웨어가 파일을 읽기 전에 예약해야 할 공간을 알 수 있다고 생각합니다. 일부 "raw"형식 파일 형식은 각 수평 행 행의 끝에 일부 "줄 끝"바이트가있는 바이트 스트림 일 수 있습니다 (이 경우 소프트웨어는 첫 번째 행을 읽고 바이트 스트림의 크기를 나누어야합니다) 높이를 얻으려면 줄 길이로).

파일을 읽는 방법을 알기 위해 파일 형식을 이해하거나 라이브러리를 사용해야하기 때문에 "일반적인"방식으로 이것을 만들 수 있다고 생각하지 않습니다. 대부분의 경우 전체 파일을 읽지 않고도 대략적인 크기를 추정 할 수있는 코드를 찾을 수 있지만 일부 파일 형식을 사용하면 전체 파일을 읽어야 실제로 어떤 크기인지 확인할 수 있습니다. 대부분의 웹 중심 이미지 형식에는 이러한 정보가 포함 된 헤더가 있으므로 전체 이미지가로드되기 전에 브라우저가 상자 크기를 만들 수 있습니다.

좋은 라이브러리에는 처리하는 파일의 크기를 가져 오는 몇 가지 방법이 있으며 그 방법은 가능한 한 효율적으로 구현 될 것입니다.

업데이트 : imageinfo 는 원하는 것을하는 것처럼 보입니다. (테스트하지 않았습니다)


그 도구는 내가 필요로하는 한 빨리 작동합니다.). 제대로 사용할 수 있는지 살펴 보겠습니다.
— dAnjou

0

이미지에 EXIF ​​정보가 있으면 EXIF ​​헤더를 읽을 수 있습니다.


불행히도 나는 어떤 종류의 이미지가 있고 EXIF ​​데이터가 있는지 여부를 알 수 없습니다.
— dAnjou

3
얼마나 많은 이미지의 DO 정보가? 90 %의 EXIF ​​데이터가있는 경우 다른 10 %에서 ImageMagick을 사용하는 속도가 느려질 수 있습니다.
— Andy Lester

이 답변에 다운 보트가있는 이유는 무엇입니까? 질문에 대한 올바른 답변이며 OP 또는 다른 사람이 찾고있는 것일 수도 있습니다.
— Will Sheppard

0

-ping 은 해당 목적을 위해 도입 된 것으로 보이는 옵션입니다.

그러나 ImageMagick 6.7.7부터 모든 큰 파일의 경우에도 속도 저하가 관찰되지 않습니다.

head -c 100000000 /dev/urandom > f.gray
# I don't recommend that you run this command as it eats a lot of memory.
convert -depth 8 -size 20000x10000 f.gray f.png
identify f.png

여전히 느린 입력 이미지 예를 만들 수 있습니까?


0

tldr : 파일 "imagename"은

webp, 모든 jpg 형식 (jpeg, jpg200, ..)과 호환

샘플 출력은 다음과 같습니다

JPEG 이미지 데이터, JFIF 표준 1.02, 종횡비, 밀도 1x1, 세그먼트 길이 16, 기준선, 정밀도 8, 650x400, 프레임 3

파일의 출력을 파이썬 목록에로드하고 목록의 4 번째 필드를 사용하십시오.

참고로, 네트워크 트래픽을 줄이기 위해 약 18000 개 이상의 이미지를 최적화했습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.