Pdf.js: تعذر طباعة PDF عند التحميل في iFrame

تم إنشاؤها على ١١ أكتوبر ٢٠١٤  ·  21تعليقات  ·  مصدر: mozilla/pdf.js

أحاول استخدام جافا سكريبت للتركيز وطباعة ملف 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 ، وكانت طباعة النتيجة من ذلك تافهة.

مع ذلك ، بمعرفي ، ربما تكون هناك طريقة أفضل وأسهل للقيام بذلك ...

في حوالي: config لقد قمت بتعيين pdfjs.disabled = صحيح ولكن 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 للطباعة باستخدام جافا سكريبت. يبدو أن هذه المشكلة تعود إلى عامين أو نحو ذلك (ربما أطول) الآن.

هل وجد أي شخص حلاً جانبيًا عميلاً؟ رأيت حل Petce لكن هذا الحل لن يعمل معي.

لا تحبس أنفاسك @ Lynda333 ، فدعم هذه المشكلة معروف بأنه لا يستجيب. خيارك الحقيقي الوحيد في رأيي هو إيجاد حل وسط مناسب في الوظائف. إذا أخبرتنا بالمزيد عن حالتك ، فقد أتمكن من تقديم حل محتمل للآخرين.

Petce - لن أفعل ذلك عندما رأيت منذ متى بدأت هذه المشكلة. يبدو من السخف عدم تضمين هذه القدرة. لقد تحدثت مع العميل وسوف أغير نهجنا لهذا الموقع. 1) يمكنهم تنزيل ملف PDF و 2) أقوم بإعادة إنشاء بعض محتوى PDF بتنسيق HTML والسماح للمستخدم باختيار ما سيتم طباعته. يستغرق المزيد من الوقت للإنشاء ولكنه سينجح.

هل يمكن لأي شخص طباعة إطار iframe المضمن؟ لقد قمت فقط بتثبيت الإصدار الأخير من الامتداد ورفض الحصول على إذن خطأ ، كما أنني لا أستطيع عرض ملفات pdf على وصول pdf العادي.

باستخدام التعليمات البرمجية من هذه الالتزامات (ومحلل بيانات pdfjs نفسه) يمكنك إعادة كتابة ملف pdf الخاص بك على هيئة blob مؤقت وإضافة تعليمات طباعة: https://github.com/mozilla/pdf.js/pull/6190/commits
قم بإنشاء إطار iframe باستخدام blob كمصدر وسيبدأ الطباعة (لاحظ أنه لن يتم تحميل blobs في إطارات iframe على الإطلاق ، بصرف النظر عن عدم اتباع طريقة الطباعة).
على أي حال ، هذا معقد جدًا إذا لم تكن تشغل بالفعل إصدارًا مخصصًا من العارض.
بدلاً من ذلك ، يمكنك إضافة تعليمات الطباعة على الخادم أو في أي مكان يمكنك فيه تحرير بيانات ملف pdf.

الجزء المضحك هو أن Firefox يحتاجه فقط ... لقد مرت ثلاث سنوات على الإبلاغ عن هذه المشكلة وفايرفوكس هو المتصفح الوحيد الذي يشتكي من الوصول إلى محتوى iframe Windows: يبدو أنه لا أحد يهتم حقًا بالطباعة في الوقت الحاضر ، وربما يكون هذا أمرًا جيدًا.

يبدو أن هذا يعمل بالنسبة لي

        setTimeout(function(){
            this.printIframeRef.contentWindow.document.getElementById('secondaryPrint').click()
        }.bind(this), 3000)

لم أتمكن من العثور على أي أحداث أو طرق للتواصل مع العارض ، ولكن إذا قمت بتشغيل النقر حتى على أزرار الطباعة (أنا أستخدم الإصدار 1.4.20) ، فيبدو أنها تطبع. تسمح مهلة التسوية للمشاهد بالتحميل وما إلى ذلك

هل تستطيع الوصول إلى contentWindow على Firefox؟ ألا تواجه مشكلة أمنية؟

paolocaminiti أقوم بتحميل جميع الملفات من نفس المجال. ويبدو أن العمل بالنسبة لي. لقد استخدمت IE 10 و 11 و IE Edge و Chrome على نظام التشغيل Windows. وفايرفوكس 38 على أوبونتو 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)
  })
}

ببساطة يستخدم البيانات المحلية لإنشاء blob ثم استدعاء الطباعة ، يسمح setTimeout 0 بإرفاق إطار iframe.

لسوء الحظ ، لا يسمح Firefox بالمحتوى على Windows مع blob ، ولكن سيتم طباعة blob مع تعليمات الطباعة من تلقاء نفسها.

على سبيل المثال ، لا يوجد حل باستخدام البيانات المحلية ، ولكن ربما يكون وجود وكيل على خادم واحد لتوجيه بيانات ملفات pdf من شأنه السماح للجميع بأن يكونوا نفس المجال وتطبيق الكود الخاص بك.

أهلا،

ماذا يعني ذلك "الدقة"؟ و PDFViewerApplication يأتي من PDF.js؟

شكرا،

نعم يتم توفير PDFViewerApplication بواسطة PDFViewer build of pdfjs ، المصدر موجود ضمن دليل الويب / ، يجب عليك تعديله هناك لإنشاء بنية جديدة بحيث يكون من الأسهل دمج الريبو الرئيسي أثناء تحديثه ...

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 على كل من ie و edge لا يهم باستخدام نفس المجال).
أنت تقوم بتحميل عارض PDFjs في إطار iframe ، ربما يكون مرئيًا ، وتتحكم في طباعته من التطبيق المضيف.

إنه أمر مضحك لأنني كنت أحاول تحقيق paolocaminiti بإدخال برنامج نصي إلى iframe الخاص بي وتسميته كوظيفة ولكني الآن أحصل على "offsetParent لم يتم تعيينه - لا يمكن التمرير" 😢. سأستخدم طباعة كشك الكروم ونسيت هذا.

حتى الآن ، لم يتم اقتراح حل

هل ما زلت بحاجة إلى حل من جانب الخادم أم أن هناك أي تقدم في هذا الموضوع؟ هل من الممكن استخدام PDFPrintService من pdf-js؟ هل سيكون هذا حلاً وظيفيًا؟ إذا كانت الإجابة بنعم ، كيف يمكن استخدام هذه الخدمة دون الحاجة إلى استخدام عارض pdf بالكامل؟

تم الإصلاح بواسطة https://bugzilla.mozilla.org/show_bug.cgi؟

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات

القضايا ذات الصلة

anggikolo11 picture anggikolo11  ·  3تعليقات

BrennanDuffey picture BrennanDuffey  ·  3تعليقات

timvandermeij picture timvandermeij  ·  4تعليقات

aaronshaf picture aaronshaf  ·  3تعليقات

sujit-baniya picture sujit-baniya  ·  3تعليقات