python : แตกไฟล์ JPG จากไฟล์ภาพ Canon

 

มีโจทย์อยู่คือ
เวลาไปเที่ยวหรือมีงานที่ต้องถ่ายภาพเป็นจำนวนมาก เกินการ์ดหน่วยความจำที่มีอยู่
เวลาการ์ดเต็ม ก็ต้องถ่ายออกมาเก็บไว้ในโน๊ตบุ๊ก

ปัญหาคือเวลาจะดูภาพจากโน๊ตบุ๊ก ซึ่งสเปคเครื่องต่ำมาก โหลดไฟล์ภาพใหญ่ ๆ ไม่ไหว มันจะดูได้ช้ามาก ๆ ดูภาพ 10 ภาพ ใช้เวลาไป 15 นาที

ทางแก้คือคัดลอกไฟล์ภาพมาแปลงเป็นไฟล์เล็ก (อาจจะแปลงด้วย gimp หรือ imagemagick ก็ได้) แต่เนื่องจากสเปคเครื่องต่ำมาก แปลงไฟล์แต่ละครั้งกินเวลาเป็นชั่วโมง ไม่ทันต่อเหตุการณ์

ทางออกอีกทางคือไปแตกเอาไฟล์ JPG อันเล็ก ที่ซ่อนอยู่ภายใต้ไฟล์ตัวจริงซึ่งใหญ่มาก เอาออกมาแทน วิธีนี้จะทำงานได้รวดเร็วกว่ามาก

เคยเขียน C ไว้เป็นไฟล์เล็ก ๆ บนวินโดวส์ แต่เที่ยวนี้ผมลองเอามาคอมไพล์บนลินุกส์ ปรากฎว่าคอมไพล์ไม่ผ่าน และภาษา C ก็ลืมสิ้นแล้ว อย่ากระนั้นเลย พึ่งไพธอนดีกว่า

ผมใช้กล้อง Canon และเราจะแตกไฟล์ JPG อันเล็ก ซึ่งเป็นไฟล์ลำดับที่ 3 ที่ซ่อนอยู่ในไฟล์ใหญ่ เลยตั้งชื่อโปรแกรมว่า canon3.py

เวลาใช้งานก็สั่ง
$ ./canon3.py FILENAME.JPG
ก็จะแตกไฟล์ FILENAME.JPG ไปเป็น canon3/FILENAME.JPG

หรือถ้าสั่ง
$ ./canon3.py เฉย ๆ
ก็จะควานหาทุกไฟล์ในไดเรกทอรี่ที่เป็น JPG หรือ CRW และแตกไฟล์ย่อยออกมาใส่ในไดเรกทอรี่ย่อย canon3

โดยโปรแกรมจะคัดลอกเอาข้อมูล Exif ของกล้องติดไปด้วย (แต่ข้อมูลขนาดภาพใน Exif จะผิดจากความเป็นจริง ขี้เกียจแก้แล้วอ่ะ)

ทดลองแล้วความเร็วใสการแตกไฟล์ดีมาก (ไพธอนนี่ดีกว่าที่คิดเยอะเลย)

โค๊ดมีดังนี้

#!/usr/bin/env python
# EXTRACT THIRD jpg FILE IN Canon CAMERA
#
# jpg file format
# start with: FF D8 FF E1 NN NN ...  (contain exif data to byte NN NN)
# first JPG : FF D8 ... FF D9 (thumbnail)
# second JPG: FF D8 ... FF D9 (real JPG)
# third JPG : FF D8 ... FF D9 (hidden small JPG)
# SKIP TO 2/3 OF FILE THEN SEARCH FOR THIRD #FFD8 TO #FFD9
#

import sys, os, string

# VAR
tag_beg="\xff\xd8"
tag_end="\xff\xd9"
subdir="canon3"
file_skel=[".JPG",".jpg",".jpeg"]
dir_skel=["DCIM","CANON"]

# PROCEDURE
def process_file(filename):
  for fskel in file_skel:
    if fskel in filename:
      #OPEN FILE IN BINARY MODE
      try:
        f = open(filename, 'rb')
      except:
        print 'Could not open file to read !', filename
        sys.exit(3)
      if f is None:
        print 'Error opening file ', filename
        sys.exit(3)

      # COPY EXIF HEADING TO NEW FILE IN SUBDIR canon3
      basename=os.path.basename(filename)
      print "%s -> %s/%s" % (basename,subdir,basename)

      if not os.path.exists(subdir):
        os.mkdir(subdir)
      #
      f_new=open(os.path.join(subdir,basename),"wb")

      # SEEK FF D8 FF E1 NN NN
      f.seek(4)
      offset_low=f.read(1)
      offset_hi=f.read(1)
      no_of_byte=ord(offset_low)*256+ord(offset_hi)-4

      ## print "no_of_byte=%i" % no_of_byte

      # WRITE TO NEW FILE
      f_new.write("\xff\xd8\xff\xe1"+offset_low+offset_hi+f.read(no_of_byte))

      # SEEK FOR THE REST 3RD JPG FILE
      # INCREASE SPEED BY SKIP TO 2/3 OF FILE
      f.seek(os.path.getsize(filename) * 2/3)
      is_found=False
      for i in f:
        if tag_beg in i:
          is_found=True
          # WRITE THIRD JPG TO NEW FILE
          f_new.write(tag_beg+i.split(tag_beg)[1])

          for j in f:
            if tag_end in j:
              f_new.write(j.split(tag_end)[0]+tag_end)
              break
              f_new.close()
            else:
              f_new.write(j)
            #
          #
          break
        #
      #
      f.close()
      if not is_found:
        print "third JPG file not found."
      #
    #
  #

def process_dir(dirname):
  ## print "dirname=%s" % dirname
  for dskel in dir_skel:
    if dskel in dirname:
      print "enter %s" % dirname
      os.chdir(dirname)
      filelist=os.listdir(".")
      for i in filelist:
        if os.path.isdir(i):
          process_dir(i)
        else:
          process_file(i)
        #
      #
      print "exit %s" % dirname
      os.chdir("..")
    #
  #


# MAIN PROG
def main():
  if len(sys.argv) < 2:
    # PROCESS ALL FILE&DIR
    for filelist in os.listdir("."):
      if os.path.isdir(filelist):
        process_dir(filelist)
      else:
        process_file(filelist)
      #
    #
  else:
    filename = os.path.abspath(sys.argv[1])
    if os.path.isdir(filename):
      process_dir(filename)
    else:
      process_file(filename)
    #
  #
  print "finished"

if __name__=="__main__":
        main()

แถมอีกนิด
ถ้าจะให้หมุนภาพอัตโนมัติด้วย ต้องใช้แพคเกจ jhead
$ sudo apt-get install jhead
$ jhead -autorot *

 

Syndicate

Subscribe to Syndicate

Who's online

There are currently 0 users online.