iPod touch用写真リネームツール New!
iPod touch(iPhoneも)の写真がメチャクチャな順番で表示される件(http://support.apple.com/kb/HT4221?viewlocale=ja_JP)の回避ツールですが、フラットに1000枚近いのが並ぶのもどうかと思い。
こんな感じに年ごとにフォルダを分けるようにしました。
「何が便利なの?」
と思われると思うのですが(笑)
僕はPicasaで写真を管理していて、これをtouchに全部突っ込もうとすると、iTunesが「RAMが足りません」とか言い出しまして。今時組み込みでもあるまいしw
それはともかく、400GByte近くある写真を全部持ち歩くのも無理があるので、星をつけてるやつだけにしようかと。
そうするとPicasaからExportするわけですが、PicasaのExportでは一つのフォルダにフラットにファイルが並ぶ、と。タチの悪いことにiTunesは「すでに知ってるファイルか?」「ファイル名は?」ということでソートするので、ファイルの順番ぐちゃぐちゃ。目的の写真にたどり着くまでえらいかかる、というかたどり着けない。
で、このツールをかけると、
- EXIFを読んで古い順にソート
- ファイル名は古い順に連番
- 年ごとにフォルダを分ける
と、なります。これでtouchでも快適に写真が探せる、と。
ワークフローは
- Picasaでスター付き画像をすべて選択してExport(ここでtouchにサイズを合わせるとよい)
- touchとの同期用ディレクトリをipod photo cacheを含めてクリア。
- Export先のディレクトリに対して、ツールをかける
- touchとの同期用のディレクトリに、ツリー構造で写真が出力される
- iTunesの写真の共有元に4.のディレクトリを指定
- (゚Д゚)ウマー
と、そんな感じです。
相変わらず例外処理が甘かったりするし、環境特化なので、とりあえずはソースを置いておきます。GUIつけるのもバイナリ配布するのも簡単なんですが、要望があったらやろうかなー、くらいです。
using System; using System.Collections; using System.Linq; namespace CorrectTouchPics { class CorrectTouchPics { const string SRC_DIR = @"C:\Users\Hiroyuki\Desktop\スター付き画像"; const string DST_DIR = @"C:\Users\Hiroyuki\Desktop\touch_pics"; const string FILE_NAME_BASE = "CTP"; static void Main(string[] args) { Console.Title = "Correct Touch Pictures"; Console.WriteLine("---------------------------Correct Touch Pictures Start."); // //元ファイル取得 // Console.Write("Searching..."); ArrayList srcFiles = new ArrayList(); string[] picFiles = System.IO.Directory.GetFiles(SRC_DIR, "*.jpg"); Console.WriteLine("\t{0}files found.", picFiles.GetLength(0)); if (picFiles.GetLength(0) == 0) { Console.WriteLine("No picture file found."); goto END; } // //日付でソート // Console.Write("Getting EXIF..."); foreach (string pic in picFiles) { string strDate = ""; //日付文字列(仮にemptyとする) System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(pic); //画像ファイルとして読み込み //日付を取得 DateTime dt; var dateProperty = from System.Drawing.Imaging.PropertyItem dp in bmp.PropertyItems where dp.Id ==0x9003 select dp.Value; foreach (var dp in dateProperty) //foreachにしているが、実行回数は0or1 { strDate = System.Text.Encoding.ASCII.GetString(dp); } if (strDate.Length != 0) //日付の文字列が取得できた { strDate = strDate.Trim(new char[] { '\0' }); //終端の\0をとる dt = DateTime.ParseExact(strDate, "yyyy:MM:dd HH:mm:ss", null); } else //EXIFから日付が取得できなかった { dt = DateTime.MaxValue; } srcFiles.Add( new TouchPic(pic,dt)); //ファイル情報を配列に追加 } Console.WriteLine("\tdone."); // //ソートする // Console.Write("Sorting..."); srcFiles.Sort(); Console.WriteLine("\tdone."); // //年ごとにわけてコピーを行う。 // if (srcFiles.Count != 0) //対象の写真があれば { Console.WriteLine("Exporting..."); int year = ((TouchPic)srcFiles[0]).photoYear; //一番古い写真の年から始める。 while (year <= 9999) //EXIFなしまで回す。 { int fileNum = 0; //ファイル連番 string dstDir = System.IO.Path.Combine( //出力ディレクトリ\yyyy DST_DIR, year.ToString("D4") ); var files = from TouchPic tp in srcFiles //同じ年の写真を抜き出す where tp.photoYear == year select tp; if (files.Count() != 0) //該当する写真があれば { Console.WriteLine("\t{0}", year.ToString()); if(!System.IO.Directory.Exists(dstDir)) //出力ディレクトリがなければ生成する。 { System.IO.Directory.CreateDirectory(dstDir); } //ファイルコピー foreach (var file in files) { //出力ディレクトリ+ファイル名ベース+XXXXX+.jpg string dstFileName = FILE_NAME_BASE + fileNum.ToString("D5") + ".jpg"; dstFileName = System.IO.Path.Combine(dstDir, dstFileName); System.IO.File.Copy(file.srcFile, dstFileName, true); fileNum++; } } year++; } } //終了処理 END: Console.WriteLine("--------------Correct Touch Pictures End. Press any key."); ConsoleKeyInfo ki = Console.ReadKey(); //ユーザ入力待ち } } class TouchPic : IComparable { public readonly string srcFile; //コピー元ファイル public readonly DateTime dateTime; //EXIF撮影日 public readonly int photoYear; //撮影日の「年」部分 public TouchPic(string src, DateTime dt) { srcFile = src; dateTime = dt; photoYear = dt.Year; } public int CompareTo(object obj) { int ret; DateTime dtThis, dtOther; dtOther = ((TouchPic)obj).dateTime; dtThis = this.dateTime; if (dtThis < dtOther) { ret = -1; } else { ret = 1; } return (ret); } } }
今回は初めてLINQを使ったので色々トラブったけれど、それなりに見られるコードになっていると思います。ソートもLINQ使えばいいようなもんですが、このへんはもう作っちゃってたのでそのまま利用してます。