วิธีรับขนาดภาพที่รวดเร็ว (ไม่ใช่ขนาดไฟล์)


138

ฉันกำลังมองหาวิธีที่รวดเร็วเพื่อให้ได้ความสูงและความกว้างของรูปภาพเป็นพิกเซล ควรจัดการอย่างน้อย JPG, PNG และ TIFF แต่ยิ่งดี ฉันเน้นอย่างรวดเร็วเพราะภาพของฉันมีขนาดค่อนข้างใหญ่ (สูงถึง 250 MB) และใช้เวลานานในการเพิ่มขนาดด้วย ImageMagick identifyเพราะเห็นได้ชัดว่าเป็นการอ่านภาพโดยรวมก่อน

โดยเฉพาะอย่างยิ่งฉันมองหาวิธีที่ทำงานได้ดีใน Ruby หรือแม้แต่ใน Rails 3

ฉันรู้ว่าสิ่งต่าง ๆ ทางทฤษฎี (รูปแบบภาพต่างๆส่วนหัวและความแตกต่างของพวกเขาและอื่น ๆ ) อันที่จริงฉันขอห้องสมุดบางประเภทที่สามารถแก้ไขปัญหาของฉันในทางที่ค่อนข้างทั่วไป

ฉันเพิ่งพบภาพขนาดย่อที่ดูมีแนวโน้มแม้ว่าการพัฒนาดูเหมือนว่าจะตาย


8
สิ่งนี้ดูเหมือนจะไม่เป็นจริงสำหรับ ImageMagick รุ่นใหม่ การใช้ ImageMagick 6.5.4-7 ฉันได้ยืนยันแล้วว่าการระบุ (อย่างน้อยสำหรับ TIF และ PNG) จะอ่านเฉพาะส่วนหัว (สูงสุด 60KB) และทำงานได้อย่างรวดเร็วแม้กระทั่งภาพขนาด 335MB
coderforlife

คำตอบ:


195
  • fileคำสั่งพิมพ์ขนาดสำหรับรูปแบบภาพหลาย (เช่น PNG, GIF, JPEG; รุ่นล่าสุดยัง PPM, WEBP) และไม่เพียง แต่อ่านส่วนหัว

  • identifyคำสั่ง (จาก ImageMagick) พิมพ์จำนวนของข้อมูลที่ภาพเพื่อดูความหลากหลายของภาพ ดูเหมือนว่าจะยับยั้งตัวเองเพื่ออ่านส่วนหัว (ดูความคิดเห็น) นอกจากนี้ยังมีการส่งออกครบวงจรซึ่งfileเศร้าขาด

  • exiv2ให้มิติสำหรับหลาย ๆ รูปแบบรวมถึง JPEG, TIFF, PNG, GIF, WEBP แม้ว่าจะไม่มีส่วนหัว EXIF ​​ก็ตาม มันไม่ชัดเจนว่ามันจะอ่านข้อมูลทั้งหมดสำหรับที่แม้ว่า ดู manpage ของ exiv2 สำหรับรูปแบบภาพที่รองรับทั้งหมด

  • head -n1 จะให้มิติสำหรับรูปแบบ PPM, PGM

สำหรับรูปแบบที่เป็นที่นิยมบนเว็บทั้งคู่exiv2และidentifyจะทำงาน ขึ้นอยู่กับกรณีการใช้งานคุณอาจต้องเขียนสคริปต์ของคุณเองที่รวม / แยกวิเคราะห์ผลลัพธ์ของเครื่องมือต่างๆ


3
ฉันได้ทำการทดสอบบางอย่างด้วยคำสั่ง ImageMagick identifier โดยใช้ strace เพื่อบันทึกการโทรแบบเปิด / อ่าน / mmap / close เพื่อดูว่ามีการอ่านข้อมูลจำนวนมากจากภาพที่ระบุ มันขึ้นอยู่กับประเภทไฟล์และขนาดไฟล์เล็กน้อย แต่ฉันได้รับ 20-60 KB อ่านโดย "ระบุ" สำหรับภาพ 5-335 MB (ฉันทดสอบกับ "แปลง" ซึ่งแสดงให้เห็นว่ามีการอ่านไบต์ทั้งหมด) ดังนั้นดูเหมือนว่า "ระบุ" เป็นตัวเลือกที่ดีที่นี่ (เนื่องจากรองรับรูปแบบที่นิยมทั้งหมดและอ่านเฉพาะส่วนหัว)
coderforlife

1
ฉันคิดว่า exiv2 ก็ทำ PNG เช่นกัน
chx

วิธีใดในการแยกคำสั่งไฟล์ที่ส่งออกได้อย่างง่ายดาย ระบุได้ดี แต่ไม่สามารถใช้งานกับไฟล์ WebP ได้อย่างน่าเศร้า
Brian 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));
  }

ใช้รหัส Java:

        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พารามิเตอร์ใน Java - นั่นถือเป็นแนวปฏิบัติที่ดีที่สุดหรือไม่?
Dai

คำตอบนี้เก่ามากตอนนี้ฉันไม่เต็มใจที่จะอัพเดท (ฉันลืมสิ่งต่าง ๆ มากมายและฉันไม่มีเวลา) แต่คุณสามารถตรวจสอบรหัสและแก้ไขได้
joseluisbz

joseluisbz.wordpress.com/2013/07/26/… (คำอธิบายสำหรับ WMF)
joseluisbz

สำหรับตัวอย่างนี้ฉันแนะนำให้ใช้คลาสใหม่ที่มี 3 ฟิลด์, รูปแบบ, สูงและกว้าง, ส่งคืนอินสแตนซ์ของคลาสนี้
joseluisbz

1

มันคือขนาดพิกเซลที่คุณต้องการ (ความกว้างและความสูง) ฉันจะถือว่า

ฉันคิดว่ารูปแบบไฟล์ส่วนใหญ่มีข้อมูลส่วนหัวที่กำหนดขนาดเพื่อให้ซอฟต์แวร์ที่อ่านไฟล์สามารถรู้ว่าต้องจองพื้นที่เท่าใดก่อนที่จะเริ่มอ่านไฟล์ รูปแบบไฟล์ชนิด "ดิบ" บางรูปแบบอาจเป็นสตรีมของไบต์ที่มีบางไบต์ "จุดสิ้นสุดบรรทัด" ที่ส่วนท้ายของแต่ละแถวแนวนอนของพิกเซล (ในกรณีนี้ซอฟต์แวร์จะต้องอ่านบรรทัดแรกและแบ่งขนาดของสตรีมไบต์ โดยความยาวบรรทัดเพื่อรับความสูง)

ฉันไม่คิดว่าคุณสามารถทำสิ่งนี้ในลักษณะ "ทั่วไป" ใด ๆ ตามที่คุณต้องเข้าใจรูปแบบไฟล์ (หรือใช้ห้องสมุดแน่นอน) เพื่อที่จะรู้วิธีการอ่าน คุณอาจพบรหัสบางส่วนที่โดยส่วนใหญ่จะประมาณขนาดโดยไม่ต้องอ่านไฟล์ทั้งหมด แต่ฉันคิดว่าไฟล์บางประเภทอาจต้องการให้คุณอ่านไฟล์ทั้งหมดเพื่อให้แน่ใจว่าขนาดจริงมีขนาดใด ฉันคาดหวังว่ารูปแบบไฟล์ภาพศูนย์กลางบนเว็บส่วนใหญ่จะมีส่วนหัวพร้อมข้อมูลดังกล่าวเพื่อให้เบราว์เซอร์สามารถสร้างขนาดกล่องก่อนที่จะโหลดภาพทั้งหมด

ฉันเดาห้องสมุดที่ดีจะมีวิธีการบางอย่างเพื่อให้ได้ขนาดของไฟล์ที่จัดการและวิธีการเหล่านั้นจะถูกนำไปใช้อย่างมีประสิทธิภาพมากที่สุด

อัปเดต : imageinfoดูเหมือนว่าจะเป็นสิ่งที่คุณต้องการ (ยังไม่ได้ทดสอบ)


เครื่องมือนั้นทำงานได้เร็วเท่าที่ฉันต้องการ;) ฉันจะดูว่าฉันสามารถใช้งานได้อย่างถูกต้อง
dAnjou

0

หากคุณมีข้อมูล EXIF ​​ในภาพคุณสามารถอ่านส่วนหัว EXIF


โชคไม่ดีที่ฉันไม่รู้ว่าจะมีภาพประเภทใดและพวกเขามีข้อมูล EXIF ​​หรือไม่
dAnjou

3
วิธีการหลายภาพของคุณไม่ได้มีข้อมูลที่? บางทีถ้า 90% ของพวกเขามีข้อมูล EXIF ​​ความช้าของการใช้ ImageMagick ในอีก 10% จะเป็นที่ยอมรับ
Andy Lester

ทำไมคำตอบนี้ถึงมี downvotes มันเป็นคำตอบที่ถูกต้องสำหรับคำถามและอาจเป็นสิ่งที่ OP หรือคนอื่นกำลังมองหา
Will Sheppard

0

- การพิมพ์เป็นตัวเลือกที่ดูเหมือนว่าจะมีการแนะนำสำหรับวัตถุประสงค์นั้น

อย่างไรก็ตามใน 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

โหลดเอาต์พุตของไฟล์ไปยังรายการ python และใช้ฟิลด์ 4'th ในรายการ

FYI ได้ปรับภาพประมาณ 18,000 ภาพเพื่อลดทราฟฟิกเครือข่าย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.