MFC から SVG の画像

## 画像の配置
SVG において画像の配置方法は大きく２種類あります。

- 画像 URL で表示する
- 画像データを SVG の中に埋め込む

URL の指定は文字列を貼り付ける簡単な処理となりますので本稿では画像データを SVG の中に埋め込む方法を取りたいと思います。

注意点として、SVG 画像の中に SVG 画像の埋め込みはできません。
SVG 画像を埋め込みたい場合は別途 SVG 形式で縮尺調整などしながら直接描く手法が求められます。
本投稿では SVG 画像の埋め込みは考慮しません。

```diff_cpp:SvgImage.h
class SvgImage
{
public:
+   void AddImage(CPoint pn, BYTE* pbSrc, DWORD dwSrcLength, int nWidth, int nHeight,
+        double dScaleX, double dScaleY, int nDegree, int nDepth = 0);
}
```

```cpp:SvgImage
void SvgImage::AddImage(CPoint pn, BYTE* pbSrc, DWORD dwSrcLength, int nWidth,
         int nHeight,　double dScaleX, double dScaleY, int nDegree, int nDepth)
{
	SvgTag* svgImageTag = new SvgTag();
	svgImageTag->m_strName = L"image";
	svgImageTag->m_nDepth = nDepth + 1;
	svgImageTag->m_bOne = TRUE;

	CString csStr;
	csStr.Format(_T("%.03lf"), pn.x - m_rectAll.left);
	svgImageTag->m_arrAttr.Add(L"x");
	svgImageTag->m_arrAttrValue.Add(csStr);
	csStr.Format(_T("%.03lf"), m_rectAll.bottom - pn.y);
	svgImageTag->m_arrAttr.Add(L"y");
	svgImageTag->m_arrAttrValue.Add(csStr);
	double dWidth = nWidth * dScaleX;
	double dHeight = nHeight * dScaleY;
	CString strWidth;
	strWidth.Format(L"%.03lf", dWidth);
	svgImageTag->m_arrAttr.Add(L"width");
	svgImageTag->m_arrAttrValue.Add(strWidth);
	CString strHeight;
	strHeight.Format(L"%.03lf", dHeight);
	svgImageTag->m_arrAttr.Add(L"height");
	svgImageTag->m_arrAttrValue.Add(strHeight);
	CString strRotate;
	strRotate.Format(L"rotate(%d)", -nDegree);
	svgImageTag->m_arrAttr.Add(L"transform");
	svgImageTag->m_arrAttrValue.Add(strRotate);

	// 画像データの埋め込み
	bool bResult = false;
	DWORD dwDestLength = 0;
	LPTSTR psDest = NULL;
	CString strBase64;
	if (CryptBinaryToString(pbSrc, dwSrcLength, CRYPT_STRING_BASE64,
         NULL, &dwDestLength) == TRUE)
	{
		psDest = new TCHAR[dwDestLength + 1];
		if (CryptBinaryToString(pbSrc, dwSrcLength, CRYPT_STRING_BASE64,
             psDest, &dwDestLength) == TRUE)
		{
			strBase64 = CString(psDest);
			bResult = true;
		}
		delete psDest;
	}
	CString strSrc;
	strSrc.Format(L"data:image/png;base64,%s", static_cast<LPCWSTR>(strBase64));
	svgImageTag->m_arrAttr.Add(L"xlink:href");
	svgImageTag->m_arrAttrValue.Add(strSrc);

	// image の回転は中心点（絶対座標）を指定する必要がある
	double dCenterX = 0.0;
	dCenterX = pn.x - m_rectAll.left + nWidth / 2 * dScaleX;
	double dCenterY = 0.0;
	dCenterY = m_rectAll.bottom - pn.y + nHeight / 2 * dScaleY;
	CString strCenter;
	strCenter.Format(L"%.03lf %.03lf", dCenterX, dCenterY);
	svgImageTag->m_arrAttr.Add(L"transform-origin");
	svgImageTag->m_arrAttrValue.Add(strCenter);

	m_arrayTag.Add(svgImageTag);
}
```

表示する座標と表示する際の縮尺、回転具合を設定します。

```cpp
	CString csStr;
	csStr.Format(_T("%.03lf"), pn.x - m_rectAll.left);
	svgImageTag->m_arrAttr.Add(L"x");
	svgImageTag->m_arrAttrValue.Add(csStr);
	csStr.Format(_T("%.03lf"), m_rectAll.bottom - pn.y);
	svgImageTag->m_arrAttr.Add(L"y");
	svgImageTag->m_arrAttrValue.Add(csStr);
	double dWidth = nWidth * dScaleX;
	double dHeight = nHeight * dScaleY;
	CString strWidth;
	strWidth.Format(L"%.03lf", dWidth);
	svgImageTag->m_arrAttr.Add(L"width");
	svgImageTag->m_arrAttrValue.Add(strWidth);
	CString strHeight;
	strHeight.Format(L"%.03lf", dHeight);
	svgImageTag->m_arrAttr.Add(L"height");
	svgImageTag->m_arrAttrValue.Add(strHeight);
	CString strRotate;
	strRotate.Format(L"rotate(%d)", -nDegree);
	svgImageTag->m_arrAttr.Add(L"transform");
	svgImageTag->m_arrAttrValue.Add(strRotate);
```
入力データは PNG 画像である前提のコードになります。

base64 形式で保存するため、バイナリデータをコピーし文字列に変換します。
出来上がった文字列は "xlink:href" 属性の値の先頭に "data:image/png;base64,"を付けてバイナリデータの base64 文字列を格納します。

一度目の CryptBinaryToString 関数でテキストへ変換できるかどうかを確認し、二度目の CryptBinaryToString でテキストへ変換しています。
```cpp
	// 画像データの埋め込み
	bool bResult = false;
	DWORD dwDestLength = 0;
	LPTSTR psDest = NULL;
	CString strBase64;
	if (CryptBinaryToString(pbSrc, dwSrcLength, CRYPT_STRING_BASE64,
         NULL, &dwDestLength) == TRUE)
	{
		psDest = new TCHAR[dwDestLength + 1];
		if (CryptBinaryToString(pbSrc, dwSrcLength, CRYPT_STRING_BASE64,
             psDest, &dwDestLength) == TRUE)
		{
			strBase64 = CString(psDest);
			bResult = true;
		}
		delete psDest;
	}
	CString strSrc;
	strSrc.Format(L"data:image/png;base64,%s", static_cast<LPCWSTR>(strBase64));
	svgImageTag->m_arrAttr.Add(L"xlink:href");
	svgImageTag->m_arrAttrValue.Add(strSrc);
```
回転する中心点を指定します。
```cpp
	// image の回転は中心点（絶対座標）を指定する必要がある
	double dCenterX = 0.0;
	dCenterX = pn.x - m_rectAll.left + nWidth / 2 * dScaleX;
	double dCenterY = 0.0;
	dCenterY = m_rectAll.bottom - pn.y + nHeight / 2 * dScaleY;
	CString strCenter;
	strCenter.Format(L"%.03lf %.03lf", dCenterX, dCenterY);
	svgImageTag->m_arrAttr.Add(L"transform-origin");
	svgImageTag->m_arrAttrValue.Add(strCenter);
```