MOSS2010βのメディアライブラリで MP4 を Silverlight で再生する方法
MOSS2010のベータ版が公開されていたので早速試してみた。
今回から(?)ドキュメントコレクションの一つとしてメディアライブラリが作成可能で、縮小表示ビューでは対応したファイルは Silverlight で直接ブラウザ上から再生できるようになっている。現在 MOSS として対応しているファイルは wmv, wma, mp3 のみのようでそれ以外は再生ではなくダウンロードする処理になってしまった。Silverlight はMP4の再生も対応しているはずなので何とかならないかなーと探っていたところひとまずの解決策を見つけた。
下記ファイルの59行目に任意の拡張子を付け加えればとりあえずはブラウザ上の Silverlight で再生できる。アイコンの表示とかはおかしいままだけどコレで MP4 はブラウザ上で再生可能に。
C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions \14\TEMPLATE\LAYOUTS\1041\CmsSiteManager.js L59 : var g_silverlightExtensions=new Array("wmv","wma","mp3"); → var g_silverlightExtensions=new Array("wmv","wma","mp3","mp4");
RTMする際には対応しておいてほしいところだ。
synergy-plus における106日本語KBでのALT+半角/全角(修正)
synergy-plus へファイルのクリップボード共有機能実装
前回の続きで、synergy-plus にタイトルの通りファイルに対するクリップボード共有機能を実装する。実現方法はファイルのデータ本体をやりとりするという方法もあるが、そうすると巨大なファイルの際に問題が発生するのが目に見えているので、Windows間限定になってしまうが、Windowsの管理共有機能を利用する。
CF_HDROP
エクスプローラからファイルがクリップボードにコピーされるとフォーマットIDとしてはCF_HDROPになり、ファイルの取得方法はファイルのDrag&Drop時と同じようにDragQueryFile関数で取得できる。また、Win2000以降はファイル名にUnicode(UTF16)が使われるのでこれらを考慮して実装する。
変更箇所
元々がかなり整理して作られていたので変更しなければならない箇所はすぐにわかる。クリップボードに送られるフォーマットごとにWindows環境用は、CMSWindowsClipboardXXXConverterという名前がついている。そのため、今回はCMSWindowsClipboardFilePathConverter.cpp/hを作成する。また、作成したConverterを利用するためにいくつかの変更を行った。作り方は他のConverterのソースが参考になる。
IClipboard.h
synergyは複数のOS間で利用できるように作られているので、クリップボードのフォーマットを独自に定義してあり、IClipboard.hにある。ここに、ファイルのパスを表すkFilePathを追加し、これを用いて機能を実現することに。もし、ファイルパスではなくファイルのデータ丸ごとやりとりする場合等はここに別の値を追加してやればできるだろう。どうやらUTF8で文字のやりとりが多いようなのでそれに従ってファイルパスもUTF16ではなくUTF8に変換して送ることにした。
diff --git a/lib/synergy/IClipboard.h b/lib/synergy/IClipboard.h --- a/lib/synergy/IClipboard.h +++ b/lib/synergy/IClipboard.h @@ -56,6 +56,7 @@ kText, //!< Text format, UTF-8, newline is LF kBitmap, //!< Bitmap format, BMP 24/32bpp, BI_RGB kHTML, //!< HTML format, HTML fragment, UTF-8, newline is LF + kFilePath, //!< File Path format, UTF-8, separetor is \t kNumFormats //!< The number of clipboard formats };
CMSWindowsClipborad.cpp
MSWindowsとファイル名にあるものはすべてWindows用の実装になっている。ここのコンストラクタで各種コンバータが登録されているので作成したCMSWindowsClipboardFilePathConverterを登録するように追加する。
diff --git a/lib/platform/CMSWindowsClipboard.cpp b/lib/platform/CMSWindowsClipboard.cpp --- a/lib/platform/CMSWindowsClipboard.cpp +++ b/lib/platform/CMSWindowsClipboard.cpp @@ -17,6 +17,7 @@ #include "CMSWindowsClipboardUTF16Converter.h" #include "CMSWindowsClipboardBitmapConverter.h" #include "CMSWindowsClipboardHTMLConverter.h" +#include "CMSWindowsClipboardFilePathConverter.h" #include "CLog.h" #include "CArchMiscWindows.h" @@ -39,6 +40,7 @@ } m_converters.push_back(new CMSWindowsClipboardBitmapConverter); m_converters.push_back(new CMSWindowsClipboardHTMLConverter); + m_converters.push_back(new CMSWindowsClipboardFilePathConverter); } CMSWindowsClipboard::~CMSWindowsClipboard()
CMSWindowsClipboardFilePathConverter.cpp
クリップボードにコピーされたファイルパスは管理共有を使ったUNCパスに変換(複数アイテムの場合はタブ(\t)を区切り文字)し、UTF8にした後で相手先に送信する。受信側は逆順に展開し、クリップボードにデータとしてセットするように実装している。
#include "CMSWindowsClipboardFilePathConverter.h" #include "CLog.h" #include "shellapi.h" #include "shlobj.h" #include "CUnicode.h" #define WCToCString(x) (CString((const char*)(x), wcslen(x)*sizeof(wchar_t))) // // CMSWindowsClipboardFilePathConverter // CMSWindowsClipboardFilePathConverter::CMSWindowsClipboardFilePathConverter() { OSVERSIONINFO os_info; os_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); ::GetVersionEx(&os_info); if ( os_info.dwPlatformId == VER_PLATFORM_WIN32_NT ) { // Widechar useWideChar = TRUE; // ARCH->getHostName() DWORD size = sizeof(computerNameWC); if ( ::GetComputerNameW(computerNameWC, &size) == FALSE ) { // Failed computerNameWC[0] = 0; } } else { // Multibyte useWideChar = FALSE; DWORD size = sizeof(computerNameMB); if ( ::GetComputerNameA(computerNameMB, &size) == FALSE ) { // Failed computerNameMB[0] = 0; } } separator = CUnicode::textToUTF8(CString("\t")); } CMSWindowsClipboardFilePathConverter::~CMSWindowsClipboardFilePathConverter() { } IClipboard::EFormat CMSWindowsClipboardFilePathConverter::getFormat() const { return IClipboard::kFilePath; } UINT CMSWindowsClipboardFilePathConverter::getWin32Format() const { return CF_HDROP; } HANDLE CMSWindowsClipboardFilePathConverter::fromIClipboard(const CString& data) const { // data is UTF8 std::vector<CString> fileList; { // separate data with separator('\t') CString s = data; for (int p = 0; (p = s.find(separator)) != s.npos; ) { #ifdef _DEBUG LOG((CLOG_DEBUG "> %s", CUnicode::UTF8ToText(s.substr(0, p)).c_str())); #endif fileList.push_back(s.substr(0, p)); s = s.substr(p + separator.size()); } if ( s.length() > 1 ) { #ifdef _DEBUG LOG((CLOG_DEBUG ">* %s", CUnicode::UTF8ToText(s).c_str())); #endif fileList.push_back(s); } } LOG((CLOG_DEBUG "file: recv count > %d / widechar > %d", fileList.size(), useWideChar)); #ifdef _DEBUG LOG((CLOG_DEBUG " %s", CUnicode::UTF8ToText(data).c_str())); for ( int i = 0; i < fileList.size(); i++ ) { LOG((CLOG_DEBUG "> %s", CUnicode::UTF8ToText(fileList[i]).c_str())); } #endif LPDROPFILES lpDropFile; HDROP hDrop; UINT bufferSize = 0; // calc buffer size & convert encoding if ( useWideChar == TRUE ) { // widechar for ( UINT i = 0;i < fileList.size(); i++ ) { // Widechar is UTF16 in Windows fileList[i] = CUnicode::UTF8ToUTF16(fileList[i]); bufferSize += fileList[i].size() + sizeof(wchar_t); // length + NULL } } else { // multibyte for ( UINT i = 0; i < fileList.size(); i++ ) { fileList[i] = CUnicode::UTF8ToText(fileList[i]); bufferSize += fileList[i].size() + 1; } } hDrop = (HDROP)::GlobalAlloc(GHND,sizeof(DROPFILES) + bufferSize + 2); if (hDrop == NULL) { return NULL; } lpDropFile = (LPDROPFILES) ::GlobalLock(hDrop); lpDropFile->pFiles = sizeof(DROPFILES); lpDropFile->pt.x = 0; lpDropFile->pt.y = 0; lpDropFile->fNC = FALSE; lpDropFile->fWide = useWideChar; if ( useWideChar == TRUE ) { // widechar wchar_t *buf; buf = (wchar_t*)(&lpDropFile[1]); for ( UINT i = 0; i < fileList.size(); i++ ) { memcpy(buf, fileList[i].c_str(), fileList[i].size()); buf += (fileList[i].size()/sizeof(wchar_t)); *buf++ = 0; } *buf = 0; } else { // multibyte char *buf; buf = (char *)(&lpDropFile[1]); for ( UINT i = 0; i < fileList.size(); i++ ) { memcpy(buf, fileList[i].c_str(), fileList[i].size()); buf += fileList[i].size(); *buf++ = 0; } *buf = 0; } ::GlobalUnlock(hDrop); return hDrop; } CString CMSWindowsClipboardFilePathConverter::toIClipboard(HANDLE data) const { CString fileList; UINT fileCount = 0; // FileCount if ( useWideChar == TRUE ) fileCount = ::DragQueryFileW((HDROP)data, (UINT)-1, NULL, 0); else fileCount = ::DragQueryFileA((HDROP)data, (UINT)-1, NULL, 0); LOG((CLOG_DEBUG "file: send count > %d / widechar > %d", fileCount, useWideChar)); if ( fileCount == 0 ) { // nothing return CString(); } // Get file path from clipboard if ( useWideChar == TRUE ) { wchar_t szPath[MAX_PATH]; for ( UINT i = 0; i < fileCount; i++ ) { ::DragQueryFileW((HDROP)data, i, szPath, sizeof(szPath)); CString cnvPath = convertPath(szPath); fileList.append(cnvPath); fileList.append(separator); // separate with '\t' LOG((CLOG_DEBUG " %s", CUnicode::UTF8ToText(cnvPath).c_str())); } } else { char szPath[MAX_PATH]; for ( UINT i = 0; i < fileCount; i++ ) { ::DragQueryFileA((HDROP)data, i, szPath, sizeof(szPath)); CString cnvPath = convertPath(szPath); fileList.append(cnvPath); fileList.append(separator); // separate with '\t' LOG((CLOG_DEBUG " %s", szPath)); LOG((CLOG_DEBUG " -> %s", cnvPath.c_str())); } } return fileList; } // Convert to UNC path using administrative shared folder CString CMSWindowsClipboardFilePathConverter::convertPath(char* szPath) const { CString path = CString(szPath); CString unc; if ( path.substr(0, 2) == "\\\\" ) { // Remote Path unc = CString(path); } else { // Local Path unc = CString("\\\\"); unc.append(computerNameMB); unc.append("\\"); unc.append(path.replace(1, 1, "$")); // Convert 'C:\...' to 'C$\...' } return CUnicode::textToUTF8(unc); } CString CMSWindowsClipboardFilePathConverter::convertPath(wchar_t* szPath) const { size_t lenPath = wcslen(szPath); if ( lenPath < 3 ) return CString(); CString unc; if ( szPath[0] == L'\\' && szPath[1] == L'\\' ) { // Remote Path unc = WCToCString(szPath); } else { // Local Path unc = WCToCString(L"\\\\"); unc.append(WCToCString((wchar_t*)computerNameWC)); unc.append(WCToCString(L"\\")); char* drive = new char[sizeof(wchar_t)]; memcpy(drive, szPath, sizeof(wchar_t)); unc.append(drive, 1 * sizeof(wchar_t)); // Convert 'C:\...' to 'C$\...' delete drive; unc.append(WCToCString(L"$")); unc.append(WCToCString(szPath+2)); } return CUnicode::UTF16ToUTF8(unc); // Widechar is UTF16 in Windows }
CMSWindowsClipboardFilePathConverter.h
#ifndef CMSWindowsClipboardFilePathConverter_H #define CMSWindowsClipboardFilePathConverter_H #include "CMSWindowsClipboard.h" //! Convert to/from some text encoding class CMSWindowsClipboardFilePathConverter : public IMSWindowsClipboardConverter { private: CString separator; BOOL useWideChar; char computerNameMB[MAX_COMPUTERNAME_LENGTH+1]; wchar_t computerNameWC[MAX_COMPUTERNAME_LENGTH+1]; CString convertPath(char* szPath) const; CString convertPath(wchar_t* szPath) const; public: CMSWindowsClipboardFilePathConverter(); virtual ~CMSWindowsClipboardFilePathConverter(); // IMSWindowsClipboardConverter overrides virtual IClipboard::EFormat getFormat() const; virtual UINT getWin32Format() const; virtual HANDLE fromIClipboard(const CString&) const; virtual CString toIClipboard(HANDLE) const; }; #endif
synergy-plus の日本語対応+α
気がついたら半年ほど放置していた。まぁ気が向いたときの投稿ということで。
前振り
- Windows7を機にx64環境へ移行を計画
- 常用していて手放せないsynergyのx64版がない
- synergyは開発が長いことと待っていたのでforkしたsynergy-plusがあり、こちらはx86/x64ともにある
というかんじで、synergyのソースにx64パッチを当てている方もいらしたが、せっかくなので設定の互換等もあるsynergy-plusへ移行をすることにした。
synergy-plusへの日本語KB対応パッチ等の適用
synergyでもあったように、日本語キーボードの場合にいろいろと問題があるのはplusでも同じだった。なのでsynergy向けに公開されている情報を元にplusのソースコードにパッチを当ててビルドし直し。調査や情報公開をされていた方々に感謝。
Synergy - 斜に
http://naname.jp/index.php?Synergy
1.3.2 (正確にはr897)をビルド - 忘れないようにメモ
http://d.hatena.ne.jp/desutai/20080304/1204598380
memo/Synergy - wiki@nothing
http://wiki.nothing.sh/page/memo/Synergy
ベースが同じだけあり、全く差異がなかったためすんなりパッチの適用が完了。すでに先達の方が公開されている内容と同じだが、自分用メモのためにも下記にまとめておく。また、併せてALT押しっぱなし問題など上述ページにあるパッチも当てさせていただいた。
diff --git a/lib/platform/CMSWindowsKeyState.cpp b/lib/platform/CMSWindowsKeyState.cpp --- a/lib/platform/CMSWindowsKeyState.cpp +++ b/lib/platform/CMSWindowsKeyState.cpp @@ -64,7 +64,7 @@ /* 0x01a */ { kKeyNone }, // undefined /* 0x01b */ { kKeyEscape }, // VK_ESCAPE /* 0x01c */ { kKeyHenkan }, // VK_CONVERT - /* 0x01d */ { kKeyNone }, // VK_NONCONVERT + /* 0x01d */ { kKeyMuhenkan }, // VK_NONCONVERT /* 0x01e */ { kKeyNone }, // VK_ACCEPT /* 0x01f */ { kKeyNone }, // VK_MODECHANGE /* 0x020 */ { kKeyNone }, // VK_SPACE @@ -1154,6 +1154,12 @@ else { // found in table switch (m_buttonToVK[i]) { + case VK_KANJI: + case VK_OEM_AUTO: + case VK_OEM_ENLW: + item.m_id = kKeyZenkaku; + break; + case VK_TAB: // add kKeyLeftTab, too item.m_id = kKeyLeftTab;
diff --git a/lib/synergy/KeyTypes.h b/lib/synergy/KeyTypes.h --- a/lib/synergy/KeyTypes.h +++ b/lib/synergy/KeyTypes.h @@ -103,7 +103,8 @@ static const KeyID kKeyScrollLock = 0xEF14; static const KeyID kKeySysReq = 0xEF15; static const KeyID kKeyEscape = 0xEF1B; +static const KeyID kKeyMuhenkan = 0xEF22; /* Cancel Conversion */ static const KeyID kKeyHenkan = 0xEF23; /* Start/Stop Conversion */ static const KeyID kKeyHangulKana = 0xEF26; /* Hangul, Kana */ static const KeyID kKeyHiraganaKatakana = 0xEF27; /* Hiragana/Katakana toggle */ static const KeyID kKeyZenkaku = 0xEF2A; /* Zenkaku/Hankaku */ @@ -106,8 +107,8 @@ static const KeyID kKeyHenkan = 0xEF23; /* Start/Stop Conversion */ static const KeyID kKeyHangulKana = 0xEF26; /* Hangul, Kana */ static const KeyID kKeyHiraganaKatakana = 0xEF27; /* Hiragana/Katakana toggle */ static const KeyID kKeyZenkaku = 0xEF2A; /* Zenkaku/Hankaku */ -static const KeyID kKeyHanjaKanzi = 0xEF2A; /* Hanja, Kanzi */ +static const KeyID kKeyHanjaKanzi = 0x0060; /* Hanja, Kanzi */ static const KeyID kKeyDelete = 0xEFFF; /* Delete, rubout */ // cursor control
diff --git a/lib/platform/CSynergyHook.cpp b/lib/platform/CSynergyHook.cpp --- a/lib/platform/CSynergyHook.cpp +++ b/lib/platform/CSynergyHook.cpp @@ -202,6 +202,9 @@ bool doKeyboardHookHandler(WPARAM wParam, LPARAM lParam) { + if( g_mode != kHOOK_RELAY_EVENTS ) + return false; + // check for special events indicating if we should start or stop // passing events through and not report them to the server. this // is used to allow the server to synthesize events locally but @@ -682,21 +685,22 @@ keyboardLLHook(int code, WPARAM wParam, LPARAM lParam) { if (code >= 0) { - // decode the message - KBDLLHOOKSTRUCT* info = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam); - WPARAM wParam = info->vkCode; - LPARAM lParam = 1; // repeat code - lParam |= (info->scanCode << 16); // scan code - if (info->flags & LLKHF_EXTENDED) { - lParam |= (1lu << 24); // extended key - } - if (info->flags & LLKHF_ALTDOWN) { - lParam |= (1lu << 29); // context code - } - if (info->flags & LLKHF_UP) { - lParam |= (1lu << 31); // transition - } - // FIXME -- bit 30 should be set if key was already down but - // we don't know that info. as a result we'll never generate - // key repeat events. + if( g_mode == kHOOK_RELAY_EVENTS ) { + // decode the message + KBDLLHOOKSTRUCT* info = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam); + WPARAM wParam = info->vkCode; + LPARAM lParam = 1; // repeat code + lParam |= (info->scanCode << 16); // scan code + if (info->flags & LLKHF_EXTENDED) { + lParam |= (1lu << 24); // extended key + } + if (info->flags & LLKHF_ALTDOWN) { + lParam |= (1lu << 29); // context code + } + if (info->flags & LLKHF_UP) { + lParam |= (1lu << 31); // transition + } + // FIXME -- bit 30 should be set if key was already down but + // we don't know that info. as a result we'll never generate + // key repeat events. @@ -702,7 +706,8 @@ - // handle the message - if (keyboardHookHandler(wParam, lParam)) { - return 1; + // handle the message + if (keyboardHookHandler(wParam, lParam)) { + return 1; + } } }
ログウィンドウの日本語化
現在ログウィンドウには2バイト文字が表示されると表示が崩れるので、これに対してのパッチを当てる。原因はロケールの設定がされていないためのようなので、アプリケーション起動時にシステムロケールを取得して設定するように変更。
diff --git a/cmd/synergyc/synergyc.cpp b/cmd/synergyc/synergyc.cpp --- a/cmd/synergyc/synergyc.cpp +++ b/cmd/synergyc/synergyc.cpp @@ -852,6 +852,9 @@ int WINAPI WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int) { + // Change locale to system locale for 'wctomb' etc... + setlocale(LC_CTYPE, setlocale(LC_CTYPE, "")); + try { CArchMiscWindows::setIcons((HICON)LoadImage(instance, MAKEINTRESOURCE(IDI_SYNERGY),
diff --git a/cmd/synergys/synergys.cpp b/cmd/synergys/synergys.cpp --- a/cmd/synergys/synergys.cpp +++ b/cmd/synergys/synergys.cpp @@ -1266,6 +1266,9 @@ int WINAPI WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int) { + // Change locale to system locale for 'wctomb' etc... + setlocale(LC_CTYPE, setlocale(LC_CTYPE, "")); + try { CArchMiscWindows::setIcons((HICON)LoadImage(instance, MAKEINTRESOURCE(IDI_SYNERGY),
次なる課題は
synergy はクリップボードの内容についてテキストとビットマップは共有できるが、エクスプローラのファイルについては現在できない。そこで、ファイルについてもクリップボードを経由して共有できるようになると非常に便利なのでこの機能を synergy-plus へ実装したいと思う。せっかくオープンソースで公開されている訳だし、いじらにゃ損(?)ということで。
蛇足
CMAKEってのを初めて使ってみたけど便利!自分のビルド環境を使えるというのがいい。synergyの場合、無理矢理VS2008でビルドするといろいろ警告が出たりと気になっていたけど、plusでCMAKEからVS2008のソリューションを生成すればそんなことはなかった。
Word から InlineShape の画像を取り出す
Word 文書に埋め込まれた画像を取り出すにはどうしたら…といろいろ調べて回ってみると、クリップボードを経由して画像を取りだしているサンプルは見つけた。が、Word は拡縮前(劣化前)の画像データを持っている*1のでそれを何とかして取りだしてみた。
スマートなやり方ではない気がするけどポイントは下記の通り
- Range.get_XML() から該当部分の DOCX(XML) を取得して、Base64Encode された元の画像データを取得する
- 取得した画像データから実際に Word 上に表示されているサムネイル画像を作成する
- Word 上の画像の単位は Point なので Pixel へ変換するため、PointsToPixels を用いて変換する
下記サンプルを実行すれば、Shape.png と Thumb.png が生成される。
object missing = Type.Missing;
// 取り出したい InlineShape
var shape = ActiveDocument.InlineShapes[1];
// 画像じゃなければ処理しない(チャートの場合などがある)
if ( shape.Type != Word.WdInlineShapeType.wdInlineShapePicture )
return;
System.Drawing.Image image = null; // 元画像
System.Drawing.Image thumb = null; // サムネイル
// InlineShape の高さと幅を取得する
// Width, Height はそのままだと単位が pt なので pixel へ変換する
int pixWidth = (int)shape.Application.PointsToPixels(shape.Width, ref missing);
int pixHeight = (int)shape.Application.PointsToPixels(shape.Height, ref missing);
// 素の画像データを取得するため DOCX に埋め込まれる XML を取得する
// この中に Base64 エンコードされた素の画像データが入っている
XmlDocument xmlShape = new XmlDocument();
xmlShape.LoadXml(shape.Range.get_XML(false));
XmlNamespaceManager nm = new XmlNamespaceManager(xmlShape.NameTable);
nm.AddNamespace("w", "http://schemas.microsoft.com/office/word/2003/wordml");
// 画像データがあるノードを取得する
var binDataNode = xmlShape.DocumentElement.SelectSingleNode("//w:pict/w:binData", nm);
if ( binDataNode == null )
{ // XML 内に画像データが見つからなかった
// 代替として表示されているものをクリップボードを経由して画像作成
shape.Select();
shape.Application.Selection.Copy();
image = Clipboard.GetImage();
}
else
{ // 素の画像データが取得できた場合
// メモリに展開した後に Image クラスを作成
MemoryStream ms = new MemoryStream(System.Convert.FromBase64String(binDataNode.InnerText));
image = System.Drawing.Image.FromStream(ms);
// クリッピングされている場合の処理
// PictureFormat に CropXXXX として値が入っているので取得する
// (Width とかと同じく pt から pixel へ変換する)
int cropTop = (int)shape.Application.PointsToPixels(shape.PictureFormat.CropTop, ref missing);
int cropBottom = (int)shape.Application.PointsToPixels(shape.PictureFormat.CropBottom, ref missing);
int cropLeft = (int)shape.Application.PointsToPixels(shape.PictureFormat.CropLeft, ref missing);
int cropRight = (int)shape.Application.PointsToPixels(shape.PictureFormat.CropRight, ref missing);
// クリッピング用 Rectangle 作成
System.Drawing.Rectangle clippingRect = new System.Drawing.Rectangle
{
X = cropLeft,
Y = cropTop,
Width = image.Width - ( cropRight + cropLeft ),
Height = image.Height - ( cropBottom + cropTop ),
};
// サムネイル用の Bitmap を作成(Height と Width は現在表示しているサイズで)
thumb = new System.Drawing.Bitmap(pixWidth, pixHeight, image.PixelFormat);
// サムネイルに描画する
var g = System.Drawing.Graphics.FromImage(thumb);
g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
g.DrawImage(image,
new System.Drawing.Rectangle(0, 0, thumb.Width, thumb.Height),
clippingRect,
System.Drawing.GraphicsUnit.Pixel);
}
image.Save("Shape.png", ImageFormat.Png);
if ( thumb != null )
{
thumb.Save("Thumb.png", ImageFormat.Png);
}
*1:大きい画像を貼り付けると自動的に縮小されるが、画像を右クリック>サイズからリセットをすれば実寸大に表示される
Word 文書からきれいな HTML とはてな記法で出力する - 経過(1)
現在までに完成している機能
- 見出し
- リスト
- 文中のスタイル変更
これからやる機能
- Hyperlink処理
- テーブル処理
- 画像処理
- 文書整形
ポイント
処理単位
Word.Document や Word.Range のプロパティにある下記を使えばそれぞれの単位で処理が行える。
プロパティ名 | 説明 |
---|---|
Sections | 節ごと |
Paragraphs | 段落(ENTER改行)ごと |
Sentences | 一文ごと |
Words | 単語ごと(日本語文書の場合はあんまり意味ない…) |
Characters | 一文字ごと |
カウントするだけなら Count プロパティをみればいいだけなのでコードに全く意味はないけどサンプル↓
Word.Document document = Globals.ThisAddIn.Application.ActiveDocument;
int countParagraph = 0;
int countSentence = 0;
int countWord = 0;
int countCharacter = 0;
foreach ( Word.Section section in document.Sections )
{
foreach ( Word.Paragraph paragraph in section.Range.Paragraphs )
{
foreach ( Word.Range sentence in paragraph.Range.Sentences )
{
foreach ( Word.Range word in sentence.Words )
{
foreach ( Word.Range charcter in word.Characters )
{
countCharacter++;
}
countWord++;
}
countSentence++;
}
countParagraph++;
}
string msg = string.Format("下記セクションには段落が{0}, 文が{1}, 単語が{2}, 文字が{3} あります。\n---------------------\n{4}",
countParagraph, countSentence, countWord, countCharacter, section.Range.Text);
MessageBox.Show(msg);
}
スタイルの文中変更を確認するためには Characters で一文字ずつみていかないとだめぽい…。DOCX の XML から XSLT で HTML へ変換した方がよいのだろうか…。