Проблема с добавлением Draw Ink и повторным открытием в средстве просмотра PDF после изменений в библиотеке Syncfusion, Javascript

Форум по Javascript
Ответить
Anonymous
 Проблема с добавлением Draw Ink и повторным открытием в средстве просмотра PDF после изменений в библиотеке Syncfusion,

Сообщение Anonymous »

У меня возникла проблема при использовании Syncfusion PDF Viewer с PDF-файлами после внесения изменений с помощью инструмента Draw Ink или любых других инструментов:
  • Я открыл PDF-файл с помощью PDF Viewer.
  • Я добавил текст с помощью инструмента Draw Ink .
  • Затем я загрузил измененный файл, и все появилось правильно, включая добавленный мной текст.
  • Однако, открыв файл на следующий день с помощью Просмотр PDF, я заметил, что подпись больше не отображается в Просмотр PDF, хотя она существует в файле, если его открыть с помощью другой программы чтения PDF.
Это кажется, существует проблема с тем, как подписи или дополнения к инструменту рисования отображаются или сохраняются после повторного открытия файла в средстве просмотра PDF.

Код: Выделить всё

Could you please advise if there is a solution for this issue or a way to ensure that signatures are permanently visible in PDF Viewer?

[HttpPost("Load")]
[IgnoreAntiforgeryToken]
public async Task Load()
{
Console.WriteLine("Load called");

string body;
using (var r = new StreamReader(Request.Body, Encoding.UTF8, detectEncodingFromByteOrderMarks: false))
body = await r.ReadToEndAsync();

if (string.IsNullOrWhiteSpace(body))
return BadRequest("Empty body");

var json = JsonConvert.DeserializeObject(body)
?? new Dictionary(StringComparer.OrdinalIgnoreCase);

if (!json.TryGetValue("document", out var doc) || string.IsNullOrWhiteSpace(doc))
return BadRequest("Missing 'document'");

// build data object from incoming json (preserve incoming hashId if present)
var data = new Dictionary(json, StringComparer.OrdinalIgnoreCase);

// If client passed hashId and we have cached annotation data, attach it
if (data.TryGetValue("hashId", out var incomingHash) && !string.IsNullOrWhiteSpace(incomingHash))
{
if (_cache.TryGetValue($"pdf:ann:{incomingHash}", out string annBase64) && !string.IsNullOrWhiteSpace(annBase64))
{
data["importedData"] = annBase64;
data["annotationDataFormat"] = "Json";
Console.WriteLine($"Load: attached importedData for hashId={incomingHash} (len={annBase64.Length})");
}
else
{
Console.WriteLine($"Load: no cached annotations for hashId={incomingHash}");
}
}

byte[] bytes;
if (IsHttpUrl(doc))
{
var bust = doc.Contains("?") ? "&" : "?";
var noCacheUrl = doc + bust + "v=" + DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();

using var http = new HttpClient(new HttpClientHandler { AutomaticDecompression = DecompressionMethods.All });
http.DefaultRequestHeaders.CacheControl = new System.Net.Http.Headers.CacheControlHeaderValue
{
NoCache = true,
NoStore = true,
MaxAge = TimeSpan.Zero
};

bytes = await http.GetByteArrayAsync(noCacheUrl);
if (bytes == null || bytes.Length == 0)
return BadRequest("Remote document returned empty content.");
}
else if (IsDataUrl(doc))
{
var comma = doc.IndexOf(',');
if (comma <  0) return BadRequest("Invalid data URL.");
var b64 = doc[(comma + 1)..];
bytes = Convert.FromBase64String((b64));
}
else if (LooksLikeBase64(doc))
{
bytes = Convert.FromBase64String((doc));
}
else
{
var localPath = Path.IsPathRooted(doc)
? doc
: Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, "wwwroot", "Data", doc));
if (!System.IO.File.Exists(localPath))
return NotFound($"File not found: {localPath}");
bytes = await System.IO.File.ReadAllBytesAsync(localPath);
if (!data.ContainsKey("fileName"))
data["fileName"] = Path.GetFileName(localPath);
}

var pdfviewer = new PdfRenderer(_cache);
object jsonResult;

var stream = new MemoryStream(bytes);
jsonResult = pdfviewer.Load(stream, data);

Console.WriteLine("Load jsonResult: " + JsonConvert.SerializeObject(jsonResult));

return Content(JsonConvert.SerializeObject(jsonResult), "application/json; charset=utf-8");
}

Код: Выделить всё


let viewer = null;
let pdfUrlExample = '';

var currentPdfName = '';
var currentHashId = null;
var currentPdfLink = '';

function initializePdfViewer() {
try {
console.log('initializePdfViewer: start');

if (typeof ej === 'undefined' || !ej.pdfviewer || !ej.base) {
throw new Error('Syncfusion EJ2 scripts not loaded (ej is undefined). Ensure scripts are included before this file.');
}
if (typeof syncfusion_key === 'undefined') {
console.warn('initializePdfViewer: syncfusion_key is undefined — registerLicense may fail');
} else {
try { ej.base.registerLicense(syncfusion_key); } catch (e) { console.warn('registerLicense failed', e); }
}

const el = document.querySelector('#pdfViewer');
if (!el) {
throw new Error('Missing DOM element with id="pdfViewer".  Create  in your page.');
}

ej.pdfviewer.PdfViewer.Inject(
ej.pdfviewer.Toolbar,
ej.pdfviewer.Magnification,
ej.pdfviewer.BookmarkView,
ej.pdfviewer.ThumbnailView,
ej.pdfviewer.TextSelection,
ej.pdfviewer.TextSearch,
ej.pdfviewer.Print,
ej.pdfviewer.Navigation,
ej.pdfviewer.LinkAnnotation,
ej.pdfviewer.Annotation,
ej.pdfviewer.FormFields,
ej.pdfviewer.FormDesigner,
ej.pdfviewer.Download
);

const saveItem = {
id: 'saveToServer',
text: 'Save',
tooltipText: 'Save to server',
prefixIcon: 'e-icons e-save',
overflow: 'Show'
};

viewer = new ej.pdfviewer.PdfViewer({
serviceUrl: '/PdfViewer',
resourceUrl: 'https://cdn.syncfusion.com/ej2/23.2.6/dist/ej2-pdfviewer-lib',
documentPath: pdfUrlExample,
ajaxRequestSuccess: function (args) {
try {
if (args && args.action === 'Load') {
console.log('ajaxRequestSuccess.Load args.data=', args.data);
currentHashId = args.data?.hashId || args.data?.documentId || null;
if (args.data?.documentName) currentPdfName = args.data.documentName;
}
} catch (err) {
console.error('ajaxRequestSuccess handler error', err);
}
},
documentLoad: function (args) {
if (args.documentName) currentPdfName = args.documentName;
},
serverActionSettings: {
load: 'Load',
renderPages: 'RenderPdfPages',
renderTexts: 'RenderPdfTexts',
renderThumbnail: 'RenderThumbnailImages',
download: 'Download',
print: 'PrintImages',
exportAnnotations: 'ExportAnnotations',
importAnnotations: 'ImportAnnotations',
annotations: 'RenderAnnotationComments',
unload: 'Unload'
},
enableToolbar: true,
toolbarSettings: {
showTooltip: true,
toolbarItems: [
saveItem,
'OpenOption',
'PageNavigationTool',
'MagnificationTool',
'PanTool',
'SelectionTool',
'SearchOption',
'PrintOption',
'DownloadOption',
'UndoRedoTool',
'AnnotationEditTool',
'FormDesignerEditTool',
'CommentTool'
]
}
});

viewer.toolbarClick = function (args) {
if (args.item.id !== 'saveToServer') return;

const recordId = Number($('#DocumentIdForPdfPreView').val()) || 0;
const docType = $('#DocumentTypeForPdfPreView').val();
const actionId = Number($('#DocumentUserActionIdForPdfPreView').val()) || 0;

const fileName = (currentPdfName && currentPdfName !== 'document.pdf')
? currentPdfName
: getFileNameFromUrl(viewer.documentPath);

if (!currentHashId) {
displayErrorAlert('لا يوجد hashId للملف الحالي.  الرجاء فتح الملف من المصدر الذي يُعيد hashId.');
return;
}

saveAnnotationsAndUpload({ recordId, docType, actionId, fileName, currentHashId })
.then(res => {
if ((res?.data && typeof res.data === 'string' && res.data.includes('OK')) || res?.isSussccful === true) {
$('#PdfPreviewButtonModal').click();
displaySuccessfulAlert('...تم الحفظ');
} else {
displayErrorAlert(res?.message || 'حدث خطأ أثناء الحفظ');
}
})
.catch(err => {
console.error(err);
displayErrorAlert(err?.message || err);
});
};

viewer.appendTo('#pdfViewer');

$('div').filter(function () {
return $(this).text().includes('This application was built using a trial version of Syncfusion');
}).remove();

console.log('initializePdfViewer: done, viewer=', viewer);
} catch (err) {
console.error('initializePdfViewer failed:', err);
viewer = null;
throw err;
}
}

function ensureViewerInitialized(timeoutMs = 5000) {
return new Promise((resolve, reject) => {
if (viewer) return resolve(viewer);

try {
initializePdfViewer();
} catch (initErr) {
return reject(initErr);
}

const start = Date.now();
const t = setInterval(() => {
if (viewer) {
clearInterval(t);
return resolve(viewer);
}
if (Date.now() - start > timeoutMs) {
clearInterval(t);
return reject(new Error('Viewer init timed out'));
}
}, 50);
});
}

async function setPdfToPdfViewer(url, dmsId, documentId, documentActionId, documentType, incomingHashId = window.currentHashId) {
try {
await ensureViewerInitialized();
} catch (err) {
console.error('setPdfToPdfViewer: ensureViewerInitialized failed', err);
displayErrorAlert('فشل تهيئة عارض الـ PDF.  تحقق من تحميل مكتبات Syncfusion ووجود العنصر #pdfViewer.');
return;
}

try {
if (!viewer) {
console.error('setPdfToPdfViewer: viewer is still null after initialization attempt');
return;
}

console.log('setPdfToPdfViewer incomingHashId=', incomingHashId, 'currentHashId=', window.currentHashId, 'url=', url);

if (typeof incomingHashId !== 'undefined' && incomingHashId !== null && incomingHashId !== '') {
window.currentHashId = incomingHashId;
}

if (viewer) {
viewer.ajaxRequestInitiate = function (args) {
if (args.action === 'Load') {
// دائماً اجعل Load جديد - لا ترسل hashId تلقائياً
const base = Object.assign({}, args.customData || {});
base.documentId = crypto.randomUUID();      // معرف تتبعي جديد
base.cacheBuster = Date.now().toString();   // يكسر الـ HTTP cache
base.fileName = currentPdfName || getFileNameFromUrl(url);
console.log('ajaxRequestInitiate (Load) customData=', base);
args.customData = base;
}
};
} else {
console.error('setPdfToPdfViewer: viewer unexpectedly null before ajaxRequestInitiate assignment');
}

try { viewer.unload(); } catch (e) { }
const bustedUrl = url + (url.includes('?') ? '&' : '?') + 'v=' + Date.now();
viewer.load(bustedUrl);

currentPdfName = getFileNameFromUrl(url);

$('#DocumentTypeForPdfPreView').val(documentType);
$('#DocumentIdForPdfPreView').val(documentId);
$('#DocumentUserActionIdForPdfPreView').val(documentActionId);
} catch (err) {
console.error('setPdfToPdfViewer failed', err);
}
}

function getFileNameFromUrl(url, fallback = 'document.pdf') {
if (!url) return fallback;
currentPdfLink = url;
const clean = url.split('#')[0].split('?')[0];
let name = clean.split('/').pop();
if (!name) return fallback;
name = decodeURIComponent(name);
return name || fallback;
}

function exportAnnotationsViaServer(hashId) {
return fetch('/PdfViewer/ExportAnnotations', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ hashId, annotationDataFormat: 'Json' })
}).then(async (resp) => {
const txt = await resp.text();
if (!resp.ok) throw new Error(txt || `${resp.status} ${resp.statusText}`);
if (txt.startsWith('data:')) {
const b64 = txt.split(',')[1] || '';
return atob(b64);
}
return txt;
});
}

function toBase64Utf8(str) {
return btoa(unescape(encodeURIComponent(String(str ?? ''))));
}

function buildImportedDataBase64(annText) {
const toBase64Utf8Local = (s) => btoa(unescape(encodeURIComponent(String(s ?? ''))));
let text = String(annText || '');
if (text.startsWith('data:')) {
const comma = text.indexOf(',');
const meta = text.substring(5, comma);
const payload = text.substring(comma + 1);
if (/;base64/i.test(meta)) return payload;
return toBase64Utf8Local(decodeURIComponent(payload));
}
if (/^\s*[\{\[]/.test(text)) return toBase64Utf8Local(text);
if (/^[A-Za-z0-9+/]+={0,2}$/.test(text.replace(/\s/g, ''))) return text.replace(/\s/g, '');
return toBase64Utf8Local(text);
}

function normalizeBase64ForUpload(b64) {
if (!b64) return '';
b64 = String(b64).trim();
const commaIdx = b64.indexOf(',');
if (commaIdx >= 0) b64 = b64.substring(commaIdx + 1);
b64 = b64.replace(/\s+/g, '');
b64 = b64.replace(/-/g, '+').replace(/_/g, '/');
const mod4 = b64.length % 4;
if (mod4 === 1) {
console.warn('normalizeBase64ForUpload: length % 4 == 1, trimming last char as fallback');
b64 = b64.slice(0, b64.length - 1);
} else if (mod4 >  0) {
b64 += '='.repeat(4 - mod4);
}
return b64;
}

async function saveAnnotationsAndUpload({ recordId, docType, actionId, fileName, currentHashId }) {
if (!currentHashId) throw new Error('missing hashId');

const annText = await exportAnnotationsViaServer(currentHashId);
const importedData = buildImportedDataBase64(annText);

await fetch('/PdfViewer/ImportAnnotations', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
hashId: String(currentHashId),
fileName: fileName,
importedData: importedData,
annotationDataFormat: 'Json',
recordId: String(recordId || 0),
documentsUserActionsId: String(actionId || 0),
fileType: 'pdf',
documentType: String(docType || '')
})
}).then(async resp => {
if (!resp.ok) throw new Error(await resp.text());
});

const downloadResp = await fetch('/PdfViewer/Download', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ hashId: String(currentHashId), fileName: fileName, fileType: 'pdf' })
});

if (!downloadResp.ok) throw new Error(await downloadResp.text());
const mergedBase64 = await downloadResp.text();

const filesWithIds = [{
RecordId: recordId,
FileContent: normalizeBase64ForUpload(mergedBase64),
FileName: fileName,
FileType: 'pdf',
DocumentType: docType,
HeaderRecordId: 0,
DocumentsUserActionsId: actionId
}];

const uploadRes = await runEndpointWithPostJson('/Master/UploadActionDmsList', filesWithIds);

if ((uploadRes?.data && uploadRes.data.includes('OK')) || uploadRes?.isSussccful === true) {
$('#PdfPreviewButtonModal').click();
displaySuccessfulAlert('تم حفظ الـ PDF بكل التعديلات (يشمل الـ Ink).');
} else {
displayErrorAlert(uploadRes?.message || 'حدث خطأ أثناء الحفظ');
}

return uploadRes;
}
Спасибо

Подробнее здесь: https://stackoverflow.com/questions/798 ... in-library
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Javascript»