Я пытаюсь использовать Javascript для фокусировки и печати файла PDF, который загружается в iframe, который я динамически помещал в DOM. Эта проблема возникает конкретно у меня в Firefox.
Мой код выглядит следующим образом:
<iframe name="printer_frame" id="printer_frame" src="http://domain.com/media/eparcel_label_1413020567.pdf"></iframe>
window.frames['printer_frame'].window.focus();
window.frames['printer_frame'].window.print();
Я получаю следующую ошибку:
Ошибка: Отказано в доступе к свойству "печать"
Мое исследование говорит мне, что это должно работать, дальнейшее чтение привело меня к мысли, что это может быть ошибка. Любая помощь будет оценена по достоинству.
Я протестировал функциональность, заменив PDF-файл снимком экрана в формате PNG на первой странице внутри него, и функция печати сработала.
Дальнейшее тестирование. Добавил pdfjs в мою установку Chrome и попытался распечатать с тем же кодом, что и выше. та же ошибка:
SecurityError: заблокирован фрейм с источником " http://domain.com " от доступа к фрейму из другого источника.
code: 18
message: "Blocked a frame with origin "http://domain.com" from accessing a cross-origin frame."
name: "SecurityError"
stack:
"Error: Blocked a frame with origin "http://domain.com" from accessing a cross-origin frame.
at Error (native)
at <anonymous>:2:34
at Object.InjectedScript._evaluateOn (<anonymous>:730:39)
at Object.InjectedScript._evaluateAndWrap (<anonymous>:669:52)
at Object.InjectedScript.evaluate (<anonymous>:581:21)"
Я должен четко указать, что файл PDF загружается в том же домене.
Возможно дубликат ошибки 874200 .
Для тех, кто наткнется на эту проблему и хотел бы, чтобы ее можно было обойти (учитывая, что эта проблема существует уже более года без каких-либо исправлений), я использовал ImageMagick в PHP вместе с GhostScript для создания изображений PDF на сервере. , а затем вернул эти URL-адреса изображений в ответ json, распечатав результат из этого было тривиально.
Однако, зная меня, возможно, есть лучший и более простой способ сделать это...
в about:config я установил pdfjs.disabled=true, но pdf начал загрузку, я полагаю, если он использует plugin.disable_full_page_plugin_for_types = application/pdf, он не может загрузить pdf и увидеть в средстве просмотра
Я думаю, что знаю причину этого, по крайней мере, в Firefox. В простом примере, таком как выше, если вы используете Firefox DevTools для проверки document.domain
как на главной странице, так и в iframe, я обнаружил, что document.domain
равно pdf.js
для средство рендеринга PDF.js, так что ограничения браузера на кросс-происхождение срабатывают.
Кроме того, если я создал PDF.js из исходного кода и установил для своего iframe значение web/viewer.html?file=
, а затем вызвал сообщение iframe для печати (как в OP), все сработало нормально.
Есть ли способ для PDF.js (по крайней мере, при работе в Firefox) принимать сообщения из других окон, возможно, через что-то вроде window.postMessage
? (Я никогда не использовал его, поэтому не знаю, подходит ли он для этого варианта использования или нет.)
Еще одно наблюдение: я надеялся инициировать печать с помощью события onload
в iframe
, но PDF еще не обязательно был обработан. Не уверены, есть ли надежный способ проверить это?
Я видел # 5765, но, похоже, он относится только к событиям, к которым вы могли бы подключиться, если бы вы запускали PDF.js напрямую, а не встроенную версию Firefox?
Я сбит с толку тем, что это такая проблема, чтобы сделать что-то столь же простое, как запуск PDF-файла для печати с использованием javascript. Эта проблема, кажется, возникла два или около того года назад (возможно, дольше).
Кто-нибудь нашел решение на стороне клиента? Я видел решение @Petce , но оно мне не подошло.
Не задерживайте дыхание @ Lynda333 , служба поддержки по этой проблеме, как известно, не отвечает. Ваш реальный единственный вариант, на мой взгляд, - найти подходящий компромисс в функциональности. Если вы расскажете нам больше о своей ситуации, я и другие могут представить возможную работу.
@Petce - я не буду, когда увижу, как давно началась эта проблема. Кажется смешным не включать эту способность. Я поговорил с клиентом и собираюсь изменить наш подход к этому сайту. 1) Они могут загрузить PDF и 2) Я воссоздаю часть содержимого PDF в HTML и позволяю пользователю выбирать, что печатать. Для создания требуется больше времени, но это сработает.
Кто-нибудь может распечатать встроенный iframe? я просто устанавливаю последнюю версию расширения, и мне отказывают в разрешении на ошибку, также я не могу просматривать файлы PDF при обычном доступе к PDF.
Используя код из этих коммитов (и сам анализатор данных pdfjs), вы можете переписать свой pdf как временный блоб и добавить инструкцию для печати: https://github.com/mozilla/pdf.js/pull/6190/commits
Создайте iframe с большим двоичным объектом в качестве источника, и он начнет печатать (обратите внимание, что т.е. вообще не будет загружать большие двоичные объекты в iframe, за исключением того, что не следует инструкции по печати).
В любом случае, это довольно сложно, если вы еще не используете пользовательскую версию средства просмотра.
В качестве альтернативы вы можете добавить инструкцию печати на сервер или в любое другое место, где вы можете редактировать данные PDF.
Забавно то, что это нужно только firefox... Об этой проблеме сообщалось уже три года, и firefox - единственный браузер, жалующийся на доступ к iframe contentWindow: похоже, в настоящее время никто не заботится о печати, что, возможно, и хорошо.
Кажется, это работает для меня
setTimeout(function(){
this.printIframeRef.contentWindow.document.getElementById('secondaryPrint').click()
}.bind(this), 3000)
Я не смог найти никаких событий или способов подключиться к средству просмотра, но если вы нажмете кнопку даже на его кнопках печати (я использую версию 1.4.20), то, похоже, оно будет напечатано. Settimeout позволяет зрителю загрузиться и т.д.
Вы можете получить доступ к contentWindow в Firefox? У вас нет проблем с безопасностью?
@paolocaminiti Я загружаю все файлы из одного домена. Кажется, это работает для меня. Я использовал IE 10 и 11, IE Edge, Chrome в Windows. И FireFox 38 на Ubuntu 14.04.
handlePrintClick() {
blurComponentRef(this.printButtonRef)
this.printIframeRef.contentWindow.document.getElementById('secondaryPrint').click()
}
handlePrintLoad() {
this.printIframeRef.contentWindow.addEventListener("documentload", function(){
this.setState({canPrint: true})
}.bind(this));
}
Я вижу, вы снова загружаете PDF-файл с удаленного компьютера, и в результате получается тот же домен.
В chrome/opera/safari я использую это:
function directPrint () {
PDFViewerApplication.pdfDocument.getData().then(function(res) {
var b = URL.createObjectURL(new Blob([res], { type: 'application/pdf' }))
var printFrame = document.getElementById('print-frame')
if (!printFrame) {
printFrame = document.createElement('iframe')
printFrame.id = 'print-frame'
printFrame.src = b
document.body.appendChild(printFrame)
}
setTimeout(function () {
printFrame.contentWindow.print()
// ...dispose iframe and blob.
}, 0)
})
}
Просто использует локальные данные для создания большого двоичного объекта, а затем вызывает печать, setTimeout 0 позволяет прикрепить iframe.
К сожалению, firefox запрещает contentWindow с BLOB-объектом, но BLOB-объект с инструкцией печати будет печатать сам по себе.
Ибо нет решения, использующего локальные данные, но, возможно, наличие прокси-сервера на одном собственном сервере для маршрутизации данных pdf позволит всем быть одним и тем же доменом и применять ваш код.
Привет,
Что значит "рес"? А PDFViewerApplication исходит из PDF.js?
Спасибо,
Да, PDFViewerApplication предоставляется сборкой PDFViewer для pdfjs, исходный код находится в каталоге /web, вы должны изменить его и создать новую сборку, чтобы было проще объединить основной репозиторий по мере его обновления...
res — это просто аргумент, возвращаемый getData, должен быть байтовым представлением pdf-файла, здесь используется для создания URL-адреса локального BLOB-объекта для загрузки без дальнейших сетевых запросов.
Если вы собираетесь использовать что-то вроде приведенного выше кода, вы можете немного его очистить:
function directPrint () {
var printFrame = document.getElementById('print-frame')
if (printFrame) {
printFrame.contentWindow.print()
} else {
PDFViewerApplication.pdfDocument.getData().then(function(res) {
var src = URL.createObjectURL(new Blob([res], { type: 'application/pdf' }))
printFrame = document.createElement('iframe')
printFrame.id = 'print-frame'
printFrame.style.display = 'none'
printFrame.src = src
document.body.appendChild(printFrame)
setTimeout(function () {
printFrame.contentWindow.print()
}, 0)
})
}
}
В конце концов, я решил не утилизировать iframe, поскольку оказалось, что это усложняет понимание того, когда это делать, я просто оставляю его там и повторно использую каждый раз, когда пользователь хочет распечатать, предполагая, что pdf не может измениться между ними.
Надеюсь, поможет.
@thenewguy Просто чтобы прояснить эту ветку для других читателей, похоже, мы делаем совершенно разные вещи:
Я пытаюсь использовать встроенную программу просмотра PDF-файлов в браузере для печати в полном качестве (я не нашел способа получить доступ к contentWindow как на т.е., так и на краю, не имеет значения, используя один и тот же домен).
Вы загружаете средство просмотра PDFjs в iframe, возможно, видимое, и управляете его печатью из хост-приложения.
Это забавно, потому что я пытался добиться того, чтобы @paolocaminiti вставил скрипт в мой iframe и вызвал его как функцию, но теперь я получаю «offsetParent не установлен - не может прокручиваться» 😢. Я буду использовать печать хромированного киоска и забыл об этом.
Пока решения не предложено
Нужно ли мне по-прежнему иметь серверное решение или есть какие-то подвижки в этом вопросе? Можно ли использовать PDFPrintService
из pdf-js? Будет ли это функциональным обходным путем? Если да, то как можно использовать этот сервис, не используя всю программу просмотра pdf?
Исправлено https://bugzilla.mozilla.org/show_bug.cgi?id=911444 .
Самый полезный комментарий
Я думаю, что знаю причину этого, по крайней мере, в Firefox. В простом примере, таком как выше, если вы используете Firefox DevTools для проверки
document.domain
как на главной странице, так и в iframe, я обнаружил, чтоdocument.domain
равноpdf.js
для средство рендеринга PDF.js, так что ограничения браузера на кросс-происхождение срабатывают.Кроме того, если я создал PDF.js из исходного кода и установил для своего iframe значение
web/viewer.html?file=
, а затем вызвал сообщение iframe для печати (как в OP), все сработало нормально.Есть ли способ для PDF.js (по крайней мере, при работе в Firefox) принимать сообщения из других окон, возможно, через что-то вроде
window.postMessage
? (Я никогда не использовал его, поэтому не знаю, подходит ли он для этого варианта использования или нет.)