Instagram是一個我一直蠻喜歡的service, 主要是簡單, 加上有一些濾鏡可以豐富我隨手拍的照片, 當然, 重要的是, 高價賣給了Facebook而一炮而紅

上星期, 參加了AT&T Palo Alto Hackthon, 拿到大獎的團隊用了一個lib叫 caman.js 的, 這東西讓我有點小小驚艷, 它光用javascript (其實是Coffee script)就實作出了許多影像處理的功能, 這讓我興起想用這個來試著做出類似Instagram的東西, 當然是純用HTML+Javascript

首先面臨的一個問題是, 實作Camera的部份, HTML5支援media capture的方式有三種(請參考Reference 3) : Input tag, device tag, WebRTC (getUserMedia)

但很不幸, 除了Input tag以外, 大部分手機上的browser,如Android browser, Firefox, Chrome, 可以說幾乎全部都不支援, 這可真是有點令人傷心的消息, 因為用Input tag, 會離開browser跳到另一個程式, 這樣就無法結合自己的UI了

不過, 其實也沒那麼絕望, Android上的Opera Mini, 就支援getUserMedia (參考Reference 1)

因此就可以實作出像這樣的東西:

Device-2012-05-10-021018

WebRTC(getUserMedia)的原理是把media stream導到video tag去播放(理應就這樣做), 但這樣出來的比例是camera的比例, Instagram的照片都是方形的, 要實現這點, 其實也不難, 就另外把內容畫到另一個方形canvas, 在video play的時候開始每隔40ms畫一次, 把video畫到canvas的方式也不難, 就把他當image看待就行了

不過當第一次使用時, 瀏覽器會跳出詢問是否允許使用相機的對話窗:

Device-2012-05-10-021029

因為偷懶, 拍照的部份沒沿用原本的canvas, 另起一個Canvas, 並把可用的濾鏡放在下面:

Device-2012-05-10-021056

接下來就是神奇的CamanJS的工作了, CamanJS是一個以CoffeeScript實作出來的影像處理的lib, 還真的蠻厲害的, 害我都有點想研究一下CoffeeScript了

使用方式非常的簡單, 像以下面的程式:

Caman(“path/to/image.jpg”, “#canvas-id”, function () {

    // manipulate image here

    this.brightness(5).render();

});

就可以提高影像的亮度了,

此外還有許多預設的濾鏡, 我也偷懶直接採用, 這就是做出來的效果:

Device-2012-05-10-021122
Device-2012-05-10-020928

Source codes分享於此: https://github.com/julianshen/instagramlikecam

References: 

  1. http://dev.opera.com/articles/view/playing-with-html5-video-and-getusermedia-support/
  2. http://people.opera.com/danield/webapps/instant-camera/
  3. http://www.html5rocks.com/en/tutorials/getusermedia/intro/
  4. http://camanjs.com/

B2G並未一定要開發者把應用程式發表到一個特別的app store, 網站也可以自行加一個install按鍵, 讓使用者把你的網站當應用程式裝到手機內

首先, 你必須要先有個manifest, 目前manifest並沒強制的檔名, 但文件裡建議叫 xxxx.webapp, 以下是範例內容:

{ "name": "MyTestApp", "description": "test app", "launch_path": "/", "icons": { "128": "/img/icon.png" }, "developer": { "name": "Julian Shen" } }

 

然後在網頁內加上檢查是否安裝, 以及安裝的程式碼, 範例如下:

var manifestUrl = 'http://localhost:3000/manifest.webapp'; var app = navigator.mozApps;  function checkInstalled() { var request = app.getSelf(); request.onsuccess = function() { if(request.result) { //installed console.log('installed'); document.getElementById('installmsg').style.display='none'; } else { //not installed console.log('not installed'); } }; }  function install(cb) { var request = app.install(manifestUrl); request.onsuccess = function() { alert('installed'); };  request. function() { alert('Not installed'); } }
這邊要注意的是manifestUrl必須是full path而不是只有相對位置, 寫相對位置, 它還是讀的到, 但會出parse error, 之前害我搞半天一直以為是格式問題, trace了一下Webapps.js, 發現可能是判斷install origin有問題
目前安裝介面很醜:
_2012-05-08_2
安裝完就可以在Home screen看到它的存在了:
_2012-05-08_2

First, you need to follow this doc (http://developer.yahoo.com/cocktails/mojito/docs/quickstart/) to install Mojito as a global node module. Why install it globally? Because you need the Mojito command line to create your first app.

Create application with command line:

mojito create app mymojito

Change working directory to “mymojito”.

Create a “Procfile” whose content is:

web: mojito start $PORT

Use the following command to create an application on heroku and deploy codes to it.

  • git init
  • git add .
  • git commit -am init
  • heroku create mymojitotest –stack cedar
  • git push heroku master

After successfully commit codes to heroku, you could check running process with “heroku ps”. However, you cannot find any running process. That is because there is one important step missed:

heroku ps:scale web=1

This command adds one dyno for web process. After that, you will find one web process when you check with “heroku ps”. And the server is now started up. You can check your app with browser.

Source: https://bitbucket.org/julianshen/videomag/overview

Demo URL: http://growing-wind-8625.herokuapp.com/top

Server: Play framework 2.0 on Heroku

Open graph object: Youtube video, Action: watch

It’s not a problem to add youtube video since it already contains open graph meta data in page. All we have to do is call “/me/video.watches?video=youtube_link” with POST.

To post activity to timeline, the permission “publish_actions” is required. 

The result on timeline:

_2012-04-13_2

最近好像有點混, 都吃吃喝喝的, po的滿滿blog都拉麵, 連跑去香港參加Hack Event也吃了兩碗拉麵, 該反省一下, 不過反省歸反省, 食記還是要寫一下, 這次也偷懶把兩家併一篇寫

這兩家是 “Mist” 和 秀拉麵, Mist是米其林一星級的拉麵, 而秀拉麵是 米其林 必比登 推薦

先說Mist,

這不愧是米其林一星級, 服務相當好, 我進去後, 由於我只有一個人, 所以招呼我坐吧台, 但吧台本來就有一個體型比較龐大的外國人已經坐那等著點餐, 他看太擠, 剛好又有一桌空下來, 就請那位外國人獨自一桌, 另外幫我拉開椅子, 整個就像高級餐廳的服務, 不像拉麵店

DSC02076

小抽屜拉開, 整齊的擺滿餐具, 非常整齊, 裡面還有一張介紹這家店的簡介, 一下子好像有點來到展餐具的博物館一樣

在吧台有個好處, 可以看著師父處理食物, 雖說是拉麵, 但感覺好像是法式料理版的拉麵店, 看著師父用著麵條做出一小匙一小匙的前菜(別桌點的), 還真像法式料理, 說到這, 這還真是我第一次吃拉麵有前菜的

“一小匙"的起司番茄, 很特別, 不過其實不覺得這番茄有特別美味就是了

DSC02079

另外我還點了啤酒:

DSC02078

啤酒是他們自家品牌的白啤酒, 送出來時, 杯子是冰過的還在冒汗, 此時服務生才開瓶倒入, 所以喝的時候是完全冰涼, 啤酒不苦不澀, 很爽口….

DSC02081

接著, 主題, 拉麵, 看這張照片別誤會, 叉燒並不是另外放, 那盤是我加點的鴨胸肉, 鴨胸是,彈牙!而且沒一般鴨胸的油膩, 不過切薄薄的, 也只有三塊, 兩三下就沒了

拉麵裡面另有一片入口即化的叉燒,不誇張,真的入口即化, 說到湯頭…我第一次喝到湯第一口喝到發抖的…這不是形容詞, 是真的發抖(我那時感冒還沒好啦), 還不小心摔了相機…不過, 這湯頭也不能說是很正統的拉麵湯頭, 濃, 但不會真的太鹹, 也不太膩, 我點的是味噌拉麵, 點的時候服務生有說這比較濃, 問我是否可以接受, 不過實際嚐過後, 我是覺得還不是到真正口味很重的味噌拉麵, 麵條是我吃過最好吃的, 我是覺得比一蘭還好吃

整體說來, 這碗拉麵配冰啤酒, 還蠻讚的, 主要服務也不錯, 這一頓花了220港幣

再來是秀拉麵 –

DSC02178

菜單上有所謂的黑秀赤秀, 沾麵似乎也是當店推薦(面前就有貼著沾麵午餐特餐的廣告), 不過我點的是博多傳統拉麵, 想試試這家的豬骨湯如何

從麵條軟硬度, 湯頭濃淡, 到叉燒都可以客製, 我叉燒特別點豬頸肉, 這也只有我點的博多拉麵可以選配, 另外加點半熟蛋

DSC02173

半熟蛋不錯吃, 豬頸肉叉燒感覺像是火烤的, 口感比較硬, 但切成薄片, 老實說這樣的叉燒我吃不習慣

麵條還不錯, 但稍乾, 湯頭非常正宗的豬骨湯頭, 濃度夠, 油脂跟膠質都很足夠, 豬骨湯的香氣相當濃郁

進門之前, 有查一下網路評價, 有看到這家店的餃子蠻特別的, 所以就點了一份加了芝士沙律醬的煎餃

DSC02180

煎好的餃子上面淋一層芝士, 然後再淋一層沙律(沙拉醬), 乍看之下蠻特別的, 視覺上也蠻特別的

但我還蠻後悔點這盤的, 餃子本身煎的不錯, 皮脆脆的不錯吃, 但芝士加上沙律, 芝士鹹鹹的加一股奶味, 沙律又酸酸的, 老實說, 不喜歡, 我也不覺得很搭, 早知道就用傳統的方法吃煎餃了, 雖然我很喜歡標新立異, 但這吃法, 真的不對我胃口

這價格就比Mist便宜多了, 這樣吃下來才吃掉一百多