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


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 형식의 크기를 알려줍니다.

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


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.