はじめに
今回からは数回にわたりWindows Live Photo Gallery SDKsにある、
本連載では、
Windows Live フォト ギャラリー
Windows Live フォト ギャラリー

執筆時点では、
Windows Live ムービー メーカー
Windows Live ムービー メーカー

Liveフォト ギャラリーと同じくベータ版を http://
Live Photo Gallery SDKs は、
Windows Live Photo Gallery SDKs
Live Photo Gallery SDKsは次のふたつから構成されています。
- Windows Live Photo Gallery Publishing Plug-in Platform
- Windows Live Photo Gallery Simple Extensibility Points
Live Photo Gallery Publishing Plug-in Platform
Live Photo Gallery Publishing Plug-in Platformを利用するとWindows Live フォト ギャラリーとWindows Live ムービー メーカーの投稿用プラグインの作成が可能です。いずれのLiveアプリケーションにも

Liveアプリケーションでは、
Live Photo Gallery Simple Extensibility Points
Live Photo Gallery Simple Extensibility Pointsは、

本連載では、
はてなフォトライフ
現在公開されている投稿プラグインは英語のものばかりですので、

はてなフォトライフでは、
開発環境
投稿プラグインは、
はてなフォトライフAtomAPI
具体的なプラグインの作成は次回からはじめます。今回は はてなフォトライフAtomAPIを利用して写真を投稿する部分を実装しておきましょう。
はてなフォトライフAtomAPIは、
現在 はてなフォトライフAtomAPIがサポートしている操作は、
WSSE認証
はてなフォトライフAtomAPIでは、
APIを利用して はてなのサーバーへアクセスする際には、
X-WSSE: UsernameToken Username="***", PasswordDigest="XXX", Nonce="XXX", Created="2008-12-01T12:00:00"
ヘッダ内にある各パラメータは次の値となります。
- Username
- ユーザー名
(はてなのアカウント) - Nonce
- リクエストごとに生成する使い捨てのランダムな文字列
(セキュリティ・ トークン) をBase64エンコードしたもの - Created
- Nonceが生成された日時をISO-8601表記したもの
- PasswordDigest
- NonceとCreatedと
(はてなのアカウントの) パスワードを連結し、 SHA-1によりハッシュ化した値をBase64エンコードしたもの
以上を踏まえた、
Protected Shared Function CreateWsseHeaderValue(ByVal userName As String, ByVal password As String) As String
Dim sha1 = New System.Security.Cryptography.SHA1CryptoServiceProvider
Dim created = Now.ToString("s") ' Created
Dim nonce = Guid.NewGuid.ToString ' Nonce
Dim passwordDigest = Convert.ToBase64String( _
sha1.ComputeHash(System.Text.Encoding.ASCII.GetBytes(nonce & created & password))) ' PasswordDigest
Return String.Format("UsernameToken Username=""{0}"", PasswordDigest=""{1}"", Nonce=""{2}"", Created=""{3}""", _
userName, passwordDigest, Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(nonce)), created)
End Function
ユーザー名とパスワードを引数として渡して使用します。処理内容は上記の通りです。Nonce用の値はGUIDを利用しています。
新規投稿用のアドレス取得
続いて写真を新規投稿するためにアクセスするアドレスを取得する部分を実装します。まず、
応答されるデータは次のようなXML文書になっています。
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://purl.org/atom/ns#">
<link type="application/x.atom+xml" rel="service.post"
href="http://f.hatena.ne.jp/atom/post" title="sample">
<link type="application/x.atom+xml" rel="service.feed"
href="http://f.hatena.ne.jp/atom/feed" title="sample">
</feed>
<link rel="service.post">要素のhref属性の値が、
Imports <xmlns="http://purl.org/atom/ns#">
Protected Shared Function GetPostUri(ByVal userName As String, ByVal password As String, ByRef title As String) As String
' リクエストの作成
Dim request = DirectCast(WebRequest.Create("http://f.hatena.ne.jp/atom"), HttpWebRequest)
With request
.Method = "GET"
' WSSE認証用
.Headers.Add(HttpRequestHeader.Authorization, "WSSE profile=""UsernameToken""")
.Headers.Add("X-WSSE", CreateWsseHeaderValue(userName, password))
.Accept = "application/x.atom+xml, application/xml, text/xml, */*"
.ServicePoint.Expect100Continue = False
End With
' レスポンスの取得
Dim document As XDocument
Using response = DirectCast(request.GetResponse, HttpWebResponse), _
reader = New System.IO.StreamReader(response.GetResponseStream, System.Text.Encoding.UTF8)
document = XDocument.Load(reader)
End Using
' <link rel="service.post">要素の取得
Dim elements = From e In document.<feed>.<link> Where e.@rel = "service.post"
title = elements.First.@title ' title
Return elements.First.@href ' PostUri
End Function
HttpWebRequestオブジェクトを作成してルートAtomエンドポイントにアクセスしています。リクエスト時に先ほど作成したCreateWsseHeaderValueメソッドを使用してWSSE認証用のヘッダを追加しています。
レスポンスは、
例外処理は記述していませんので注意してください。
写真の新規投稿
最後に写真を新規投稿する部分を実装します。この部分は作成する投稿プラグインとも密接に関わってくる部分ですので、
取得したPostURIにHTTP POSTメソッドによりアクセスします。POSTデータには次の書式の<entry>要素を指定します。
<entry xmlns="http://purl.org/atom/ns#">
<title>[写真のタイトル]</title>
<content mode="base64" type="[Content-Type]">[画像データをBase64エンコードしたもの]</content>
<hatena:generator xmlns:hatena="http://www.hatena.ne.jp/info/xmlns#" url="example.jp" version="1.0">[アップロードツール名]</hatena:generator>
<dc:subject xmlns:dc="http://purl.org/dc/elements/1.1/">[フォルダ名]</dc:subject>
</entry>
レスポンスは、
新規に写真を投稿できる最低限のコードを以下に示します。メソッドの引数にユーザー名、
Imports <xmlns="http://purl.org/atom/ns#">
Imports <xmlns:hatena="http://www.hatena.ne.jp/info/xmlns#">
Imports <xmlns:dc="http://purl.org/dc/elements/1.1/">
Protected Shared Sub PostPhoto(ByVal userName As String, ByVal password As String, _
ByVal postUri As String, ByVal photoPath As String)
' リクエストの作成
Dim request = DirectCast(WebRequest.Create(postUri), HttpWebRequest)
With request
.Method = "POST"
' WSSE認証用
.Headers.Add(HttpRequestHeader.Authorization, "WSSE profile=""UsernameToken""")
.Headers.Add("X-WSSE", CreateWsseHeaderValue(userName, password))
.ContentType = "application/x.atom+xml"
.Accept = "application/x.atom+xml, application/xml, text/xml, */*"
.ServicePoint.Expect100Continue = False
End With
' 写真をバイト配列として読み込み
Dim photoBuffer = New Byte() {}
Using stream = New System.IO.FileStream(photoPath, IO.FileMode.Open, IO.FileAccess.Read), _
reader = New System.IO.BinaryReader(stream)
If stream.Length <= Integer.MaxValue Then
photoBuffer = reader.ReadBytes(CInt(stream.Length))
End If
End Using
' <entry>要素
Dim entry = <entry>
<title>Sample</title>
<content mode="base64" type="image/jpeg"><%= Convert.ToBase64String(photoBuffer) %></content>
<hatena:generator url="http://gihyo.jp/dev/serial/01/wl-sdk/" version="1.0">gihyo.jp sample tool</hatena:generator>
<dc:subject>Sample</dc:subject>
</entry>
' <entry>要素をバイト配列へ変換
Dim entryBuffer = System.Text.Encoding.UTF8.GetBytes(entry.ToString)
request.ContentLength = entryBuffer.Length
' POSTデータ書き込み
Using stream = request.GetRequestStream
stream.Write(entryBuffer, 0, entryBuffer.Length)
End Using
' レスポンス取得
Dim document As XDocument
Using response = DirectCast(request.GetResponse, HttpWebResponse), _
reader = New System.IO.StreamReader(response.GetResponseStream, System.Text.Encoding.UTF8)
document = XDocument.Load(reader)
End Using
End Sub
コードを確認するとわかるように、
上記のように操作は限定されていますが、
Dim userName = "ユーザー名"
Dim password = "パスワード"
Dim title = ""
Dim postUri = GetPostUri(userName, password, title)
PostPhoto(userName, password, postUri, "C:\Users\UserName\Pictures\Sample.jpg")
うまくできたでしょうか? うまくいかない場合はリクエスト時など例外が起きていないか確認し、
今回はここまでです。次回からはLive フォト ギャラリー用の投稿プラグインを作成していきます。