小学生の娘が自分用のデジカメが欲しいというので、そう言えば昔クレーンゲームでとったのがあるよと出してきたはいいけど、 PC に接続して写真を取り出すためのアプリが入ってた CD を処分してしまっていたので何とかしたメモ。
デジカメ本体はこんな感じ。本体には D:X DIGITAL とか DIGITAL CAMERA とか USB とか(笑)しか表示がなくて、ネットを色々探してみたけれど使えそうなアプリは見つけられず。 USB ケーブルを接続する端子も特殊?な感じだけどケーブルは奇跡的に発見。
Linux に繋げて lsusb してみると…
Bus 001 Device 006: ID 0979:0227 Jeilin Technology Corp., Ltd JL2005B/C/D Toy Camera
という表示。更にこれを手掛かりに探してみると、 gphoto を使うとカメラ内の写真を取り出せるっぽい!
早速 MacPorts で gphoto2 をインストールするけど、どうも最近 MacPorts でのインストールやアップグレードが失敗するなぁと少し調べてみると、どうもこういうことみたい。確かに Mavericks にしてから鴨。これまでバータリーに対処してきたのは無駄だったのね。 Homebrew だとこんなことないのかな? 取り敢えず手順通りに実行すると確かにエラーは出なくなったけど、やたらと時間がかかる。かかり過ぎる。カペルスキーインターネットセキュリティって奴を入れてから色々かなり重たくなってる実感があったので、試しにこれを無効にしてみると100倍速くなりますた。あくまで体感(笑)。 Parallels にバンドルされてたから使ってみてたけど、これを機会にサイナラします…。
gphoto2 を使ってコマンドラインから写真の取出しや削除ができる事は確認できたけど、さすがに小学生の娘にターミナルからコマンド入力させるのもアレなので簡単な GUI を Ruby/Tk でテキトーにこんな感じに。やっぱりマルチスレッドにするべきかなぁと直しかけたけど、使えないこともなさげなのでそのままに。やっつけなコードを恥ずかしながら置いときます。プログレスバーつけようとして志半ばな残骸もそのままに。あ、 gphoto2 と ppmtojpeg を内部で呼び出してます。あとは Automator を使ってアプリっぽく起動できるようにして出来上がり。
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
# tiny script to get all files from a JL2005B based toy camera
require "tk"
require "tkextlib/bwidget"
require "fileutils"
require "open3"
CmdDetectCamera = "/opt/local/bin/gphoto2 --auto-detect"
ValidCameraRegexp = /^ JL2005B/
CmdListFiles = "/opt/local/bin/gphoto2 -L"
FileListRegexp = /^#(\d+)\s+(jl_\d+)\.ppm/
CmdCountFiles = "/opt/local/bin/gphoto2 -n"
FileCountRegexp = /^Number of files.+:\s*(\d+)$/
CmdDelAllFiles = "/opt/local/bin/gphoto2 -D" # the camera does not support indivisual file deletion
CmdGetPicAsJpg = "/opt/local/bin/gphoto2 --stdout -p %d | /opt/local/bin/ppmtojpeg > %s.jpg"
ENV["LC_ALL"] = "C"
HomeDir = ENV["HOME"]
CameraDir = "#{HomeDir}/Documents/Camera"
TkOption.add '*font', 'Wawati\ SC 18'
class MainView
def initialize
@root = TkRoot.new do
title "写真取り込み"
minsize 300, 20
attributes "topmost", 1
end
# build GUI
@btnChk = TkButton.new(@root) do
text "カメラチェック"
pack("side" => "top", "padx" => "2", "pady" => "2", "fill" => "both")
focus
end
@btnGet = TkButton.new(@root) do
text "全部取り込む"
state "disabled"
end
@btnDel = TkButton.new(@root) do
text "全部消す"
state "disabled"
end
@stsLabel = TkLabel.new(@root) do
text ""
state "normal"
end
# @pgsVar = TkVariable.new
# @pgsBar = Tk::BWidget::ProgressBar.new(@root) do
# variable @pgsVar
# end
@btnChk.command( proc {self.checkCamera} )
@btnGet.command( proc {self.getAllPix} )
@btnDel.command( proc {self.delAllPix} )
self.centerWindow()
@btnChk.focus()
Tk.update
end
def packChild(child)
child.pack("side" => "top", "padx" => "2", "pady" => "2", "fill" => "both")
end
def unpackChild(child)
child.unpack()
end
def centerWindow
x = @root.winfo_screenwidth()/2 - @root.winfo_width()/2
y = @root.winfo_screenheight()/2 - @root.winfo_height()/2
@root.geometry("+%d+%d" % [x, y])
end
def messageBox(type, icon, title, message)
Tk.messageBox(
"type" => type,
"icon" => icon,
"title" => title,
"message" => message
)
end
def checkCamera
# self.unpackChild(@pgsBar)
self.unpackChild(@stsLabel)
self.unpackChild(@btnDel)
self.unpackChild(@btnGet)
stdin, stdout, stderr, thread = Open3.popen3(CmdDetectCamera)
stdin.close
stdout.each { |line|
if line =~ ValidCameraRegexp
self.messageBox(
"ok",
"info",
"OK",
"サポートしているカメラが見つかりました。"
)
self.packChild(@btnGet)
self.packChild(@btnDel)
self.packChild(@stsLabel)
# self.packChild(@pgsBar)
self.toggleButtons("normal")
@stsLabel.text("処理を選んでください。")
Tk.update
return
end
}
self.messageBox(
"ok",
"error",
"エラー",
"サポートしているカメラが見つかりませんでした。"
)
end
# # http://stackoverflow.com/questions/5781286/tkinter-how-do-widgets-update
# def doPrintLabelSlowly(label, message)
# text = label.text
# text << message[0]
# label.text(text)
# if message.length > 1
# self.doPrintLabelSlowly(label, message[1 .. message.length])
# end
# end
# def setLabel(label, message)
# label.text = ""
# self.doPrintLabelSlowly(label, message) if message.length > 0
# end
def getAllPix
self.toggleButtons("disabled")
@stsLabel.text("カメラ内の写真をチェック中…")
Tk.update
stdin, stdout, stderr, thread = Open3.popen3(CmdListFiles)
stdin.close
files = Array.new
stdout.each { |line|
if line =~ FileListRegexp
num, file = [Regexp.last_match(1), Regexp.last_match(2)]
# puts "#{num} #{file}"
files << [num, file]
end
}
stdin, stdout, stderr, thread = Open3.popen3(CmdCountFiles)
stdin.close
count = 0
stdout.each {|line|
count = Regexp.last_match(1).to_i if line =~ FileCountRegexp
}
if count == files.length
if count > 0
@stsLabel.text("%d 枚の写真が見つかりました。" % [count])
Tk.update
dateTime = Time.now.strftime("%Y%m%d-%H%M%S")
picDir = "#{CameraDir}/#{dateTime}"
dir = FileUtils.mkpath(picDir).shift
Dir.chdir(dir) { |dir|
files.each {|file|
stdin, stdout, stderr, thread = Open3.popen3(CmdGetPicAsJpg % file)
stdin.close
if thread.value.exitstatus != 0
self.messageBox(
"ok",
"error",
"エラー",
"#{file[0]} 枚目の写真の取得に失敗しました。\n全ての処理が終わってからもう一度試してみてください。"
)
count -= 1 # failed
else
@stsLabel.text("#{file[0]} 枚目の写真を取り込みました。")
Tk.update
end
}
}
self.messageBox(
"ok",
"info",
"OK",
"写真 #{count} 枚の取り込みに成功しました。"
)
self.toggleButtons("normal")
@stsLabel.text("#{count} 枚の写真を取り込みました。")
Tk.update
return
else
self.messageBox(
"ok",
"info",
"OK",
"写真が一枚もありませんでした。"
)
self.toggleButtons("normal")
@stsLabel.text("写真が一枚もありませんでした。")
Tk.update
return
end
end
self.messageBox(
"ok",
"error",
"エラー",
"カメラ内の写真の確認に失敗しました。\nもう一度やり直してみてください。"
)
self.toggleButtons("normal")
Tk.update
return
end
def delAllPix
@stsLabel.text("全ての写真を削除します。")
self.toggleButtons("disabled")
Tk.update
stdin, stdout, stderr, thread = Open3.popen3(CmdDelAllFiles)
stdin.close
if thread.value.exitstatus != 0
self.messageBox(
"ok",
"error",
"エラー",
"写真の削除に失敗しました。\nもう一度試してみてください。"
)
else
self.messageBox(
"ok",
"info",
"OK",
"全ての写真を削除しました。"
)
@stsLabel.text("全ての写真を削除しました。")
end
self.toggleButtons("normal")
Tk.update
end
def toggleButtons(state)
@btnChk.state(state)
@btnGet.state(state)
@btnDel.state(state)
end
def mainloop
@root.mainloop
end
end
view = MainView.new
view.mainloop()
最近のコメント