1. Canon Raw Codec + WPF #2, ThreadPool

    效能問題, 就跟我自己寫的小工具一起講好了. 話說之前 Microsoft 提供了一個很讚的小工具: Resize Pictures Power Toys, 功能超簡單, 大概就是檔案總管把圖檔選一選, 按右鍵選 "Resize pictures" 就好了:

    image

    選了之後就有簡單的對話視窗:

    image

    很簡單吧, 我個人非常愛用, 而且轉出來的效果也不差, 看起來 JPEG quality 大約有 80% ~ 90% 吧... 無耐 windows xp 裡有幾個跟 image 相關的 power toys, 到了 vista 通通不能用. 看來應該都是碰到 GDI+ 要轉換到 WPF 的陣痛期吧, 這幾個小工具還真是讓我繼續撐在 XP 的主要理由之一...

    扯遠了, 所以我的目標就是寫個類似的小工具, 讓我簡單的做批次縮圖就好. 有了上一篇的基礎, 要寫這種 tools 實在是沒什麼挑戰, 大概會寫 winform 的拉兩下就可以收工了...

     

    不過, 大話說太早. 先貼一下成品的畫面, 後面說明比較清楚:

    image

    要做的東西很簡單. 選好一堆圖按右鍵選 resize pictures 後就跳這畫面, 按 Resize 就開始跑. 用的是前一篇弄好的 library. 結果碰到的障礙還不少. 雖然可以跑, 但是看了就很礙眼...

    1. 效能有點糟.
      比較好的架構一定會有額外的效能折損, 我倒可接受. 內建的 JPEG codec 還好, 比不上像 Google Picasa 那樣快速. 但是 canon raw codec 就慘不忍睹... 如果把 raw 轉成同大小的 jpg (4000x3000 pixel), 足足要 60 ~ 80 sec ...
    2. 沒針對多處理器最佳化
      簡單的說, 以我的雙核 CPU (Core2Duo E6300), 跑起來 CPU 利用率只有 5x% 而以.
    3. ThreadPool 也無法解決問題
      因為 (2), 就很直覺的聯想到, 我一次轉兩張, 同樣時間內可以完成兩張的轉檔, 單位時間的運算量還是有提升, 雖然每一張還是要花那麼久... 不過我錯了, 看來是 canon codec 的限制, 開 thread pool 跑下去, 一樣是卡在 60% cpu 使用率左右...
    4. UI thread 問題
      thread pool 也不完全沒有作用. jpeg encode / decode 的部份是可以充份利用到 thread pool 的好處的, 只是 canon raw decode 的部份用不到. 當部份時間是 canon raw decode + jpeg encode / decode 時, 剩餘的 CPU 運算能力還是吃的到. 但是 thread pool 無法控制 priority, pool 裡的 thread 就嚴重的影響到 UI thread 的作業. 常看到的現像就是進度列一直在跑, 不過預覽圖片的控制項卻一直跑不出來

     

    (1) 的問題其實沒這麼嚴重. Microsoft HD Photo 有一個 feature, 就是大檔放在網路上, 你也能夠很快的透過網路看到小圖. 有點類似早期漸進式的 jpeg 那樣. 不過看起來 codec 的設計更好一點. 實驗的結果是, Full Size .CR2 (4000x3000) 存成同大小的 JPEG 檔需要 60sec, 而存成 800x600 只要 5 sec. 但是拿對照組 .JPG (4000x3000) -> .JPG (800x600), 差距又沒這麼大. 因此推測起來, 應該在 decode 階段就已經針對這樣的需求設計過了.

    剩下的問題我試了好幾種方法, 目標都擺在如何安排這堆 thread 在合適的時間做合適的工作. canon codec 就不適合同時丟好幾個 thread 下去跑, 因為完全沒用, 反而拉長每個 .CR2 從開始到輸出的時間. jpeg 的部份就很適合, 因為時間短, 多核的好處也可以藉著多 thread 用的到. 另外 canon codec 因為限制較多, 我需要它以較高的 priority, 並且要在第一時間就開始跑, 才不會拖慢整個轉檔的處理時間... 理想的 task 安排狀況應該要像這樣:

    簡報1

     

    最後找到一個我比較滿意的解, 就是另外寫一個合用的 ThreadPool... @_@

     

    其實我是很不想做重新發明輪子這件事, 不過除此之外實在沒什麼好方法. 所幸 .net 下要自己弄出個 thread pool 也不難. 這一切都要感謝當年在 yam, 當時研發部的一位主管, 交大的學長, 現在跑到 Microsoft 去了, 我們都叫他 "旺旺" .. 他技術能力只能用 "神" 來形容... 當時他在公司內開了門課, 真是印像深刻. 就用 java 示範了如何寫 ThreadPool ... 寫起來還真沒幾行... 扣掉一堆 import (相當於 c# 的 using) 等宣告之類的 code, 整個功能 "完整" 的 thread pool 大概只有一百行左右的 code... 而且 thread 動態 create 跟回收等功能一樣不少... threads 之間同步問題也沒漏掉..

    我歸納了一下我需要的 ThreadPool 到底要什麼功能, 而內建的到底缺什麼... 要怎麼做就很清楚了... 要解決上面的問題, 我大概需要這樣的 thread pool 來支援我的想法:

    1. thread 的數量不需要是動態的, 固定的就夠了. 一次開太多 thread 效果不見得好.
    2. thread 一定要能設定 priority. 因為轉圖檔是 cpu bound 的工作, priority 設低一點對整體的回應時間比較好.
    3. 需要多組 thread pool. 我的想法是用一組專用的 thread pool 來處理 canon raw codec, 只要 1 thread 就夠 (以後 canon 真的改善的話再加大數量). 另外其它 (大部份都是 jpeg codec) 的工作就丟到有 4 threads 的 thread pool 去跑. 至少到四核的 cpu 都還能夠充份的利用到.
    4. 需要簡單的作法, 能夠 wait thread pool 裡的工作全處理完. .net 內建的也可以, 不過必需透過比較麻煩的 WaitHandle 自己去 wait ...

    這些剛好都是我需要, 但是 .NET 內建的 thread pool 做不到的需求. 因此自己寫了個簡單的 SimpleThreadPool .. 介面規格就儘量比照內建的 ThreadPool (因為 code 已經寫好不想改太多 [:P]). 用起來像這樣:

     

       1:          private static void SimpleThreadPoolTest()
    
       2:          {
    
       3:              SimpleThreadPool stp1 = new SimpleThreadPool(2, System.Threading.ThreadPriority.BelowNormal);
    
       4:              SimpleThreadPool stp2 = new SimpleThreadPool(1, System.Threading.ThreadPriority.Lowest);
    
       5:   
    
       6:              stp1.StartPool();
    
       7:              stp2.StartPool();
    
       8:   
    
       9:              for (int count = 0; count < 10; count++)
    
      10:              {
    
      11:                  stp1.QueueWorkItem(
    
      12:                      new WaitCallback(ShowMessage),
    
      13:                      string.Format("STP1[{0}]", count));
    
      14:                  stp2.QueueWorkItem(
    
      15:                      new WaitCallback(ShowMessage),
    
      16:                      string.Format("STP2[{0}]", count));
    
      17:   
    
      18:                  Thread.Sleep(13);
    
      19:              }
    
      20:   
    
      21:   
    
      22:              Console.WriteLine("wait stop");
    
      23:              stp1.EndPool();
    
      24:              stp2.EndPool();
    
      25:          }
    
      26:   
    
      27:   
    
      28:          private static void ShowMessage(object state)
    
      29:          {
    
      30:              Console.WriteLine("ThreadID: {0}, state: {1}", Thread.CurrentThread.ManagedThreadId, state);
    
      31:              Thread.Sleep((new Random()).Next(1000));
    
      32:          }
    

     

    嗯, 功力跟旺旺比差了一點, 不過也是一百出頭行就搞定這個 ThreadPool ... [:D], 接下來就是火力展示了... 因為介面跟內建的 ThreadPool 幾乎一樣. 就簡單測一下 125 JPEG + 20 G9 RAW + 2 G2 RAW files 一起做轉檔時的 CPU 使用率記錄...

    圖一. 用內建的 ThreadPool, 110 sec ( UI 回應正常, 進度列也會跑. 不過礙於 CPU loading 關係, ImageBox 的圖都沒出來)

    image

     

     

    圖二. 改用我自己寫的 SimpleThreadPool, 90 sec. 因為調整過 priority, 每張圖轉完 ImageBox 都會立即顯示出來.

    image

     

    第一張圖, 所有的 job 都依序執行, 簡單的 jpeg 都擠在前段, 那段 cpu 100% 就是這樣來的. 後面就都是 canon decoder 在跑, cpu 大約都維持在 50% 左右, 直到跑完為止.

    而第二張圖, jpeg / canon 都強迫同時一起執行. 而 canon 的 priority 略高於 jpeg. 因此排程的策略是優先執行較慢的 canon decoder, 而剩餘的 cpu 運算能力就拿來處理 jpeg 的部份. 因為 cpu 使用率的統計圖下的面積 (積分) 就是總共需要的運算量. 看的出來維持在 100% 的部份越短, 則總體完成的時間就會拉長... 後面自定的 thread pool 的作法, 不論在 UI 回應, 跟整體處理的時間都比較好. 看來適度的調整 thread 數量, 跟 thread priority 還是很有用的. 不過題外話, thread 再怎麼用, 效果還是不如 lib or compiler level 做的平行處理效果來的好. ZD Net 上有一系列 intel 提供的 video, 講的還不錯. Microsoft 也替 .NET 開發了一套 Library (download), 只要調整一點語法, 就可以把 loop 內的運算轉成平行運算, 這種效果遠比用 thread pool 來的聰明 & 有效. 不過還在 community preview 就暫時不考慮採用了.

    總算, 搞定了 thread pool, 也搞定了 metadata, 幾個主要的障礙都排除了. 兩個要開發的工具也完成了一個 ( image resizer ), 剩下的歸檔程式就剩下納入 video encoder 的部份也就大功告成了. 有力氣的話會再寫一篇吧, 敬請期待 [:D]

    2007/12/12 系列文章: Canon Raw Codec & WPF .NET WPF 作品集 多執行緒

  2. Canon Raw Codec + WPF #1, WPF Image Codec, Metadata

    託 Canon G9 的福, 這一個月來的空閒時間都在研究 Windows Presentation Foundation 裡的 Image Codec 相關事項. 幹嘛買個相機還這麼辛苦? 因為原本算計好的計劃, 就差這一環啊... 雖然老早就有換機的計劃, 為什麼龜了那麼久 G9 一出來就跑去買? 除了之前講了一堆相機本身的考量之外, 剩下的關鍵因素是 RAW support. 因為:

    1. Canon G9 "又" 開始支援 RAW file
    2. Canon 正好搭配 WPF (windows presentation foundation), 發表了它專屬的 RAW file codec.
    3. WPF 裡提供了許多 JPEG 無法帶來的好處, 我打的如易算盤是: 不管未來是什麼東西取代了 JPEG, 留著 RAW 一定沒錯, 因此支援 RAW 就大大加了不少分.

    RAW support 在我看來是必要的. 照片可不能等十年後再搭時光機回來照, 而現有的 JPEG 又已經是老古董的規格了, 未來是一定會有取而代之的新規格. 會是什麼我不曉得, 不過留著 RAW 準沒錯. 只要 Canon 沒倒, 未來一定有辦法把 RAW 轉成新的通用格式, 而不用經過 JPEG 的折損...

    未來看起來很美好, 不過當 G9 入手後, 事情沒有想像的順利, 有了 WPF + Codec, 我自己必需寫些小程式來簡化未來例行的相片歸檔動作. Codec 只要去 Canon 下載就有, WPF 則是新東西, 得自己先研究一番... 搭配 WPF, Microsoft 也推出了新的圖型檔格式: HD Photo. 它的一堆好處我就不多說了, Microsoft 網站多的是. 我在意的是, HD Photo 提供的新功能, 包括廣大的色域等, 也會對應的在 image codec 裡提供. 因此如果 RAW file 本身就包含這些資訊的話, 透過 codec 讀出來就不會有資訊的折損, 存成 JPEG 就沒有這些好處了.

    實作第一步, 當然是先研究 WPF 關於 Image 物件的基本處理. 嗯, 果然是跟之前的 GDI / GDI+ 不一樣. 感覺起來 GDI 典型 application 就是像 "小畫家" 這類的 AP, 而 WPF 典型的 application 就是像 flash 這類的, 裡面的物件已經變成圖型來源, 套用各種 transform, 層層處理套上去後得到的結果才是你看到的東西, 大概就類似 photoshop 的 layer 那樣的東西.

    講了那麼多, 其實我也只是要用到 codec 來讀取 canon raw file, 把圖檔縮成我要的像素, 存成指定的 jpeg 檔而以... 我就以這個例子貼一段 sample code

       1:  BitmapDecoder source = BitmapDecoder.Create(
    
       2:      new Uri(@"C:\IMG_0001.CR2"),
    
       3:      BitmapCreateOptions.DelayCreation,
    
       4:      BitmapCacheOption.None);
    
       5:  JpegBitmapEncoder target = new JpegBitmapEncoder(); 
    
       6:   
    
       7:  target.Frames.Add(BitmapFrame.Create(
    
       8:      new TransformedBitmap(source.Frames[0], new ScaleTransform(0.3, 0.3)),
    
       9:      source.Frames[0].Thumbnail,
    
      10:      metadata,
    
      11:      null)); 
    
      12:  target.QualityLevel = 80; 
    
      13:   
    
      14:  FileStream trgs = File.OpenWrite(@"C:\IMG_0001.JPG");
    
      15:  target.Save(trgs);
    
      16:  trgs.Close(); 
    

    而過去也寫過 GDI+ 版本的, 那個我就不貼了. 老實說 code 也不會太多, 不過寫起來就覺的是兩種不同層次的思考邏輯. 也隨著這次機會花了點心思研究 System.Windows.Media.Imaging 裡的東西, 就開始想把舊的程式都翻一翻.. 包括了之前的歸檔程式, 及另一個批次縮圖的工具. 後面有機會再貼.

    圖檔基本內容處理掉之後, 接下來就是 exif. 我很在意這些圖檔隱藏的資訊, 也不知道為什麼, 哈哈. 上面的 code 轉完是沒有半點 EXIF 的, 沒轉過來感覺就像少了什麼... 無奈在處理 metadata 時又碰到了一些小 trouble ...

     

    花了一些時間搞定了 metadata, 不過又碰到不同檔案格式之間的 metadata 轉換問題. WPF 的 Image Codec 已經把 metadata 的讀寫方式給 "抽像化" 了, 所有圖檔的 metadata 都用一樣的方式讀寫. 它採用的是類似 xpath 的 metadata query 來指明目標是那個 metadata, 然後再用 GetQuery( ) 來讀值, 或是用 SetQuery( ) 把值寫進去. 現在碰到的問題是 Canon Raw 的 query 跟 JPEG exif 用的對應不起來. 我也不知道怎麼解, google 找幾個 sample 對照著比一比, 摸黑試了幾種對應方式, 竟然看起來還好像猜中了, 就不管先用下去. 我簡單的把整理的對照表貼一下...

    /ifd/{ushort=256} --> /app1/ifd/exif/{ushort=256}
    /ifd/{ushort=257} --> /app1/ifd/exif/{ushort=257}
    ...

    請不要問我這是啥意思, 我真的也搞不懂, 看了 w3c 一些 spec, 真是天書... 大概只知道 metadata 有幾種規範, exif, xmp, ifd 等等. 而 ushort=256 大概就是指整個 block 裡, 第 256 bytes 位置的 ushort 的值就是這筆資料存放的地方等等. 我是拿幾張照片轉換後對照著看, 看起來對就將就著用了. 最後是用程式跑了一份看起來可用的對照表, 存成 xml 檔, 丟在自己寫的 library project 裡, 當作 embedded resource. 供未來轉檔的動作時拿出來用. library 包裝好之後用起來像這樣:

     

       1:  ImageUtil.SaveToJPEG(
    
       2:      @"c:\IMG_0001.CR2",
    
       3:      @"c:\IMG_0001.JPG",
    
       4:      800,
    
       5:      800,
    
       6:      75);
    

     

     

    弄到現在, 總算把最基本的動作: 轉檔 (含 exif) 給搞定了. 總算有足夠的資訊把 library 給弄好. 不過馬上就碰到第二個大問題... "效能". 這部份就留著下一篇吧.

    2007/12/12 系列文章: Canon Raw Codec & WPF .NET WPF 作品集 多執行緒 技術隨筆 當年勇

  3. 前言: Canon Raw Codec 1.2 + .NET Framework 3.0 (WPF)

    搞了好幾天, 終於理出點頭緒了. 自從 Canon 推出 1.2 版的 codec 之後, G9 拍的 .CR2 支援問題總算是往前跨了一大步, 至少在 XP / Vista 下可以直接顯示 .CR2 了. 接下來就是如何讓它自動化等等問題.

    WPF寫起來很簡單, 效率的問題就先擺一邊了 (很理想的預期 canon 會在未來版本會改善... 咳...), 不過 EXIF 的問題還真是令我傷透腦筋... 前前後後碰到幾個問題, 加上官方文件很多細節沒有提供, 讓我碰了不少釘子... Orz. 先整理一下碰過的釘子有那些 (現在當然拔乾淨了才有心情打這篇.. 哈哈 [H]), 先列一下問題最大的 metadata:

    1. Metadata抓不到, BitmapSource.Metadata 抓出來都是 null ..
      (後來發現文件漏掉一行... Orz, 目前版本不提供 BitmapSource.Metadata, 只提供每個 Frame 自己的 Metadata ...)
    2. 內建的 Metadata 只有十個不到的欄位 (ApplicationName, CameraModel, ...), 問題是 exif 有一堆啊..
    3. WPF 改用 "Metadata Query Language", 類似 xpath 之於 xml document 一樣... 看起來就像 "/ifd/{ushort1000}" 這樣. 所有底層動作都是 GetQuery( ) / SetQuery( ). 不過沒有地方讓我列舉出所有已存在的 metadata query 啊...
    4. 文件上說用 InPlaceMetadataWriter 可以修改 metadata, 不過到現在我還是試不出來 -_-
    5. EXIF 上百個欄位, 對應的 query, 官方文件一個字都沒提到... 冏rz...
    6. .CR2 解出來的 metadata 跟 .JPG 廣為接受的 EXIF, 對應的 query 完全不一樣...

    另外其它跟 metadata 無關的問題也有幾個:

    1. Canon Codec 的效能不怎麼樣, G9 的檔案 (4000x3000, 15mb 左右) 全幅解開, 接上 JpegEncoder 存同尺寸 100% quality 檔案, 在我的 Core2Duo E6300 (2GB ram, XP MCE2005 SP2) 足足要 80 sec ...
    2. 多處理器佔不到便宜. 雙核CPU跑下去, 處理器只有約 50% ~ 60% 使用率. 改了改程式, 開兩個 thread 下去也一樣, 殘念... ( Microsoft 的就要誇一下, 內建的 codec 就運作的很好... 又快, thread pool 用下去也享受的到全速.. [Y])
    3. 怪的很, Microsoft 提供的 viewer 直接看 G2 的 .CRW 一切正常, 不過透過 WPF 就會得到 Exception .. 還沒解.

    這些鳥問題都在 MSDN 找不到直接的答案, 只好埋頭苦TRY了. 好消息是主要問題都解的差不多了. 先簡單列一下 solution, 後續的等我 [歸檔程式] 改版完成後再來專欄報導..

    1. Metadata Query 列舉的問題原來隱藏在實作的 interface 裡.. [:@], 氣的是官方文件還沒有任何說明 & 範例. 原來 BitmapMetadata 實作了 IEnumerable<string>, 直接把 BitmapMetadata 丟到 foreach 裡就是了...
    2. 修改 metadata 的動作, 暫時由 metadata.clone() 之後修改, 再加到 encoder 裡可以閃開碰到的問題, 就不理它了
    3. EXIF 問題, 因為 (1) 有解了, 加上 google 找到其它 sample, 東拼西湊誤打誤撞也被我試出來... 哈哈
    4. 效能問題一樣無解, 只能改程式儘量把不相干的 job 排在一起, 想辦法把空閒的 CPU 運算能力吃掉... 就看是我改的快還是 canon 改的快了 [H]..

    前言大概就先打到這裡, 沒啥內容, 都只是預告片而以, 被它折磨了兩個禮拜, 當然要先貼一篇發洩一下. 剩下的工作就單純多了, code 改到一個段落我就會繼續寫後續幾篇. 這次會包括兩個 project, 一個是 Image Resizer, 另一個就是之前好幾篇都在講的歸檔工具. 敬請期待!

    替舊文章打一下廣告... [H]

    2007/11/26 系列文章: Canon Raw Codec & WPF .NET WPF 作品集 多執行緒 技術隨筆

  4. 網站升級: CommunityServer 2007.1

    周日下午趁小孩都回外婆家, 花了點時間把家裡該裝的裝一裝, 該接的接一接, 還有一點空檔, 就把拖了很久的網站升級處理一下... 原本的版本是 CS 2007 (3.0), 中間推出了 3.0 SP1, SP2, SP3 beta 都跳過去沒理它, 這次 2007.1 (3.1) 出來手又癢了起來...

    過程就沒啥好說了, 失敗了好幾次, 最後決定整個重裝... 抓了 2007.1 的官方版本, 把舊的 db 配上它的 upgrade script 執行完後掛上去, 基本功能就會動了, 最後再把 ~/blogs, ~/photos, ~/forums 等有 storage 的目錄搬過去, 再把我自己客制過的 themes 重改一次 ( my god, themes 裡的檔案全都調過, 原本的 themes 蓋過來可以跑, 不過心裡毛毛的 )... 總算大功告成. 事後順手也把同一台 server 另外兩套 CS 也順便升級了一下.

    老實說我也沒很注意 2007.1 到底改了啥, 就貼一下吧, 搞不好大家之前碰到的鳥問題已經被解決掉了... 正好鴕鳥混過去, 哈哈 [H]

    以下是 CS2007.1 release notes:

    Below are changes available in Community Server 2007.1
    -------------------------------------------------------------------

    Enhancements
    - Updated caching framework, performance updates, added locking support for several of the application-wide collections
    - SQL performance updates and best-practices updates
    - Added CreateEditWeblogPostForm, DeleteWeblogPostForm, and associated sub-form controls from CS2008 to support creating/editing/deleting blog posts in the front UI using Chameleon.
    - Updated styles on the TinyMCE wrapper's content to provide some default spacing and use a larger default font size.
    - Updated TagCloud controls to support disabling the "no tags" message and "no related tags" messages.  Updated all existing themes (except for tag browsing pages) to not render the "no tags" message.
    - Updated SqlProviders to resolve LINQ SortOrder namespace ambiguity
    - Added support for sorting and paging LinkCategory and Link objects in the API and via Chameleon.
    - Added toggle button for enabling/disable application tokens
    - Tweaked app tokens list a little bit to show the time for the last used column
    - Added a new AdPlacementOptions to WrappedRepeater, AlternatingSeperator - places an ad after every other item starting after the first.
    - Updated TinyMCE to use the latest wrapper.
    - Updated the email job only retrieves as many messages as it will send from the email queue (prevent large queues from causing timeouts)
    - Updated notifications and mass emails to enforce the check on a user's "Enable Email" global setting and "Allow Site to contact me" setting
    - Updated email notifications to check the enable thread tracking for post replies
    - Updated mass emailing to take place on a background thread
    - Updated Telligent.Registration.dll to address an issue where the add-ons could get stuck if they start before SQL on a reboot/startup
    - Updated Telligent.MailGateway.Common.dll to address issues with XML cleaning in the core library and downloading only as many messages as needed from the email queue
    - Updated user date formats so that month-day-year is 6-1-2007 instead of 06-01-2007
    - Updated Windows Live Writer support by implementing keywords for custom tags and removing excerpt support since it gets confused with text-mode.
    - The error messages were updated so that the actual error message is displayed more prominently.
    - Removed the AutoDeleteThreshold setting from the forum control panel since it is not implemented.
    - Updated stylesheet to not underline the group expand/collapse toggle button.
    - Updated version of CookComputing XML-RPC.NET library to use new .NET 2.0 optimized verison
    - Updated list of default Weblog Ping URLS (removed Blo.gs and PubSub.com, added PingOMatic.com)
    - Implemented TruncationEllipsisTemplate on the ObjectDataBase control to support custom markup/controls being used in the TruncationEllipsis
    - Enabled adding new categories inline through Windows Live Writer
    - Added rsd.ashx and wlwmanifest.ashx in web project, and added namespaces (Added support for RSD and WLWManifest).
    - Updated MetaBlog to support excerpts, read-more, and post names
    - Updated blog truncation to use readmore links
    - Updated Metablog to default to the users current blog
    - Added auto discovery for the current blogs metablog path
    - Added basic site and blog theme
    - Updated email templates for forum and forum thread emails to remove the background grey color.
    - CSContext.User is only overridden with TokenUser when told via AllowTokenRequests(bool requirePrivateToken)
    - Added rendering of news to the "Traveler" blog theme's sidebar.
    - Added support for TemporaryUserTokens that expire after 3 hours
    - Change password now uses a temporary user token
    - Added support for disabling exception logging. It is disabled by default.
    - Moved keep-alive code from global.js into the KeepAlive control.  Updated Editor control to *always* render a KeepAlive control.  Deleted web/utility/keepalive.aspx
    - Added a few performance improvements to ThreadQueryBuilder classes: Only joining to cs_threads if we really have to, Adding a cs_Sections.ApplicationType filter back in
    - Changed the expiration date from 30 days to 7
    - Exception logging now occurs in background cache tasks

    Bug Fixes:
    - FileSystemWatcher pathing fix
    - Request/Response encoding fix
    - You can now resize the editor horizontally in the content editor modals
    - You can now override an editor option without specifying type on the control
    - You are no longer redirected to login when browsing a site that has forums at root while you are anonymous.
    - Updated inline text editor to not overlap its popup container
    - Updated Telligent.Glow.Modal to use frameborder='0' instead of frameborder='no'
    - Create/Edit Blog Page Validation fixed so that appkey cannot be blank
    - Added code and note bbcode and updated existing processing order of scrubbing modules
    - Enabled checking of the user's Enable Email setting on a wide variety of message types
    - Corrected all references in Chameleon controls to OpenWindow function in global.js to use a direct call to window.open.
    - Updated Forum BreadCrumb control to use the current rewritten URL name instead of the rendered URL to determine the current page
    - Updated EntryThumbnail control to render the file extension in the alt attribute.
    - Updated EntryThumbnail control to render with an Image control and default to 0 border width and no alignment.
    - The parent post cache is now expired properly when creating a new post in a thread.  This allows a reply to post to always display in a thread after it is created.
    - Create edit blog post now maintains state better
    - Added validation for the user's email address to Users.Create
    - Fix for Gallery search results from searchbarrel linking to image not to gallery page
    - Removed the ability to rename or delete the anonymous user
    - Fixed issue where GalleryService.Update failed to set the PostID, which caused it to always fail.
    - Updated cs_User_Delete sproc to update author/post ID's as well as names
    - Disabled subforums no longer require user to login in parent forum
    - Fixed theme cache name so that the cache key is correct.  Previously theme configuration were never getting retrieved from cache correctly.
    - Changed create user page so that validation occurs when fields change as oppose to whenever a key was pressed.
    - Group RSS Feed no longer causes Exception
    - Pager added to the default aggregateentrylist control for the file gallery
    - Clicking the Advanced Search link from a search results page now populates the advanced search options form for the lean and green theme as well as default
    - Corrected QuickReply link to only refresh the page if false (and not undefined OR false) is passed as the callback parameter.
    - Fixed EXIF page to show the full list of tags.
    - Fixed photo post edit so it decodes the subject before populating the text box in the CP (to prevent double encoding)
    - Fixed all auto-syndication registration to not re-html-encode section names.
    - Fixed issue with users in the Member Administrators role not being able to change user passwords
    - Fixed spelling error in the API... renamed User.EnableAvtar to User.EnableAvatar
    - Updated default and leanandgreen themes to hide "view all users" link when "Display Member List" is set to "No" in the Control Panel.
    - The SaveExtendedUserData call was moved into the event handler for the submit button, before the first call to sub-forms.
    - You can now delete a tag that is disabled.
    - User Points can now display without Post Points.
    - Fixed issue with order of permissions not being handled properly
    - Control Panel Report page title now shows correct text
    - Fix for linking over to Shutterfly showing 0x0 as the picture's size.
    - Fix for null reference on private messages from CS 2.x that were to users that were later deleted
    - Fixed ForumSqlProvider to save sticky info on edited posts
    - Corrected issue resulting in multiple encoding of the AvatarUrl property.
    - Updated edit user form in the control panel to always show the user's Username in the "Alias" field.
    - Updated blog admin control panel to properly decode the blog name.
    - Corrected FireFox rendering issue on user+avatar lists in the default and lean and green themes.
    - Fixed issue where Weblog XML-RPC pings do not get sent in some scenarios.
    - Corrected misplaced </div> tag issue in PoisonIvy, Gertrude, Luxinterior, and Photos blog themes causing nested comments.
    - Changed Roller Blog add-feed sproc to set Last Modified to current time - interval, so that the feed gets pulled the next time the job runs after the feed is added.
    - Corrected rendering issue in the Control Panel in FireFox prior to JavaScript loading
    - Updated the HTMLScrubber regex to use slightly different syntax which prevents infinite loop issue in FireFox.
    - Corrected invalid anchor tag in blog themes.
    - Added check for cs_Posts.IsIndexed in all SearchBarrel-generated queries.
    - Fixed failed check to see if the user was anonymous within MailGateway
    - Fixed how SPAM blocker counts links
    - Fixed an issue with a missing resource label
    - Updated CallbackPager to always render the PagedContent contents.
    - Fixed issue with deserialization returning as successful when the output object is null
    - Blog pages now show up in the tag post list if set to be aggregated, and the aggregate options are visible when creating a new page.
    - Corrected thread view count to register one view per thread per rendered page regardless of the number of posts displayed on the page.
    - Removed script to enable/disable "Join" button on the registration form in the default and lean-and-green themes to prevent issues with auto-complete.
    - Updated TinyMCE wrapper to set the document_base_url TinyMCE option to the parent window's URL when the editor is opened in a Modal.
    - Fixed notifications of message being flagged for moderation by MailGateway being queued with SettingsID of 0
    - License usage colors are now cleared after uploading a license.
    - Updated truncation ellipsis markup to render within the content wrapper (link) on ObjectDataBase control.
    - Corrected next/previous thread links to direct to the thread's URL.
    - Updated UserAvatarSubForm to set the remote avatar URL (if available) when an avatar is uploaded.
    - cs_system_GenerateWeblogYearMonthDayList and cs_vw_weblog_PostByYearMonth now has some sql included to attempt to build the roll-up tables.
    - Fixed regression from Bug Fix #1391 with AppKey being a required field on the blog creation page
    - Selecting 'Hide Topics I've Read' in the forum filtered thread control now keeps the unread announcements visible on the first page
    - You can now delete a forum post without it sending email
    - Tweaks to cs_weblog_Post_Create and cs_weblog_Post_Update to ensure that UserTime was never NULL.
    - Corrected potential XSS issue in User RSS Feeds
    - Added EnsureHtmlEncoded calls to loaded TemporaryRssFeeds and TemporaryRssFeedItems content.
    - Updated UserSearchForm to redirect to the rewritable URL instead of directly into the current theme.
    - Pager fixed in the manage photo comments page so that you can page past the first 2 pages.
    - Membership.GetRoles result set creation updated to ensure roles and role icons are re-populated after cache expiration
    - Updated default Regex validation patterns for user names and passwords and ensured that these patterns always match the entire string when set.
    - Updated sql to only change the regex pattern if the pattern [a-zA-Z]+[^\<\>]* was in the UsernameRegex before
    - Added tabindex="-1" to all TinyMCE buttons to prevent tab-stops when navigating into the editor using the keyboard.
    - Added validation of RSS feed URLs and external avatar URLs to ensure they are HTTP-based.
    - Updated SearchBarrel to require Read access from applications supporting Read permissions.
    - Adding ']' to a post no longer causes the post to pass the duplicate post check.
    - Disabling post emoticons now hides the emoticon radio button list from the Forum options tab
    - File Gallery comment URL's now work correctly, displaying the entry they belong to
    - Corrected issue preventing section filters from being saved.
    - Updated the form adapter to only update the form's action attribute when the page's URL has been rewritten by CS to ensure compatibility with external, non-rewritten pages within CS.
    - Updated the thread queries used by blog and file gallery search indexing to specify IgnorePermissions=true so that all blogs and file gallery posts are indexed.
    - Corrected infinite redirect issue when an invalid character exists in the URL.
    - Changed const string cacheKey = "UserLookupTable" to include SettingsID
    - Photo Gallery now supports HTMLEncoding a submitted user name field
    - Added ApplicationName to the UserRoleNames cache key
    - Corrected page height issue in IE when using tabbed panes.

    2007/11/12 Community Server 技術隨筆 有的沒的 水電工

  5. Canon G9 入手, 不過...

    想了很久的 Canon PowerShot G9 終於狠下心的敗下去了, 買了英日機的水貨, 約比公司貨便宜三千塊... 其實已經買了兩個禮拜, 但是碰到一堆小障礙, 所以拖到現在才寫 BLOG...

    打從 G6 就開始物色新機, G6 因為跟 G2 都採用 DIGIC chip, 功能效能都沒啥大長進, 連 video 也都是很兩光, 不考慮... S2 IS, S3 IS 沒有熱靴不考慮, S5 IS 撐了很久, 最後還是決定留在 G 系列. G7 換了 DIGIC II 則是大改版, 光圈變小, 翻轉 LCD 沒了, 連 RAW 都沒了... 不考慮. G9 跟 G7 差不多, 就是把 RAW 加回來, 換 DIGIC III ... 覺的還在可接受範圍內, 就敗了 [:D], 那 G8 呢? 很抱歉... Canon 沒出 G8 .. Orz.

    事前雖然功課作足了, 不過買回來後還是碰到了些小障礙:

    1. 畫質普普, 大部份情況跟 G2 半斤八兩, 不過有些時後 G2 還略勝一籌... 這是意料之中, 沒有很意外, 那麼小的 CCD 擠這麼多像素進去, 這是必然的. 只不過還是有點失望, 怎麼沒有奇跡出現..
    2. 像素 12M, 拍下來的 raw file 足足有 12 ~ 15mb, jpeg 也有 3 ~ 4 mb, 如果用 RAW+JPEG 模式, 最多 18mb 就去了... 附的 32mb SD 真的是只能塞牙縫... 為了這個只好去買 SDHC 的記憶卡, 連帶的讀卡機都得換掉...
    3. RAW file 解不開... 這點最頭痛. Photoshop 元件更新後認不得 G9 拍的 .CR2, Canon 自己附的 Raw Image Converter 也不吃, DPP 3.0 也不吃, Raw Codec for Vista 1.0 也不吃, Microsoft Raw Image Viewer 也不吃, Google Picasa 可以讀, 不過顏色不正常... 試了一堆支援 .CR2 的軟體, 除了隨機光碟附的 ZoomBrowserEx 之外, 沒一個能用的 [:'(]
    4. 因為 (3) 的關係, 連帶的我自己寫的歸檔程式也不能動了...

    不過還好, 除了這些缺點之外, 其它一切如預期, 老實說電子元件本身的改變, 跟鏡頭加上 IS 真的很不錯, 整體還是值得的... 這兩個禮拜就都在搞這些小問題... 因為 (3) 的關係, 只好改一下原本的歸檔程式, 同時改變習慣一定要用 RAW+JPEG 模式, 在歸檔的動作裡跳過 RAW --> JPEG 這步驟的動作.. 勉強可用. 反正 8GB SD 卡暫時也拍不滿..

    感謝老天, 就在前天, Canon 終於發怖了 Canon Raw Codec 1.2, 支援 G9 拍的 Raw File 了. 連帶的 G2 的 Raw 也在支援範圍內, 就改起程式來試看看... 不過情況也不怎麼樂觀. 細節就不講了, 以後另外再寫一篇, 我先寫初步得到的資訊:

    1. Codec 可以搭配 Microsoft .NET Framework 3.0 的 WPF ( Windows Presentation Foundation ) 使用. 雖然官方說 for Vista 32bits only, 不過我自己在 XP SP2 下也是可以用.
    2. 15mb 的 .CR2, decode 速度... 有... 夠... 慢... [:@], Core2Duo 6300 竟然要解到快一分鐘... CPU 使用率約只有 50%, 改了改程式, 用 thread pool 一次解兩個 raw file, 一樣... CPU 使用率只有 5x%... 看來這個 codec 是 Single Thread Apartment 模式跑的... 雙核 CPU 派不上用場
    3. 慢就算了, 不知是 codec 的問題, 還是 .net runtime callable wrapper 的關係, 透過 WPF 抓不到任何的 metadata (exif), 傳回的 BitmapMetadata 物件就是 null ...

    天那, 這個 codec 對我等於完全沒用了 [:'(], 歸檔程式就是靠一堆 exif 才能達到自動歸檔, 改檔名, 照片轉正... 現在不旦讀不到 exif, 同時一張解開就要花 60 sec...

    看來用 RAW + JPEG 拍照的模式得撐上好一陣子了, 要改版就得等 canon raw codec 再改善一點了..

    2007/11/05 技術隨筆 敗家 有的沒的