window.onload = function() {
//DsPdfViewer.LicenseKey = "***key***";
let viewer, React;
// ビューワのオプションを準備
const options = {
workerSrc: "/diodocs/pdfviewer/demos/product-bundles/build/dspdfviewer.worker.js",
supportApi: getSupportApiSettings(),
restoreViewStateOnLoad: false
};
// ビューワに関連する任意のデータ
// このデータはドキュメント保存時にサーバーサイドに送信される
options.userData = { sampleName: 'SaveChangesSample', docName: new Date().getTime() + '.pdf' };
// ビューワのインスタンスを作成
viewer = new DsPdfViewer("#viewer", options);
// 注釈エディタを追加
viewer.addAnnotationEditorPanel();
// 独自の「変更を保存」ボタンを作成
React = viewer.getType('React');
viewer.toolbar.addItem({
key: 'custom-save',
icon: { type: 'svg', content: React.createElement('svg', { xmlns: 'http://www.w3.org/2000/svg', version: '1.1', width: '24', height: '24', viewBox: '0 0 24 24', fill: '#ff0000' }, React.createElement('path', { d: 'M20.913 9.058c0.057-0.26 0.087-0.531 0.087-0.808 0-2.071-1.679-3.75-3.75-3.75-0.333 0-0.657 0.044-0.964 0.125-0.581-1.813-2.28-3.125-4.286-3.125-2.047 0-3.775 1.367-4.32 3.238-0.533-0.155-1.097-0.238-1.68-0.238-3.314 0-6 2.686-6 6s2.686 6 6 6h3v4.5h6v-4.5h5.25c2.071 0 3.75-1.679 3.75-3.75 0-1.845-1.333-3.379-3.087-3.692zM13.5 15v4.5h-3v-4.5h-3.75l5.25-5.25 5.25 5.25h-3.75z' })) },
title: '変更を保存',
enabled: false,
action: function() {
// 変更をサーバーサイドにストリームとして保存
viewer.saveChanges().then(function(result) {
if(result) {
// 保存したストリームをサーバーサイドから読み込む
var docUrl = window.top.SUPPORTAPI_URL + "/GetPdfFromCloud?docName="
+ options.userData.docName + '&clientId=' + viewer.supportApi.clientId;
viewer.open(docUrl).then(function() {
alert('ドキュメントはストリームとしてサーバーに保存されます。ドキュメントは10分間保持されます。');
});
}
});
},
onUpdate: function() {
return {
enabled: viewer.hasDocument,
title: '変更を保存'
};
}
});
viewer.toolbarLayout.viewer.default.splice(0, 0, 'download');
viewer.toolbarLayout.viewer.mobile.splice(0, 0, 'download');
// ビューワのツールバーのレイアウトに'custom-save'項目を追加
viewer.toolbarLayout.viewer.default.splice(0, 0, 'custom-save');
viewer.toolbarLayout.viewer.mobile.splice(0, 0, 'custom-save');
// 注釈エディタのツールバーのレイアウトを変更
var annotationEditorButtons = ['custom-save', 'download', 'edit-select', 'edit-sign-tool', '$split', 'edit-text', 'edit-free-text', 'edit-ink', 'edit-square',
'edit-circle', 'edit-line', 'edit-polyline', 'edit-polygon', 'edit-stamp', 'edit-link',
'$split', 'edit-redact', 'edit-redact-apply', 'edit-erase', '$split', 'new-document', '$split', 'new-page', 'delete-page'];
viewer.toolbarLayout.annotationEditor = { default: annotationEditorButtons, mobile: annotationEditorButtons, fullscreen: annotationEditorButtons };
viewer.open("/diodocs/pdfviewer/demos/product-bundles/assets/pdf/viewer-save-changes.pdf");
}
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>保存ボタンのカスタマイズ</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./src/styles.css">
<script src="/diodocs/pdfviewer/demos/product-bundles/build/dspdfviewer.js"></script>
<script src="/diodocs/pdfviewer/demos/product-bundles/build/wasmSupportApi.js"></script>
<script src="/diodocs/pdfviewer/demos/resource/js/init.js"></script>
<script src="./src/app.js"></script>
</head>
<body>
<div id="viewer"></div>
</body>
</html>
#viewer { height: 100%; }
// Ignore Spelling: Pdf Api Gc
using System;
using System.Reflection;
using System.IO;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using GrapeCity.Documents.Pdf;
using Newtonsoft.Json.Linq;
using System.Threading.Tasks;
using GrapeCity.Documents.Pdf.ViewerSupportApi.Controllers;
using GrapeCity.Documents.Pdf.ViewerSupportApi.Utils;
using GrapeCity.Documents.Pdf.ViewerSupportApi.Models;
using GrapeCity.Documents.Pdf.ViewerSupportApi.Resources.Stamps;
using System.Text;
namespace GcPdfViewerSupportApiDemo.Controllers
{
[Route("api/pdf-viewer")]
[ApiController]
public class SampleSupportController : GcPdfViewerController
{
static SampleSupportController()
{
#if DEBUG
// VSのF5は、現在の作業ディレクトリを"bin"ディレクトリではなく"project"ディレクトリに設定しているため、
// ここで作業ディレクトリを"bin"に設定し、"Resources"サブディレクトリからファイルを取得できるようにします。
var exePath = new Uri(Assembly.GetEntryAssembly().Location).LocalPath;
var directory = Path.GetDirectoryName(exePath);
Directory.SetCurrentDirectory(directory);
#endif
Settings.AvailableUsers.AddRange(new string[] { "利用者A", "利用者B" });
}
/// <summary>
/// 例として、SupportAPIの基本メソッドの1つをオーバーライドします。
/// </summary>
/// <returns></returns>
public override string Ping(string docId)
{
return base.Ping(docId);
}
public override IStampImagesStorage StampImagesStorage
{
get
{
var token = GetQueryValue("token");
if (!string.IsNullOrEmpty(token) && token.Contains("custom-stamps-sample"))
{
string projectRootPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string imagesPath = Path.Combine(projectRootPath, "wwwroot/assets/example-stamps");
return new FileSystemStampImagesStorage(imagesPath);
}
return base.StampImagesStorage;
}
}
public override void OnDocumentModified(GcPdfDocumentLoader documentLoader)
{
base.OnDocumentModified(documentLoader);
CleanupSampleCloudStorage();
var userData = documentLoader.Info.documentOptions.userData as JObject;
if (userData != null)
{
var userDataObj = userData.ToObject<Dictionary<string, string>>();
if (userDataObj != null)
{
if (userDataObj.ContainsKey("sampleName") && userDataObj["sampleName"] == "SaveChangesSample")
{
string docName = userDataObj["docName"];
SaveDocumentToCloud(documentLoader.ClientId, documentLoader.Document, docName);
}
}
}
}
[Route("SubmitFormSample")]
[ApiExplorerSettings(IgnoreApi = true)]
public IActionResult SubmitFormSample()
{
if (!Request.HasFormContentType)
{
return Content("送信されたデータはありません。");
}
else
{
var form = Request.Form;
var e = form.Keys.GetEnumerator();
StringBuilder sb = new StringBuilder();
sb.AppendLine("送信されたデータ:");
while (e.MoveNext())
{
if (form.TryGetValue(e.Current, out var val))
{
sb.AppendLine($" {e.Current}: {val};");
}
}
return Content(sb.ToString());
}
}
#region ** ViewerSaveChanges サンプル:
/// <summary>
/// このメソッドは、クライアント側から呼び出されます。
/// </summary>
/// <param name="docName"></param>
/// <param name="clientId"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
[Route("GetPdfFromCloud")]
[ApiExplorerSettings(IgnoreApi = true)]
async public Task<IActionResult> GetPdfFromCloud(string docName, string clientId)
{
var fileBytes = await GetDocumentFromCloud(docName, clientId);
if (fileBytes == null)
throw new Exception($"サンプルドキュメント '{docName}' が見つかりません。");
return new FileContentResult(fileBytes, "application/pdf")
{
FileDownloadName = docName
};
}
/// <summary>
/// クラウドサービスに PDF ドキュメントを保存します。
/// </summary>
/// <param name="clientId"></param>
/// <param name="document"></param>
/// <param name="docName"></param>
[ApiExplorerSettings(IgnoreApi = true)]
public void SaveDocumentToCloud(string clientId, GcPdfDocument document, string docName)
{
// ************************************************************************************
// ここに、特定のクラウドサービスに PDF ドキュメントを保存するコードを記述します。
// ************************************************************************************
// 以下はコード例です。
SaveToMemory(clientId, document, docName);
//SaveToDisk(document, docName);
}
/// <summary>
/// クラウドサービスから PDF ドキュメントをダウンロードします。
/// </summary>
/// <param name="docName"></param>
/// <param name="clientId"></param>
/// <returns></returns>
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
async public static Task<byte[]> GetDocumentFromCloud(string docName, string clientId)
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
{
// ************************************************************************************
// ここに、特定のクラウドサービスから PDF ドキュメントを取得するコードを記述します。
// ************************************************************************************
// 以下はコード例です。
return LoadFromMemory(clientId, docName);
//return LoadFromDisk(docName);
}
#region ** ディスクストレージの例
private static byte[] LoadFromDisk(string docName)
{
string path = $"Documents/{docName}";
return System.IO.File.ReadAllBytes(path);
}
private void SaveToDisk(GcPdfDocument document, string docName)
{
if (!Directory.Exists("Documents"))
Directory.CreateDirectory("Documents");
string path = $"Documents/{docName}";
document.Save(path);
}
#endregion
#region ** インメモリストレージの例
public static Dictionary<string, KeyValuePair<DateTime, byte[]>> DocumentsInCloud { get; private set; } = new Dictionary<string, KeyValuePair<DateTime, byte[]>>();
private static byte[] LoadFromMemory(string clientId, string docName)
{
var key = $"{docName}_{clientId}";
byte[] bytes = null;
lock (DocumentsInCloud)
{
bytes = DocumentsInCloud.ContainsKey(key) ? DocumentsInCloud[key].Value : null;
}
CleanupSampleCloudStorage();
return bytes;
}
private void SaveToMemory(string clientId, GcPdfDocument document, string docName)
{
var key = $"{docName}_{clientId}";
MemoryStream ms = new MemoryStream();
document.Save(ms);
lock (DocumentsInCloud)
{
if (DocumentsInCloud.ContainsKey(key))
DocumentsInCloud.Remove(key);
DocumentsInCloud.Add(key, new KeyValuePair<DateTime, byte[]>(DateTime.Now, ms.ToArray()));
}
ms.Dispose();
}
static void CleanupSampleCloudStorage()
{
lock (DocumentsInCloud)
{
foreach (var k in DocumentsInCloud.Keys)
{
if ((DateTime.Now - DocumentsInCloud[k].Key) > new TimeSpan(0, 10, 0) /* 10 min */)
{
DocumentsInCloud.Remove(k);
}
}
}
}
#endregion
#endregion
}
}