數位單眼檔案整理計畫 (照片整理計畫)
目的:將數位相機拍攝照片、影片放置在網站上,方便平板、手機觀看存取
規格:
- 可分類
- 根據分類或自定義讀取權限
- 照片、影片必須可在 Android, IOS 上正常觀看
- 可直接上傳 RAW 格式照片
- 上傳時可選擇資料夾 (搭配 Chrome 瀏覽器)
技術:
- PHP, MySQL
- HTML5, Javascript
- Jpeg, PNG 圖檔格式轉檔
- RAW 格式圖檔轉檔
- Exif 格式存取
- 影片轉檔
- 把檔案放上去
- 處理成可以在 HTML5 可以接受的格式
- 顯示及播放
--
數位單眼有什麼檔案?
大致上分為三類
- RAW 格式圖檔
- Jpeg 圖檔
- 影片檔 (MOV, MTS...)
觀看、分享方法
放置在網站,主要使用 HTML5 技術
使用該方法限制及前置作業
圖檔和硬片都需要縮小尺寸、重新取樣、轉換格式後才上傳至網站上
1多檔案及資料夾檔案上傳
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
var uploader = new plupload.Uploader({ runtimes : 'html5', file_data_name : 'DSLRFile', drop_element : 'drag-area', browse_button : 'drag-area', //max_file_size : '10mb', url : "/?a=Upload", multipart_params: { Title:'', Date:''} }); //绑定文件添加进队列事件 uploader.bind('FilesAdded',function(uploader,files) { for(var i = 0, len = files.length; i<len; i++) { var file_name = files[i].name; //文件名 //构造html来更新UI var html = '<div id="file-' + files[i].id +'" class="statusbar"><div class="filename">' + file_name + '</div><div class="FileSize">'+ files[i].size +'</div><div class="progressBar"><div style="width: 0;"></div></div></div>'; $(html).appendTo('#file-list'); } }); //绑定文件上传进度事件 uploader.bind('UploadProgress',function(uploader,file){ $('#file-'+file.id+' .FileSize').text(file.size); // $('#file-'+file.id+' .progressBar>div').css('width',file.percent + '%');//控制进度条 }); // 上傳後回傳 uploader.bind('FileUploaded', function(uploader, file, response) { var res1 = response.response.replace('"{', '{').replace('}"', '}'); var Json = JSON.parse(res1); }); // 全部 上傳完成 uploader.bind("UploadComplete", function () { $('#file-list').find('div').remove(); }); //上傳 $('#upload-btn').click(function() { uploader.settings.multipart_params.Date = '<{$Albums.Date}>'; uploader.settings.multipart_params.Title = '<{$Albums.Title}>'; uploader.start(); //开始上传 }); |
--
2. 讀取相片 Exif
PHP exif_read_data()
因為使用 PHP 官方也有 exif 的功能,所以
1 2 3 |
cd /usr/ports/lang/php55-extensions make config make install |
補上 exif 後
1 2 3 4 5 6 7 8 |
<?php $exif = exif_read_data('DSC_1748.NEF', 0, true); echo "test2.jpg:<br />\n"; foreach ($exif as $key => $section) { foreach ($section as $name => $val) { echo "$key.$name: $val<br />\n"; } } |
就吐出錯誤訊息了
1 2 3 4 5 6 7 8 9 10 11 |
Warning: exif_read_data(DSC_1748.NEF): Process tag(xB424=UndefinedTa): Illegal components(37389860864) in /WEBSite/Albums/WWW/index.php on line 108 test2.jpg: FILE.FileName: DSC_1748.NEF FILE.FileDateTime: 1416281284 FILE.FileSize: 20399286 FILE.FileType: 8 FILE.MimeType: image/tiff FILE.SectionsFound: ANY_TAG, IFD0, THUMBNAIL, EXIF, GPS COMPUTED.html: width="160" height="120" COMPUTED.Height: 120 COMPUTED.Width: 160 |
而且尺寸也是錯的,再次 Google 之後找到了 Exiv2 - Image metadata library and tools
FreeBSD 9.1 安裝 exiv2
1 2 3 |
cd /usr/ports/graphics/exiv2 make install exiv2 -p s DSCN0166.JPG |
CentOS 6 安裝 exiv2
1 |
yum install exiv2 |
就可以得到正確的資訊了
NIKON D7000 RAW
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
File name : DSC_1748.NEF File size : 20399286 Bytes MIME type : image/x-nikon-nef Image size : 4992 x 3280 Camera make : NIKON CORPORATION Camera model : NIKON D7000 Image timestamp : 2012:12:15 08:09:50 Image number : Exposure time : 1/200 s Aperture : F7.1 Exposure bias : 0 EV Flash : No, compulsory Flash bias : Focal length : 18.0 mm (35 mm equivalent: 27.0 mm) Subject distance: ISO speed : 200 Exposure mode : Not defined Metering mode : Multi-segment Macro mode : Image quality : RAW Exif Resolution : 160 x 120 White balance : AUTO1 Thumbnail : None Copyright : Exif comment : |
SONY NEX-5
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
File name : /tmp/phpg94wur File size : 7995392 Bytes MIME type : image/jpeg Image size : 4592 x 3056 Camera make : SONY Camera model : NEX-5 Image timestamp : 2020:02:28 09:21:25 Image number : Exposure time : 1/160 s Aperture : F7.1 Exposure bias : 0 EV Flash : No, compulsory Flash bias : 0 EV Focal length : 18.0 mm (35 mm equivalent: 27.0 mm) Subject distance: ISO speed : 200 Exposure mode : Auto Metering mode : Center weighted average Macro mode : Image quality : Fine Exif Resolution : 4592 x 3056 White balance : Auto Thumbnail : image/jpeg, 16716 Bytes Copyright : Exif comment : |
HUAWEI P9+
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
File name : /tmp/phpN8b6ee File size : 3286363 Bytes MIME type : image/jpeg Image size : 2976 x 3968 Camera make : HUAWEI Camera model : VIE-L29 Image timestamp : 2020:04:12 11:44:31 Image number : Exposure time : 0.003039 s Aperture : F2.2 Exposure bias : 0 EV Flash : No flash Flash bias : Focal length : 4.5 mm (35 mm equivalent: 27.0 mm) Subject distance: ISO speed : 50 Exposure mode : Auto Metering mode : Multi-segment Macro mode : Image quality : Exif Resolution : 2976 x 3968 White balance : Auto Thumbnail : image/jpeg, 36360 Bytes Copyright : Exif comment : |
--
使用 PHP 分析字串取得 Exif
參考: php-exiv2/Exiv2ImageExplorer.php at master · joelalejandro/php-exiv2 · GitHub
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
$Exiv2 = 'exiv2 -p s /tmp/DSCN0166.JPG'; $Exif = shell_exec($Exiv2); foreach( explode("\n", $Exif) as $line ) { $key = trim(substr($line, 0, strpos($line, ':'))); $value = trim(substr($line, strpos($line, ':') + 1)); switch ($key) { case 'File size': $metadata['FileSize'] = $value; break; case 'MIME type': $metadata['MIMEType'] = $value; break; case 'Image size': $metadata['Width'] = trim(substr($value, 0, strpos($value, 'x'))); $metadata['Height'] = trim(substr($value, strpos($value, 'x')+1)); break; case 'Camera make': $metadata['CameraMake'] = $value; break; case 'Camera model': $metadata['CameraModel'] = $value; break; case 'Image timestamp': $metadata['ImageTimestamp'] = $value; break; case 'Exposure time': $metadata['ExposureTime'] = $value; break; case 'Aperture': $metadata['Aperture'] = $value; break; case 'Exposure bias': $metadata['ExposureBias'] = $value; break; case 'Flash': $metadata['Flash'] = $value; break; case 'Focal length': $metadata['FocalLength'] = $value; break; case 'ISO speed': $metadata['ISOSpeed'] = $value; break; case 'White balance': $metadata['WhiteBalance'] = $value; break; } } |
拍攝方向
1 2 |
$ identify -format "%[EXIF:Orientation]" DSC04533.JPG 8 |
--
取得影片格式資訊
1 2 3 4 |
> ffprobe -v error -show_entries stream=width,height,bit_rate -select_streams v:0 -of default=noprint_wrappers=1 movie.mkv width=1920 height=1040 bit_rate=2557822 |
--
舊數位相機 MOV 格式影片轉檔
1 |
# /usr/bin/ffmpeg -i /WEBSite/Albums/Data/1103/15c40961b34115 -vcodec libx264 -pix_fmt yuv420p -profile:v baseline -level 3 -s 640x480 -ar 44100 -strict -2 -b:v 2000k -r 30 -b:a 192k -y /WEBSite/Albums/Data/1103/15c40961b34115.mp4 |
--
1 2 |
exiv2 -p a DSC_2737.NEF | grep Orientation Exif.Image.Orientation Short 1 top, left |
--
RAW 格式轉檔
使用 dcraw 來進行處理
FreeBSD
1 2 3 4 |
cd /usr/ports/distfiles/ wget http://ftp.nsysu.edu.tw/FreeBSD/ports/local-distfiles/sunpoet/dcraw-9.19.tar.xz cd /usr/ports/graphics/dcraw/ make install |
CentOS
1 |
yum install dcraw |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
原始影像解碼工具 "dcraw" v8.96 本軟體由 Dave Coffin 製作 dcoffin a cybercom o net 指令用法: dcraw [參數]... [圖檔路徑]... -v 顯示詳細訊息 -c 將影像資料輸出終端機標準輸出埠 -e 抽出內嵌於原始圖檔中的預覽圖片 -i 確認圖檔格式但不進行解碼 -i -v 確認圖檔格式並顯示詮釋資料 (metadata)。 -z 將輸出檔案的產生時間設定成相片拍攝的時間。 -w 在允許的情況下使用相機指定的白平衡值 -a 利用整個影像的平均值來計算白平衡 -A <x y ∆x ∆y> 取灰色矩形區域平均值來計算白平衡 -r <r g b g> 使用自定白平衡值 +M/-M 使用或捨棄影像檔案中的 color matrix 資料 -C <r b> 校正色像差 -P <資料檔名> 修正列在資料檔中的損壞感光元件資料 -K <檔案路徑> 使用黑框抵消法來消除影像雜訊 (黑框檔案格式必須是 16-bit raw PGM) -k <數值> 設定黑色調數值 -S <數值> 設定色彩飽和度值 -n <數值> 設定微波雜訊消除臨界值 -H [0-9] 高亮度區域影像處理 -t [0-7] 翻轉影像 (0:不翻轉,3:轉 180 度,5:逆時針轉 90 度, 6:順時針轉 90 度) -o [0-5] 輸出 colorspace (raw,sRGB,Adobe,Wide,ProPhoto,XYZ) -o <檔案路徑> 讀取相機 ICC 描述檔案 -p <檔案路徑> 讀取相機 ICC 描述檔案或者是使用內嵌描述檔 -d 文件翻拍模式(黑白,不使用內插法) -D 黑白翻拍模式(完全不調整影像。) -j 不要拉長或是旋轉原始影像中的像素 -W 不要自動提高影像亮度 -b <數值> 調整亮度(預設值 = 1.0) -g <次方 斜率> 設定訂製 gamma 曲線 (預設值為 2.222 4.5) -q [0-3] 設定內插法所產生影像的品質。 -h 輸出影像的尺寸減半,相對的解碼速度也會比 "-q 0" 要快兩倍。 -f 在進行內插法演算時將 RGGB 當成四種顏色。 -m <num> 以 3x3 大小中間值濾鏡過濾紅綠與藍綠雜訊 -s [0..N-1] 選擇第 N 個 raw 檔案,或使用 "all" 參數來指 定轉換檔案裡所有的影像 -6 Write 16-bit instead of 8-bit -4 Linear 16-bit, same as "-6 -W -g 1 1" -T 放棄 PPM 格式,改以 TIFF 格式輸出 |
將 RAW 格式轉成 JPEG
1 |
dcraw -c -e DSC4175.NEF | convert - DSC.jpg |
--
GUI
--
IOS 的自動旋轉問題
1 2 3 4 5 6 |
.fancybox-image{ width: auto; height: auto; max-width: 100%; max-height: 100%; } |
--
取消 fancybox 的 click
- http://jsfiddle.net/DigitalBiscuits/DBvt7/211/
1 2 3 |
<a class="fancybox" href="http://digitalbiscuits.co.uk/art/photography/Photography_27.jpg"><img src="http://digitalbiscuits.co.uk/art/photography/thumbs/Photography_27.jpg" alt=""/></a> <a class="fancybox disabled" href="http://digitalbiscuits.co.uk/art/photography/Photography_53.jpg"><img src="http://digitalbiscuits.co.uk/art/photography/thumbs/Photography_53.jpg" alt=""/></a> |
1 2 3 4 5 6 7 8 9 10 |
$(".fancybox").attr('rel', 'gallery').fancybox({live: false}); //bind another click event $('.fancybox.disabled').on("click",function(e){ e.preventDefault(); alert("hi!"); }) //remove the fancybox handler from last 3 images, leaving the other click event handler untouched $('.fancybox.disabled').off('click.fb-start'); |
--
上傳即時更新
--
瀑布流布局
--
多圖處理技巧:延遲顯示、分次載入
延遲顯示 - 延遲顯示是將未出現的圖片就不載入的 Javascript 技術,一般使用 Lazy Load 來完成
分批載入 - 分批載入則是類似分頁模式,將同一頁圖檔分成數次載入。可以有顯示同頁或是分頁顯示等不同處理方式。
一般來說,對於一個相簿高達上千張圖檔需要顯示時,使用分批載入會較為恰當,因為必須考慮行動裝置硬體效能問題。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
jQuery(function($){ $("img.lazy").lazyload({ effect: 'fadeIn', effectspeed: 1000, threshold: 400 }); var min_width = 480; function masonry_update() { var $container = $('#container'); if ( $('html').width() < min_width ) { $container.masonry('destroy'); } else { $container.imagesLoaded(function(){ $container.masonry({ itemSelector: '.item', isFitWidth: true, columnWidth: 180 }); }); } } masonry_update(); $('#ww span').text($(window).width()); var ww; var timer = false; $(window).resize(function(){ ww = $(window).width(); $('#ww span').text(ww); if (timer !== false) { clearTimeout(timer); } timer = setTimeout(function() { masonry_update(); }, 200); }); $('#container').magnificPopup({ delegate: 'a', type: 'image', disableOn: function() { if( $(window).width() < 480 ) { return false; } return true; }, gallery: { //ギャラリーオプション enabled:true }, image: { // image コンテントタイプのオプション cursor: null, titleSrc: function(item) { return item.el.find('img').attr('alt'); } } }); }); |
--
影片
Error: Unsupported sample rate 7875
早期相機影片的錄影通常使用很奇怪的格式 (相較現在的 MPEG4 來說),不是奇怪的組合就是奇怪的數值設定。如果不設定預設處理數值 ffmpeg 可能會無法支援而報錯。
例如以下範例,2004 年的 NIKON Coolpix 3200 ,影像使用 mjpeg ,聲音使用 pcm ,問題出在聲音的取樣頻率,因為早期硬體效能、儲存空間問題,所以設定為 7875Hz,而此數值 ffmpeg 是不支援轉換的,必須指定支援數值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
Seems stream 0 codec frame rate differs from container frame rate: 600.00 (600/1) -> 15.00 (15/1) Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/WEBSite/Albums/Data/5/156ed053fcd909.mov': Metadata: creation_time : 2004-11-27 03:15:34 comment : NIKON DIGITAL CAMERA comment-eng : NIKON DIGITAL CAMERA Duration: 00:00:23.40, start: 0.000000, bitrate: 4240 kb/s Stream #0.0(eng): Video: mjpeg, yuvj422p, 640x480, 4155 kb/s, 15 fps, 15 tbr, 600 tbn, 600 tbc Metadata: creation_time : 2004-11-27 03:15:34 Stream #0.1(eng): Audio: pcm_u8, 7875 Hz, 1 channels, u8, 63 kb/s Metadata: creation_time : 2004-11-27 03:15:34 Incompatible sample format 'u8' for codec 'aac', auto-selecting format 's16' Incompatible pixel format 'yuvj422p' for codec 'mpeg4', auto-selecting format 'yuv420p' [buffer @ 0x8068d87a0] w:640 h:480 pixfmt:yuvj422p tb:1/1000000 sar:0/1 sws_param: [buffersink @ 0x8068d8800] auto-inserting filter 'auto-inserted scaler 0' between the filter 'src' and the filter 'out' [scale @ 0x8068d8880] w:640 h:480 fmt:yuvj422p -> w:640 h:480 fmt:yuv420p flags:0x4 [aac @ 0x80681de20] Unsupported sample rate 7875 |
1 |
/usr/local/bin/ffmpeg -i /WEBSite/Albums/Data/5/156ed053fcd909.mov -b 1200k -ar 44100 -y video.mp4 |
--
上傳佇列、背景轉檔
/etc/crontab
1 |
* * * * * root (lockf -s -t 0 /tmp/HoyoTube.lock /usr/local/bin/php /WEBSite/mytube/Process.php >> /var/log/HoyoTube.log) |
--
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
<?php // MySQL 設定 const MYSQL_HOST ="localhost"; const MYSQL_USERNAME ="Albums"; const MYSQL_PASSWORD ="xxxx"; const MYSQL_DBNAME ="Albums"; const File_Path = '/WEBSite/Albums/Data'; define( "PDO_DSN", "mysql:dbname=". MYSQL_DBNAME .";host=". MYSQL_HOST .";charset=utf8" ); $PDO = new \PDO(PDO_DSN, MYSQL_USERNAME, MYSQL_PASSWORD); $PDO->exec("set names utf8"); // php 5.3.6 之前的舊版本 $NowTime = date( "YmdHis" ); function ExtFileName($Name) { $Temp = explode('.', $Name); return array_pop($Temp); } $sql = " SELECT * FROM Movie WHERE ConvertComplete='N' "; $pre = $PDO->prepare($sql); $pre->execute(); $row = $pre->fetchAll(2); foreach( $row as $k=>$v ) { $Albums_id = $v['Albums_id']; $SaveFilename = $v['SaveFilename']; $SourceFilename = $v['SourceFilename']; //echo $SaveFilename; exit; $Source = File_Path .'/'. $Albums_id .'/'. $SaveFilename; $TargetCover = $Source .'_.jpg'; $TargetCoverSmall = $Source .'_s.jpg'; $TargetMP4 = $Source .'.mp4'; # 從影片拉出一張劇照 $ffmpeg_cover = "/usr/local/bin/ffmpeg -i $Source -vcodec mjpeg -vframes 1 -an -f rawvideo -ss 1 -y ". $TargetCover ; //echo $ffmpeg_cover; shell_exec( $ffmpeg_cover ); copy( $TargetCover, $TargetCoverSmall ); // 從副檔名決定處理程序 $SubFileName = ExtFileName($SourceFilename); if ( strtoupper($SubFileName) != 'MP4' && strtoupper($SubFileName) != 'MP3' ) { $mplayer = '/usr/local/bin/mplayer -vo null -ao null -identify -frames 0 '. $Source; //echo $mplayer; $MovieInfo = shell_exec($mplayer); $Movie = array(); foreach( explode("\n", $MovieInfo) as $line ) { $key = trim(substr($line, 0, strpos($line, '='))); $value = trim(substr($line, strpos($line, '=') + 1)); if ( $key=='ID_VIDEO_WIDTH' ) $Movie['Width'] = $value; if ( $key=='ID_VIDEO_HEIGHT' ) $Movie['Height'] = $value; } // 判斷是否為 16:9 if ( $Movie['Width']%16==0 ) { if ( $Movie['Width'] > 960 ) { $ConvertSize = '960x540'; } else { $ConvertSize = $Movie['Width'] .'x'. $Movie['Height']; } } // 判斷是否為 4:3 elseif ( $Movie['Width']%4==0 ) { if ( $Movie['Width'] > 640 ) { $ConvertSize = '640x480'; } else { $ConvertSize = $Movie['Width'] .'x'. $Movie['Height']; } } $ffmpeg_MP4 = "/usr/local/bin/ffmpeg -i ". $Source ." -vcodec libx264 -s ". $ConvertSize ." -ar 44100 -b 1600k -y ". $TargetMP4 ; //echo $ffmpeg_MP4; //exit; shell_exec( $ffmpeg_MP4 ); unlink( $Source ); } // MP4, MP3 不須轉檔處理 else { rename( $Source , $TargetMP4 ); } $sql = " UPDATE Movie SET ConvertComplete='Y' WHERE id='{$v['id']}' "; $pre = $PDO->query($sql); } |
--
--
1,006 total views, 1 views today