Pdf.js: Невозможно распечатать PDF при загрузке в iFrame

Созданный на 11 окт. 2014  ·  21Комментарии  ·  Источник: mozilla/pdf.js

Я пытаюсь использовать 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 загружается в том же домене.

3-upstream 4-printing

Самый полезный комментарий

Я думаю, что знаю причину этого, по крайней мере, в 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 ? (Я никогда не использовал его, поэтому не знаю, подходит ли он для этого варианта использования или нет.)

Все 21 Комментарий

Возможно дубликат ошибки 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?

Была ли эта страница полезной?
0 / 5 - 0 рейтинги

Смежные вопросы

timvandermeij picture timvandermeij  ·  4Комментарии

aaronshaf picture aaronshaf  ·  3Комментарии

hp011235 picture hp011235  ·  4Комментарии

smit-modi picture smit-modi  ·  3Комментарии

liuzhen2008 picture liuzhen2008  ·  4Комментарии