在“如何用MediaCapture解決二維碼掃描問題”這篇文章中,我們通過“成像”、“截圖”與“識別”三個步驟介紹了使用MediaCapture掃碼的主要過程及註意事項。本文主要針對“識別”的過程,對Barcode的概念作出一個較為簡單的介紹,同時也會討論ZXing的使用方法。 ZXing是一個Ja ...
在“如何用MediaCapture解決二維碼掃描問題”這篇文章中,我們通過“成像”、“截圖”與“識別”三個步驟介紹了使用MediaCapture掃碼的主要過程及註意事項。本文主要針對“識別”的過程,對Barcode的概念作出一個較為簡單的介紹,同時也會討論ZXing的使用方法。
ZXing是一個Java實現的開源庫,可以支持多種Barcode的識別和生成,同時也為其它的語言提供了相應的介面,比如C++、Python、.Net等等。這裡,我們使用ZXing.Net,可以很方便的集成在UWP環境中,便於掃碼工作的開發。
Barcode簡介
Barcode是一種機器可讀的數據表示方式,作為某種商品或產品的唯一標識。通常被翻譯成條碼,但我個人並不喜歡這種翻譯,因為不是所有的barcode都是條形的。當然,這應該是有歷史原因的。Barcode的形式多種多樣,按照它們的外觀,可以分為Linear barcode(一維碼)和Matrix barcode(二維碼)。你可能認為你對它們都有所瞭解,因為它們大概都是這個樣子的:
但事實上,它們有甚至有可能是這樣子的:
我們通常所說的二維碼和上文提到的二維碼有所不同,只是Matrix barcode的一種,叫做QR code。舉這些例子只是為了說明Barcode種類繁多,有些編碼格式並不常用,即使是ZXing也沒有做到所有格式的支持,開發者只需瞭解就好。
Code 39、Code 128、EAN、UPC、QR Code是我們生活中能經常見到的幾種編碼格式,同時ZXing對幾種格式都有比較好的支持。其中,UPC-A是一種國際通用的編碼格式,由12個數字構成,EAN-13是在UPC-A基礎上的一種擴充(多了一個數字)。快數一數你身邊的薯片的編碼是不是13位!如果是的話,它最前邊的兩個數字是不是“69”?在EAN-13的編碼體系中,前三位數字表示商品生產商的國家(並不是商品所屬公司的國家),中國的編碼是690~699,美國是(000~019、030~039、060~139),日本是(450~459、490~499),and so on。不同的編碼格式通常用在不同的領域,如果你看到了一個Code 39或者Code 128的Barcode,那麼這很就可能是一個快遞編碼,這個時候你就可以去那些提供快遞查詢的網站查詢一下你的快遞信息,如果有API提供出來那就更是再好不過了。至於QR Code,就是我們經常用手機掃一掃的二維碼,表示的信息更是多種多樣,並不僅僅是一個url那麼簡單,至於這些信息如何處理,是我們一會兒將要討論的內容。
配置工程
在另一篇文章中提到,可以在Visual Studio環境下,通過nuget管理器安裝ZXing.Net,如果你僅僅希望通過掃碼得到一個掃碼結果(比如字元串,或者是一個鏈接),當然可以這樣做,而且過程十分簡單。但這裡我們並不推薦這種方法,因為從NuGet上得到的package只提供了一些簡單的API介面,並沒有將ZXing.Net的API全部提供出來,至於為什麼這麼做,說實話,我也不知道,可能是為了穩定性等原因。如果你是一個比較執著的programmer,也可以在使用NuGet包的情況下,自己實現其它豐富的功能,畢竟有ZXing的源代碼可以參考,這就是開源的好處!在這篇文章中,我們還是以簡單為主,畢竟ZXing.Net已經為我們提供了編譯好的動態連接庫,有什麼理由讓我們不用呢?
Important 官網提供的庫和NuGet提供的庫API稍微有些不同,如果需要更換,需要稍作修改,但過程並不是很繁瑣。
你可以從http://zxingnet.codeplex.com/下載ZXing.Net的Release,壓縮包目錄下的/winrt/zxing.winrt.dll即是我們希望添加到工程的引用。
然後,把這個reference添加到相應的工程里就行:
獲取Barcode內容信息
首先,你可以按照“如何用MediaCapture解決二維碼掃描問題”這篇文章中提供的步驟,初始化攝像頭、設置Timer並添加Tick事件,在Tick事件中,通過調用ZXing.Net的API獲取掃碼結果。
private async void TimerTick(object sender, object e) { try { if (_mediaCapture == null) return; var props = _mediaCapture.VideoDeviceController.GetMediaStreamProperties(MediaStreamType.VideoPreview); uint width = 0, height = 0; if (props is ImageEncodingProperties) { width = (props as ImageEncodingProperties).Width; height = (props as ImageEncodingProperties).Height; } else if (props is VideoEncodingProperties) { width = (props as VideoEncodingProperties).Width; height = (props as VideoEncodingProperties).Height; } System.Diagnostics.Debug.WriteLine("Start scanning..."); Result decodeResult = null; using (VideoFrame frameFormat = new VideoFrame(BitmapPixelFormat.Rgba8, (int)width, (int)height)) { using (var frame = await _mediaCapture.GetPreviewFrameAsync(frameFormat)) { var buffer = new Windows.Storage.Streams.Buffer( (uint)(4 * frame.SoftwareBitmap.PixelWidth * frame.SoftwareBitmap.PixelHeight)); frame.SoftwareBitmap.CopyToBuffer(buffer); var reader = new BarcodeReader(); decodeResult = reader.Decode(buffer.ToArray(), (int)width, (int)height, RGBLuminanceSource.BitmapFormat.RGB32); System.Diagnostics.Debug.WriteLine(decodeResult); if (decodeResult != null) { await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { resultTextBlock.Text = decodeResult.Text; }); } } } //You can handle decodeResult by other ways. if (decodeResult != null) await Windows.System.Launcher.LaunchUriAsync(new Uri(decodeResult.Text)); } catch (ArgumentNullException ane) { System.Diagnostics.Debug.WriteLine(ane.ToString()); } catch (UriFormatException ufe) { System.Diagnostics.Debug.WriteLine(ufe.ToString()); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine("Timer tick exception: {0}!", ex); } }
得到的Result包含兩個重要的屬性: Text和BarcodeFormat。其中,Text就是相關Barcode表示的文本信息,而BarcodeFormat則是對應的編碼方式。你可能會問,知道內容就好了,要編碼方式有什麼用?這裡有個問題是,同樣的一段文本信息(尤其是純數字信息)在不同的編碼方式下可能會有不同的含義(比如兩種完全不同的商品)。
解析內容
如同前面所說,Barcode可以表示各種各樣的信息,可能是“Hello UWP!”這樣的純文本,也可能是圖書的ISBN編碼,或者是一個網路上的URL連接。這裡,我們可以通過編碼類型來判斷,因為不同的編碼類型應用場景不一樣嘛,許多一維碼根本就不支持非數字文本。此外,ZXing也為我們提供的方便的介面(NuGet上的ZXing.Net並沒有),能標識出文本的具體內容:
ParsedResult parsedResult = ResultParser.parseResult(result);
parsedResult包含以下幾種信息:
// // Summary: // Represents the type of data encoded by a barcode -- from plain text, to a URI, // to an e-mail address, etc. public enum ParsedResultType { ADDRESSBOOK = 0, EMAIL_ADDRESS = 1, PRODUCT = 2, URI = 3, TEXT = 4, GEO = 5, TEL = 6, SMS = 7, CALENDAR = 8, WIFI = 9, ISBN = 10, VIN = 11 }ParsedResultType
後續工作
有了以上的內容,我們就可以對信息作進一步的處理,這就需要依賴於第三方服務提供的API介面了。
快遞:
“快遞100”為用戶提供了一個非常方便的頁面,通過快遞條碼就可以輕鬆查詢到快遞信息。
http://m.kuaidi100.com/result.jsp?nu={0}
如果想要自定義頁面,則推薦使用其API: http://www.kuaidi100.com/openapi/
商品:
亞馬遜為其網站的商品提供了商品搜索的API,通過提供條碼Id及其類型,則可以查詢到相應商品信息。
在ItemLookup頁面中,填寫一些查詢的基本信息,Marketplace可供用戶選擇查詢的數據源,webservices.amazon.com為美國的市場,中國市場可以選擇webservices.amazon.cn。下麵的三個參數需要用戶註冊亞馬遜的AWS服務(註冊過程相當複雜╮(╯_╰)╭)。
在ItemLookup的過程,設置ItemId(code信息)和IdType(這裡可以選擇ASIN、SKU、UPC、EAN、ISBN),然後點擊Run request就可以生成Request請求的URL,並且能獲取到響應的伺服器Response——一個xml文檔,包含商品的各種信息。
Signed Request URL:
http://webservices.amazon.com/onca/xml?AWSAccessKeyId=********************&AssociateTag=************&IdType=UPC&ItemId=431604028525&Operation=ItemLookup&ResponseGroup=Images%2CItemAttributes%2COffers&SearchIndex=All&Service=AWSECommerceService&Timestamp=2016-05-30T12%3A49%3A51.000Z&Signature=**********************************************
Response:
<?xml version="1.0" ?> <ItemLookupResponse xmlns="http://webservices.amazon.com/AWSECommerceService/2011-08-01"> <OperationRequest> <HTTPHeaders> <Header Name="UserAgent" Value="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Safari/537.36 Edge/13.10586"></Header> </HTTPHeaders> <RequestId>f90faa33-3fb2-4fd7-a885-abe33ea6967f</RequestId> <Arguments> <Argument Name="AWSAccessKeyId" Value="AKIAIZNMTNCCU6OFZG4A"></Argument> <Argument Name="AssociateTag" Value="************"></Argument> <Argument Name="IdType" Value="UPC"></Argument> <Argument Name="ItemId" Value="431604028525"></Argument> <Argument Name="Operation" Value="ItemLookup"></Argument> <Argument Name="ResponseGroup" Value="Images,ItemAttributes,Offers"></Argument> <Argument Name="SearchIndex" Value="All"></Argument> <Argument Name="Service" Value="AWSECommerceService"></Argument> <Argument Name="Timestamp" Value="2016-05-30T12:49:51.000Z"></Argument> <Argument Name="Signature" Value="********************************************"></Argument> </Arguments> <RequestProcessingTime>0.1724468780000000</RequestProcessingTime> </OperationRequest> <Items> <Request> <IsValid>True</IsValid> <ItemLookupRequest> <IdType>UPC</IdType> <ItemId>431604028525</ItemId> <ResponseGroup>Images</ResponseGroup> <ResponseGroup>ItemAttributes</ResponseGroup> <ResponseGroup>Offers</ResponseGroup> <SearchIndex>All</SearchIndex> <VariationPage>All</VariationPage> </ItemLookupRequest> </Request> <Item> <ASIN>B008BO4D9G</ASIN> <DetailPageURL>http://www.amazon.com/Nature-Made-Pharmacist-Recommended-Concentrate/dp/B008BO4D9G%3FSubscriptionId%3DAKIAIZNMTNCCU6OFZG4A%26tag%3Dfreshomer-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3DB008BO4D9G</DetailPageURL> <ItemLinks> <ItemLink> <Description>Technical Details</Description> <URL>http://www.amazon.com/Nature-Made-Pharmacist-Recommended-Concentrate/dp/tech-data/B008BO4D9G%3FSubscriptionId%3DAKIAIZNMTNCCU6OFZG4A%26tag%3Dfreshomer-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386001%26creativeASIN%3DB008BO4D9G</URL> </ItemLink> <ItemLink> <Description>Add To Baby Registry</Description> <URL>http://www.amazon.com/gp/registry/baby/add-item.html%3Fasin.0%3DB008BO4D9G%26SubscriptionId%3DAKIAIZNMTNCCU6OFZG4A%26tag%3Dfreshomer-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386001%26creativeASIN%3DB008BO4D9G</URL> </ItemLink> <ItemLink> <Description>Add To Wedding Registry</Description> <URL>http://www.amazon.com/gp/registry/wedding/add-item.html%3Fasin.0%3DB008BO4D9G%26SubscriptionId%3DAKIAIZNMTNCCU6OFZG4A%26tag%3Dfreshomer-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386001%26creativeASIN%3DB008BO4D9G</URL> </ItemLink> <ItemLink> <Description>Add To Wishlist</Description> <URL>http://www.amazon.com/gp/registry/wishlist/add-item.html%3Fasin.0%3DB008BO4D9G%26SubscriptionId%3DAKIAIZNMTNCCU6OFZG4A%26tag%3Dfreshomer-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386001%26creativeASIN%3DB008BO4D9G</URL> </ItemLink> <ItemLink> <Description>Tell A Friend</Description> <URL>http://www.amazon.com/gp/pdp/taf/B008BO4D9G%3FSubscriptionId%3DAKIAIZNMTNCCU6OFZG4A%26tag%3Dfreshomer-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386001%26creativeASIN%3DB008BO4D9G</URL> </ItemLink> <ItemLink> <Description>All Customer Reviews</Description> <URL>http://www.amazon.com/review/product/B008BO4D9G%3FSubscriptionId%3DAKIAIZNMTNCCU6OFZG4A%26tag%3Dfreshomer-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386001%26creativeASIN%3DB008BO4D9G</URL> </ItemLink> <ItemLink> <Description>All Offers</Description> <URL>http://www.amazon.com/gp/offer-listing/B008BO4D9G%3FSubscriptionId%3DAKIAIZNMTNCCU6OFZG4A%26tag%3Dfreshomer-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386001%26creativeASIN%3DB008BO4D9G</URL> </ItemLink> </ItemLinks> <ImageSets> <ImageSet Category="swatch"> <SwatchImage> <URL>http://ecx.images-amazon.com/images/I/51j%2BGzAmXTL._SL30_.jpg</URL> <Height Units="pixels">30</Height> <Width Units="pixels">15</Width> </SwatchImage> <SmallImage> <URL>http://ecx.images-amazon.com/images/I/51j%2BGzAmXTL._SL75_.jpg</URL> <Height Units="pixels">75</Height> <Width Units="pixels">37</Width> </SmallImage> <ThumbnailImage> <URL>http://ecx.images-amazon.com/images/I/51j%2BGzAmXTL._SL75_.jpg</URL> <Height Units="pixels">75</Height> <Width Units="pixels">37</Width> </ThumbnailImage> <TinyImage> <URL>http://ecx.images-amazon.com/images/I/51j%2BGzAmXTL._SL110_.jpg</URL> <Height Units="pixels">110</Height> <Width Units="pixels">54</Width> </TinyImage> <MediumImage> <URL>http://ecx.images-amazon.com/images/I/51j%2BGzAmXTL._SL160_.jpg</URL> <Height Units="pixels">160</Height> <Width Units="pixels">79</Width> </MediumImage> <LargeImage> <URL>http://ecx.images-amazon.com/images/I/51j%2BGzAmXTL.jpg</URL> <Height Units="pixels">500</Height> <Width Units="pixels">247</Width> </LargeImage> </ImageSet> <ImageSet Category="variant"> <SwatchImage> <URL>http://ecx.images-amazon.com/images/I/51C8Vnbv71L._SL30_.jpg</URL> <Height Units="pixels">30</Height> <Width Units="pixels">19</Width> </SwatchImage> <SmallImage> <URL>http://ecx.images-amazon.com/images/I/51C8Vnbv71L._SL75_.jpg</URL> <Height Units="pixels">75</Height> <Width Units="pixels">48</Width> </SmallImage> <ThumbnailImage> <URL>http://ecx.images-amazon.com/images/I/51C8Vnbv71L._SL75_.jpg</URL> <Height Units="pixels">75</Height> <Width Units="pixels">48</Width> </ThumbnailImage> <TinyImage> <URL>http://ecx.images-amazon.com/images/I/51C8Vnbv71L._SL110_.jpg</URL> <Height Units="pixels">110</Height> <Width Units="pixels">71</Width> </TinyImage> <MediumImage> <URL>http://ecx.images-amazon.com/images/I/51C8Vnbv71L._SL160_.jpg</URL> <Height Units="pixels">160</Height> <Width Units="pixels">103</Width> </MediumImage> <LargeImage> <URL>http://ecx.images-amazon.com/images/I/51C8Vnbv71L.jpg</URL> <Height Units="pixels">500</Height> <Width Units="pixels">321</Width> </LargeImage> </ImageSet> <ImageSet Category="variant"> <SwatchImage> <URL>http://ecx.images-amazon.com/images/I/31m-odZf5HL._SL30_.jpg</URL> <Height Units="pixels">30</Height> <Width Units="pixels">22</Width> </SwatchImage> <SmallImage> <URL>http://ecx.images-amazon.com/images/I/31m-odZf5HL._SL75_.jpg</URL> <Height Units="pixels">75</Height> <Width Units="pixels">56</Width> </SmallImage> <ThumbnailImage> <URL>http://ecx.images-amazon.com/images/I/31m-odZf5HL._SL75_.jpg</URL> <Height Units="pixels">75</Height> <Width Units="pixels">56</Width> </ThumbnailImage> <TinyImage> <URL>http://ecx.images-amazon.com/images/I/31m-odZf5HL._SL110_.jpg</URL> <Height Units="pixels">110</Height> <Width Units="pixels">82</Width> </TinyImage> <MediumImage> <URL>http://ecx.images-amazon.com/images/I/31m-odZf5HL._SL160_.jpg</URL> <Height Units="pixels">160</Height> <Width Units="pixels">120</Width> </MediumImage> <LargeImage> <URL>http://ecx.images-amazon.com/images/I/31m-odZf5HL.jpg</URL> <Height Units="pixels">500</Height> <Width Units="pixels">375</Width> </LargeImage> </ImageSet> </ImageSets> <ItemAttributes> <Binding>Health and Beauty</Binding> <Brand>Nature Made</Brand> <CatalogNumberList> <CatalogNumberListElement>474911</Cata