From d3babfef2be0b578c8b1d51d2bcb0ec94eb417d7 Mon Sep 17 00:00:00 2001 From: Vikram Reddy Date: Sat, 25 Oct 2025 22:37:22 +0530 Subject: [PATCH 1/7] Add support for password-protected PDFs Enhanced the `PdfViewer` component to support password-protected PDFs and improved error handling for document loading. Key changes include: - Added a `Password` parameter to the `PdfViewer` component and updated the `OnAfterRenderAsync` method to pass it to JavaScript interop. - Introduced the `OnDocumentLoadError` event callback to handle document loading errors. - Updated `blazor.bootstrap.pdf.js` to support password prompts and handle password-related exceptions. - Modified `PdfViewer_Demo_01_Examples.razor` to test password-protected PDFs with a local file path. - Added a sample encrypted PDF (`pdf_password_protected.pdf`) for testing. - Improved metadata and font handling in the sample PDF. - Enhanced code robustness with null checks and better documentation. NOTE: This commit message is auto-generated using GitHub Copilot. --- .../PdfViewer_Demo_01_Examples.razor | 2 +- .../wwwroot/docs/pdf_password_protected.pdf | Bin 0 -> 14559 bytes .../Components/PdfViewer/PdfViewer.razor.cs | 26 ++++++++- .../PdfViewer/PdfViewerJsInterop.cs | 4 +- .../wwwroot/blazor.bootstrap.pdf.js | 54 +++++++++++++++--- 5 files changed, 75 insertions(+), 11 deletions(-) create mode 100644 BlazorBootstrap.Demo.RCL/wwwroot/docs/pdf_password_protected.pdf diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewer_Demo_01_Examples.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewer_Demo_01_Examples.razor index 3a72042ff..6c224f938 100644 --- a/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewer_Demo_01_Examples.razor +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewer_Demo_01_Examples.razor @@ -1,7 +1,7 @@

@eventLog

diff --git a/BlazorBootstrap.Demo.RCL/wwwroot/docs/pdf_password_protected.pdf b/BlazorBootstrap.Demo.RCL/wwwroot/docs/pdf_password_protected.pdf new file mode 100644 index 0000000000000000000000000000000000000000..9c8652248fe9ac94027ff347e83aa8f9112498f3 GIT binary patch literal 14559 zcmdse^%8LpJ z2|?wdAR)K_OdcvH3=@zQ2FgPOU|w*3lxCM!oVOnNCXOp$P3Ct!*ecW(-$f?O z)gx>9US1GyBS>mqniEx1gw~1Ce7^wa+FOu#U-`ZLmbL3TV#u#uds4*$-Mh{+?p0%me6HEQdg5SoF6Ejhsv-Et(@_j~$7tC<ZU`38@n*B6ss-)*I?%k z@sJ{kkt~Yi3KS!L6Pb}7<3CuQePJ`$buLqh9~!O>8n#QjeSrQ3H3~3LKdeMboB53s z7a5*B-_QCOhu5!5Lbe18V)94=)_sAPs?0bF54HT>??5jIYt z{t0@w`he=L0o$Hos|b};WpuAAsBA$){dQ4nx7x=#yzislBFVd;tF^o(&g7&Gd?V^J zO#y-qtL1620PnsuyaFzx+`VtXTT|`a z5wp=C)@tay>uJv2E^RDn(Qi%1mgb?Rnm<23drOcX%DFxiIquj9j`T!<7r5yIJA1LM zhS{F((GPu&W3ooqzm?h5-FW>2IuV z=MqMgu>ehc=6vmkEQHT*ji@hO8h3rnZ*LOnV_A5EEX!~PWcD2Ow%Wf?DZ0vFyNqG;0oic$&r8fdj%yX+8t7`&WxtP$ z;@PqF!0G!DLUMX)G;Xl5p?$};N8VH1TttQYZjzoOpSwH-jwbLT_?7Pbstoq@YIq9* zhn+X(lJXw^DT=@$1ZS67@-#ma_*za9@@DB)C&=%TJfAs3j;%Jk%_X$LB7md{k< z{Cz}{=m_w=#u0}l&hT>dZZcqMfg`U}%mfvu#MWdz7@6HFZl^K^UDmdc?&B-qAc`wW zwE*K-E>#^Ud>XC%U`pJge7^I5L-Ae!qtLNQJL9wZ{gk8{P;Tib`+FYdmCDN|FQWCq z&5QODUN*Z`yV81YepiJHuAZw~eCD$9WTQG|KLE#Bp0~^B9PQNdSzikHlq?6$XE^TbmJQOz+Jza#f1`29PcPNmJoPZXLQeCQm{leKDHp0oR+}m- zsb%7n_-w!FFRDJK2{rF?1||&gxtaPn717Qqp7TNPb*^^PEiFMyNk(XtOqA z0+nNGfyv#dNukRc0VcNN$<@kBFJ2Z!MUWNk6V$2}|C~nn7AKC>sz^T*@*Aa8XxhS+ z{({p%5Q#ml5>+=AI^eGq(mb>ol4dC?>BmN5twD+=B&8y6Jl>#?mwH>`hgb_pI*Hr8 z@o6hB8h2CYVTzT9W7ebmnY_joQlq#BjUU#OWZ;{Fm0S4pH;Pp2B@3#*-p%0a>Po$- z-t>k|Zs?E>#FWEIVr!L5MLfH%vd!z4XjqLi`>x{&SFx)38-kTPfF)y>CmYXo2|gym zEwRI?`pav6_7z>;>lQI$Sy<{@v^_M+*1i@p{Ly zTZ~~k7^|cvQ{A7TxvlB+gY|w;>WtTY@l&z4^*@)sQ98a8I}Fa4dFdGFyt9?xlV9n1 zX_Y|TQ%8mXc94FF?Pald;0pG9o(wx;3<`I3LwNY$W^DpKevT~6l8H{^>sCLR%dZlc zAa(W9a+hw%g1)MmnRJ-rV~>W{KGYp9ja{FQ;Be8G*A)mZnMM(e(ykU)`3=;W6^~Ey zwoUqyCOc**s@1!Vx_wLtH~_u5*?N8{s|})-`Cf6+R;_+3@x3N*M9Zs+q(U+F6|?Zb zX9oS@YsAMr(Rt<*p|QeTIcdUmCmeKJzfw(~pWetF;`Sc6d44bpNDQLqu^r;sHu~iM zHz;3?a%K^n}@mSP-$!_+TG*Fx7HUKc$%u&*w}xiW<$wF z(PUU;0?9nxfK^3Bvpg|#{>H)9b@dIWjYZQ?ha>(g8qu~hqcYw4^7qdVrMqNwd;sfC z4~V-bdV&UAq{f%>R zJlD`ALyltYqn`#VGe2-mxM4u10{_hdd8@1tsE6Mq!tEQYNn3WcWYxlO(02W!9vS@p zx26Nc6hW=IzXCZ)yY>z``EA^8HM{;W=L2(axZVRVbtR4Ay(O^&*(TGOh z;8@TSzU4qE=ft|lr5fPt#*&N$XS0B7V>?9Kgz9mMW4%gTjD7LpV-o#at@>#UC;Sd! zyS2|#(>51d&V2j}e7-5%Ysu31;oX9t^kD2uX_kiG?bUZ$E_N@CjaKCk&3al!!UI`G z`fs=Hl)_2KvR0%gMgd``TI9C63;ho|*W7q~@+$(Of;v8&`y&RZMB#*uyzw7ec*H;Q zSEJ+4f2D!zjJK;BNn%OO6WceAKt(?*We>K`9Fu;&ryh!m0Q)mIC0IK;SQB?+1#36x zUs0s@MpTl*nYIx|Zz`h#+vf0OZ)QbwCykGJHK*vkcWJwnQuncVD|p6!inHeJ(D%I9 z#60l{UGql9zUxZR{P}pxVd?w)H!daP5#dpmp*iir3g-6wFMTW?(?~yePOp>wy8Ht+ zl9t2x;#rMNaJF0GkHT2VhN8YjM0s$UDEJ0HmCD^zuI4Q2XS{S5TDNJZ4q5{h7%m-a zD#3ddGM@~4_~f1Jb%_@74~_M-Pj0fQw>eM$TWQ)s9-Uo?5!3EoUfX4!5OYlyG;Pi`6TmrHeek8>-V3{$MIYQ5XNUusouIY zU7dMWPYm5;%qX4P5LmO${TiH`Nz-vr-uBb}NpJM`x?AMbe!j9J6$ICAsRDO}y9&%s84KaP=YT zk5?uY0qjK=)M*&S5W_M}hw}%f_g**8z+47q<^9ZkoXVx9z)w~J zWWo@EjYXJn3hl&p-MfFgOg-2(IZX0PeNjf*X6@a~AG$Z;*k0zg8=MIDyMbEAICk=> zN6v{-1iSLMmyyo5?8FikrISJ2m2V4LZ?1;{NFbH1?U1rUW<6KKPn4^q%?}L1B1krc zmtUK`@KO&Y*6;LznKg-!oKPOnhd*0oa|1h3=So6z==8D@q`JJMlnmK%L#TLk? zsu9pMw)!4rB{Yfzrbn1l!&R*UVkjIW@L{pVK|BJl*q;kB?&)#{onUEv-ktk)lV99g ze$|LL@ox3YO#R@%p4@_k^b6xLK0of*rsZQ+`pR_UtYxLv#iUuGY_bQr zxAmp0(=Sv_Xe$#lk8D_N$ZF)*0v4Wa&LbZfXq=idN=eP+yeq#e6K*pkJalD|dG65h zYb;{r#x0w*d#qHCpZk>e@x8aH-G<_Z?Vt^PQ%gur;=Luo2dY`+u~pAisvAb<)ZX|_x6`Oy z!Z&LzuzjvJ=nqD=s zZ){~0T$#JkZ0b4VgWqFZSPRSUjz4WG$~@=naafh5Gqwoc@_^ZpI3?ya)p^qUYX{RS zB@yvT4PbSvCv*wIoci@Eh929PM)SwtUq(aSSUxTDrvq(f3Bcz!T#|e4a@jT z_t6W&x3=$I`=aSxh9St0!MFG96x`xPBSP@X;q8vxtFvk~WlUH*s2A-+GZEMXYc=3u zXVK>cSYBV|{CNUhgz+zwDsvu2%&zV|AiL5p?>;8gX%Vr*dS;uAPKI?5+w1_M*Mroj z&qgK8q8|EagxWY`KM-NE?&OH2@yddx3SM6Ny-t;xLnP7jKzOH$H}ckB$Hi_q^)`&D zvl6}HLo8I^wxs_+wewAXlg9r*7%!{9Eg$z-p4p&is{Q zl+0=U2Dk4ZXVkzzUu8NvLQDmf5mllIDC%Vk}qI_8Z>G{|gwaO~CXtqq)* zBoY>dbY2rvx9P8vQRPYflU9`JY9a#(=U}4LE>ZeDSAd%^Hic>rZ8oUv_ylr^8jmA< zoU*7fVthg4lEb}qBqqAii+(_FC+h;UAog0F4u2>eMinsj1lhrL+0xTdCqGx@LZLfe zzmT0P+KMns$(!(M*ElQ(8PkGD3as-6sZa36BR;;@7p3Uq8fnpYsc8I+G{fG99wn32 zQu;p1(egU8DH#lvz4$R}x}pN-{Wcexb)-3%39cm$Ay!%HLvowp1-{#}69C<>3lU=ZmA7wmDoN}&bgMmYAs9p%oA)7lyculw_+(3_ z9}*m-&(e=xoGEP*x9Js*rru zuy=DyQ@ADSY%f1;CD=3j7_KnO->mS?xq)j8j{8%*CUml_$~s2WJ}=Hg*`~eliE)c1 zHZwEZ_pkZ4g%`oL4FeF{0jrM8PVeH(^lbbwD_HsM{Az4+jdR3aD|N|_G$AZs*}}4r zDAat!g`oYo#kA&#R#BM1oFP_jUXZJs$OE;)L&qPL7o+-9NHyO+s+`K)g&YW)hyLeL z4^deb{+;iXAsd_XYJ%^h&5JC>(Kx2Y^Ksm@LnAty`p zgzGHIwUJocWUDgpse#yOW%P{?*zOvn&&ti|pKF2H1b_p9#VG+NbUqvJ)&O-M>H~k0 zADNuDnn+MQI8HBHs-qNq#_yaw#ZQv`1@xiM?U;f|O!%?X0D|0XrA6=oHzix7zT61O z8~*zyG~$U?jMZ!JlJ1?GX`!#;yH6P=crT0hCj|pneiXdA&1^#;hF}CsN{?9T5p4So z(7`LrwdPkwSZ#semrr?4;+s!8uIS(c3FH> zWk$1$Ug;V8-vrFZAZG}RSRdMABar(=A`>kqe6q$ncgDoM4HoaV^G!$O5#0)cKEY*@ zVuYl}`_4CS-0CS#el>#=;t)IfQhZHd>=kijPaVktlg@*S8Aqwt&mb3Tx)HaGddh2Z zS=guU(}^%j4mV;)uqFlxtNgqa2Ho89pODUC9PeGp&aVC_8FAdtvoBEA9c5Q$(uohx zf2I5VP%_vG+xX*=Tc2pCfI9apn>%qXNd-3-eUXt4#wC7r-cw3|XBHlUffJeT=FbNh zM7fKgqd=T@;o(g{|FphjZmW2?Gd}jPuk`-MweeXUk4@;~W~&muo29;_e@55qlsS(d z<#88lv6WK5@h3u>&qHX=n=4|(;y#g{X2Zndy&gZ^@&_rOA{ObTJSmno1A5DjTVt1; zF7O^`4T!(Hni|ReIcCXW{$)ps%PW}?`l*>#D1g(1l26`-L}n4FA@upo+A+}v=Y1)) z9T|XIT&lAV-Bexsf~$AtFd(Jv{QImuyFrFplwsNC7YDW*+Fi3x-`&aPIM|a(jX4O5 zi<|;c`Rn0;6b!<$bbSj+1@ExE@a7V8?b4OTJr7+x zy3aV_2c%hwg|%FsGIsT^f{jY$g>l-&RTV(*au#T^mb>9W>?G0`zj~Z#Ylg&BXZL`0qjcDdd zc@diG$`XQ&OMmIxxTE?LeWFsj_6n*t2T8ut4jWNxOL#~kQmTE3=d4MiUssJ#;J=YI zAA9n?ctZT~1!WlfX#Cinh5o9@Mb)prY)|XFEY2Ou}EfX@BqF z8>-^W2n(I9CZJ*I0`NcU0PTnwICp#lRot<#Q< zh#*h$Gg`%;UGJ5^AhFGAFiur zHw0&1eS|bS%ROiCFik!hl{^-mEs&d)XRNZRdSof>s8*4h&UaMllXqq(k@mSY!m)4oL^HLTCGMR~531(8j{e+wwD=-^zinDj`$6BkOZ)Kl%6A>&syE`q9>UyO-+7WU&E}A= zRi>VU7`#8jzb!BXT5SV*2~6~tA(zmTOf!l6YT~6tDT&Ncw7s{8F8QN-8B32Xa8Q=Y zWqoUzhp1y9Q~NOT&8@E-p3aIgxRT7M*kJl*x~p24c~W{JStxNO-ZTE&g_CPp=w=av zY@YNL$mZMti>8aAf_mZO90doBX^+YHkrwbGPe6_1 zBnY`5Z>rzJiC+FV`DsQKuY(Pp{oc+cPai%%ViEePWGf&e;=>nkK+*FrUc1k!a#V6bYV7g=iy*K&6NdBu2sgQsTsNDnl&{C#gS#V9*^a8BnZ(x z&L5``XI`fmHuoY5594~L6oq5Cg?eJFSV=`L|M-(ihg#SD2yX!536>Y>kFyPDnG_1Aqvx`cLpfY$<=&Xf8hKDR7Ts>3N2qErH^ub#4q3} z#6ms=i(v{f+zl7#G^UeZSOlmWG3H5!+MNlR2F{-*Y*Ri(m#gZl*df+{+-34@58_xS?O zP;#g51cq1@woeZj)52=F_jK;iIt20>apmr%F7*Y8*VinsVGYf4 zfMGr}*Rr8@&(}dDRduSz{$7QzqIKL!pAh=w-T%z8X{TZYH<^xiq9$$BedMU9v?eiq)L2L0(zLs~c37;CF#}%(E{?)01*tTs zd{%BK?WYzKq$N9ths}xIIQVAo2G%lL;V@qvJ4%0d<*eCE&3yDex1Ecil8}Ze{~N;d z)jC_u*{)8`1-B~bdrt)}wS8VGmZcBL>7@}(pZZIpXZjvJLb?dIC9g0$Rzixz(Zak& zuqXP%?&bcJEJCiQO`BJ`PIZN>HPV@xjpi=VAT2|$quk_C^39`$nxRQI97Y!;0VKCM z6Dm<05<)RY8ErpSK_OA&EB2*owXZK|19s1k*stxW2WJ|KL`W?yDV;nw8i?Z6eiv=jB^Uv?#>Yd{ZqR_X3f=({fO2m7V=0^B?fHKGtb|p z6opL7Gm&}}@`z1bgkKotHazQbT^@eV65GMxa_%USraj{D9l>rwZxXPHFOof}>?85x z*!*fyI<}G4^AIobo9T?l3VWP2OL^tV;)^Mit zhcL-Bw@7i6$c(vRujpww5nxaaU_ZVWwVl{gHw~lHEv!B7UI- zF@5pi+VB?b7&X3qtt1dH=`^Y6(w7D_K^l@s(g>buDHGQf&CmCw!(DC4jO|W|U`nq} zx(X8@g~Ley>qHyX&kMn8gv{SCl)teuK!HENGP*u4NB}?F*~uM-bhARET-=?}7(@`J zu8wfT^g!ic^78WBvY2)^OuGZZ#tneMw(u*tBOFjxvQ9P*NDN|zU)Ig)8apEj7A5At zCUjll1&Lq=${}17ktiG6zdL0;Z46M>7+8^@5RjN(4dMM)4JdRy_Ig=^zXoFvKg9fo zf6oL7Vk$cBNJo9lw7-Tyq0Zg_6J9|9f#2%@fItz@_3{t@>c&8tkRVJW=1;Z%#Pfju z{&f=pfC)qx_z(bw08E5LgdPHfKmZd#5ab~M2)-@}3u8*cKuk$Q@F4&sAc!e}G2=nM zdqLN2U=d84&~+OGLqrgSnE?_K2AF^auG@q$y&%kf0O0GnB7$Impy2g-!0WMspzD>d zsb9|rU(W}FF>8Y%m|2kP?SKWZDS^P4((j!KUQ-eQ15AWLm>HrX7@8mfOs}XYh6?C< z22cR=yCx7Jfrk(OK}CuD!DuML4S9XO|C6OU9+vLEWk5~|cHMt15ExecTP`pxRD$U` zD=5L#5H0|IC2I_CQSLq%J{w@xyk--oU&qG{!yYB4N6vt2D3g>$6`#Gjra$07lt zmG5%qCdA88o4$S>=K<^fI73)fpJ-_d^}?NC1jExjsYlplBGnxT7wBFViC`jpbNlYV5g zJ31mvgry`D!8p}|D@@)%O5@jw-667Sq;SQbfIq2mb0lC=hI*B{vNMQh)04S3cX|Kq zXoZl(!9D!cwRUd(kd(VH&YgaqFh_C-iZ-UMjrNrc_e`~xdXzMan8l_yqt30iS<^hH ztgf)&wYULe$WxbNJGSH7dP95Pxr{dz{VrLPSd?I=93#qyvM3hG1%pm4y8Bbrlc|=t zZ4)u$x_HM30mL}P4Z}jko>kW5p&yM$;f)KXzodd#&-1?HSi9jrN3MLjQ|7+{@0ECTLk|S$$wcj`2R;%?H?Ze zHVOYIKgQ7f8{+xjIfM2%1PGA4fRjMf9m)3@n5Sw3hm}DXNy4p z_7bXyKPta1y&C{{z1u(aANY>}xK{MPHY)G!u7E+Kx?gWi4ZyGNjCMpg5c69h0Kh-3 z`JeXff1M~N`+raT6E6A>`t`q>79qhuOiLyE@PWo@@itwN14%vexoI0&ev}#Yy(x+N zuairkBG>}kctY;1Xu1SZi5DUy8;Qzh^*@JbP}km|iP=r+=4sXsTDp(k*2bT{T{8lB z_NmA;^1YhKqfUX3Ta6TSjgCoS9k?UD7b@8uPG92!`VMA9SSN^}q9D?^otyHxncA$)4^`YFdkz z^jd;wk%Rc}LvGscWEIH@4r}(@I68UHY`T>-cTrkO=e_jf*3Bs(H-&*%-Ep4Vi4GH` ze+mbyh1R140`L*|u2G5_L(mwDaO2L(zzQYDQD*0pOtj)&3hG<%$uaMaSGO*^EJ|;~ z=7&a@YRx(MMDAe-Ug0tK8?7b|QrUH2m5X|l&BlLPn*UUAO@s|bLe!AfD8%n@;M&Is ziVE^!e6$Dz$R`TIL<8DLH)jvD719mx+mBp(z~2QR;4eAkhhyS|YgPFzlKlUYyx*e~ zbTEGFw|rtm8&d%SfWMv8wNUVDqMfaDknR8zehjo4z^{w+#yD3cN6em}e}Cov{wh8E zJwXn$IL3KmRN!wPsepF&aQVH^U()-#j)`12iRv~rjh7}67Eh16Dn z{wAf1uyn%!wy&ciw1<_u=JiMnVT_&qs|fg?<`ML#lEF}JE)EDEn6s5G${iEHVQ3() z$^IQ6g8oyl)R687YlJ)E8Y%sEykMxN`VZn6V~vG>E9T#UW*t$9!KLw7F8dCorSa5( z`t9PS-wjZ%L?P4IlnvIEa+O@8+Y(ifIZB1Ui#+~SGRT+nuHMI%4*xgIlSA;H^0MbO zCr!gQ9dmBiR0V2CZME|U3ARtXHA*6(IjLzRIEbCvdVIbWpAj!L`c03&i9f}?N9qZM z;qw;XhOlNr6Duuh1+LFuN{&Tg_})hT{UdK|N|ll}qUzo&=AS)Uv&^qMp);o#-Sjzi zUOdcY%?&5CT_#x%3Z+u&TjmSg6{~&m66G3e9_mSSf3@=yXR$WZ&TP$oTr9qi{nNv? zN>e@c5)`ZvPm%h?46-d#wr6Krzvo^X&vIL0*SHIOU?Hd=O}_^_pfeAMUK`TnyfylA zNfmL7zHFO^dh_cs124~LKI4I3+$(v*!!!&Ow;|*xNOBoy6#txrRjR1dS4Em(ZyW9{ zrzki!6=a0|p$QyT?!J?~f>-76?jDrqfT@6NRoQvrbUp(x+T1dvFkq^b?<{0fWSPRz zo^P}Bi((l`OUe9Y;s!fu*1bfF&Y<@N=bMjwKnMMK^zk>3@0mpLzUZBAC|Xq92n|oP z-B8jJ*X{Q7IP%fzAtWq4CeH}d*h}QIvo!xSQx~{%$npuVjKIPe+tl~_PtL}lVH5tb z5>F@W=v-$~>!2Ek_~_oSuouF|MyoY`10K=Kv0tArC~9pa97I@hFkt)IpR%x1Q?Xm+ z9hls{YwxDN!l9RcDD~2*`jHAg`90mA!(STum(M!GE^j&+CGdMzaeGt8^K7L$7x)EK z&=APMlu0+1hTrFJ}*I zlv-9`PgIfD+5 z$0_pUzxK$`Rf+%Fe&`)P)J4@}S;e^d!K0mN9OAQw^-e>GdoPKUnrP)cN04%22$aDY z)-VpZPoeT`bJlD3WYsW?z>n3A$G<@A>5+GyUzC8hP&Z4!CsujQ!qa|_w`!vrBJu%PxHI$I`eW<+dqZt+>+b0jj z8QqCScYJ5Y2vt`dtWgv5x#!XSAxCK4LWNhGDx$A-n(RBt(JNZ2^s@aw`(RyPZ`92) zskrWE`wphY6z16`SczZKeI`hRY~!x?4rEE4r?S%+-gGHi?&l(Genf>t?^IE&{5CeDk=V&g5H~P0Rl=c}K8{T6%yiP_l%MT&3ud%_eT59WW&x>^HVr`H@aoAxJzj!k_i5H#JxG^QWOHNnnH^ztAYZd+sZ{WDcSM?<2 znW%!MpE?OI?+U-d`?7wg<16(j*z~K)1J&9JGA1K@9r^%LvgK;!qtjF)R6%K~NS7S; zs3~0b(`3oOYyG$iso~vcwk+8haaqX`zzV{7Ykr$o=DU6GxPtvtu*Tl#_cN??mf4qp z8wvg3jG}XEH*XGgxi5-*B|kH~4-IJ{N?JknDEFog5*=dEcaWdx7n4~{=DvN~*Ul1g zMoi;YUdy6S(jJkgFY9YViF)SJeTF=8PRf5#I7+wT$5%s@A?-zu)mS z15Z7Yt}Ti7-W~P*aQE&1bc=splm2oe*KQGWSyw?>yJ2pa*RBoY2j!eSFs|><@adns z@V~<@IgEvOaJIR2A{YvP`w)Ir#C0x>030ZHohb9$-{_)|NNs0lcg)53x97xMx>3S zfMi8QgkUgP0XP^6#AF%4gfRI%KsX!-f(T)@CWpzj!Mt8z#tC4OlVs&EDMcVbK`00U zhrqzXvM^booS>*I6fPh7)4BL)9Fs3JDNtE*yL61 zVq%mg{Oi5PX~J;f^<5%`yfse-!^^ybaahpVW7mYbLi5_)t8!h1`|-K4Sk+`O=}q39-4t*>WVkwd+~5F68+1V7(A;rDU}@!#4M%F`SzIx{C|EZTHo9i-^s8zDn%e?m-dtu6mb+zmCSQHO%$+m OnDocumentLoaded { get; set; } + /// + /// This event fires if there is an error loading the PDF document. + /// + [Parameter] + public EventCallback OnDocumentLoadError { get; set; } + /// /// This event fires immediately after the page is changed. /// @@ -222,6 +237,15 @@ private async Task ZoomOutAsync() [Parameter] public Orientation Orientation { get; set; } = Orientation.Portrait; + /// + /// Gets or sets the password used for the PDF document if it is password-protected. + /// + /// + /// Default value is . + /// + [Parameter] + public string? Password { get; set; } + /// /// Provides JavaScript interop functionality for the PDF viewer. /// diff --git a/blazorbootstrap/Components/PdfViewer/PdfViewerJsInterop.cs b/blazorbootstrap/Components/PdfViewer/PdfViewerJsInterop.cs index 93bfc7f48..087f85bdd 100644 --- a/blazorbootstrap/Components/PdfViewer/PdfViewerJsInterop.cs +++ b/blazorbootstrap/Components/PdfViewer/PdfViewerJsInterop.cs @@ -40,10 +40,10 @@ public async Task GotoPageAsync(object objRef, string elementId, int gotoPageNum await module.InvokeVoidAsync("gotoPage", objRef, elementId, gotoPageNum); } - public async Task InitializeAsync(object objRef, string elementId, double scale, double rotation, string url) + public async Task InitializeAsync(object objRef, string elementId, double scale, double rotation, string url, string password) { var module = await moduleTask.Value; - await module.InvokeVoidAsync("initialize", objRef, elementId, scale, rotation, url); + await module.InvokeVoidAsync("initialize", objRef, elementId, scale, rotation, url, password); } public async Task LastPageAsync(object objRef, string elementId) diff --git a/blazorbootstrap/wwwroot/blazor.bootstrap.pdf.js b/blazorbootstrap/wwwroot/blazor.bootstrap.pdf.js index 67c3e3b02..a920e1782 100644 --- a/blazorbootstrap/wwwroot/blazor.bootstrap.pdf.js +++ b/blazorbootstrap/wwwroot/blazor.bootstrap.pdf.js @@ -194,17 +194,57 @@ pageRotateCwButton.disabled = this.pagesCount === 0; pageRotateCcwButton.disabled = this.pagesCount === 0; */ -export function initialize(dotNetHelper, elementId, scale, rotation, url) { +export function initialize(dotNetHelper, elementId, scale, rotation, url, password = null) { const pdf = new Pdf(elementId); pdf.scale = scale; pdf.rotation = rotation; - pdfJS.getDocument(url).promise.then(function (doc) { - pdf.pdfDoc = doc; - pdf.pagesCount = doc.numPages; - renderPage(pdf, pdf.pageNum); - dotNetHelper.invokeMethodAsync('DocumentLoaded', { pagesCount: pdf.pagesCount, pageNumber: pdf.pageNum }); - }); + // prepare loading options (optional password allowed) + const options = { url }; + if (password) { + options.password = password; // pre-supply if user already has it + } + + // begin loading document + const loadingTask = pdfJS.getDocument(options); + + // handle password only when required (optional password support) + loadingTask.onPassword = function (updatePassword, reason) { + if (reason === pdfJS.PasswordResponses.NEED_PASSWORD) { + // only prompt if PDF actually requires password + const password = prompt("This PDF is password protected. Enter password:"); + updatePassword(password); + } else if (reason === pdfJS.PasswordResponses.INCORRECT_PASSWORD) { + const password = prompt("Incorrect password. Please try again:"); + updatePassword(password); + } + }; + + // handle the promise + loadingTask + .promise + .then(function (doc) { + pdf.pdfDoc = doc; + pdf.pagesCount = doc.numPages; + renderPage(pdf, pdf.pageNum); + + // notify .NET side that document is loaded + dotNetHelper.invokeMethodAsync('DocumentLoaded', { + pagesCount: pdf.pagesCount, + pageNumber: pdf.pageNum + }); + }) + .catch(function (error) { + console.error("PDF loading error:", error); + + // handle password exceptions specifically + if (error.name === "PasswordException") { + console.error("Password required but not provided"); + } + + // notify .NET side that document loading failed + dotNetHelper.invokeMethodAsync('DocumentLoadError', error.message); + }); } function isDomSupported() { From 8d9fbf426425f49dc4988fe91901cea3a93563fb Mon Sep 17 00:00:00 2001 From: Vikram Reddy Date: Wed, 29 Oct 2025 11:39:51 +0530 Subject: [PATCH 2/7] PdfViewer failed when the pdf has password #1184 - Intital commot --- .../PdfViewer/PdfViewerDocumentation.razor | 8 ++++++++ ...dfViewer_Demo_05_Password_Protected_A.razor | 18 ++++++++++++++++++ ...sword_Protected_B_Prompt_For_Password.razor | 17 +++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewer_Demo_05_Password_Protected_A.razor create mode 100644 BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewer_Demo_05_Password_Protected_B_Prompt_For_Password.razor diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewerDocumentation.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewerDocumentation.razor index c959b8d54..d8627aebc 100644 --- a/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewerDocumentation.razor +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewerDocumentation.razor @@ -35,6 +35,14 @@ Blazor Bootstrap: Blazor PDF Viewer Component - RTL doc +
+ +
+ +
+ +
+ @code { private const string pageUrl = RouteConstants.Demos_PDFViewer_Documentation; private const string pageTitle = "Blazor PDF Viewer"; diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewer_Demo_05_Password_Protected_A.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewer_Demo_05_Password_Protected_A.razor new file mode 100644 index 000000000..ad7a00be2 --- /dev/null +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewer_Demo_05_Password_Protected_A.razor @@ -0,0 +1,18 @@ +

@eventLog

+ + + +@code { + private string documentUrl = $"{StringConstants.DocsBasePath}/pdf_password_protected.pdf"; + private string eventLog { get; set; } = $"Last event: ..., CurrentPage: 0, TotalPages: 0"; + + private void OnDocumentLoaded(PdfViewerEventArgs args) + => eventLog = $"Last event: OnDocumentLoaded, CurrentPage: {args.CurrentPage}, TotalPages: {args.TotalPages}"; + + private void OnPageChanged(PdfViewerEventArgs args) + => eventLog = $"Last event: OnPageChanged, CurrentPage: {args.CurrentPage}, TotalPages: {args.TotalPages}"; +} diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewer_Demo_05_Password_Protected_B_Prompt_For_Password.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewer_Demo_05_Password_Protected_B_Prompt_For_Password.razor new file mode 100644 index 000000000..40da0c954 --- /dev/null +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewer_Demo_05_Password_Protected_B_Prompt_For_Password.razor @@ -0,0 +1,17 @@ +

@eventLog

+ + + +@code { + private string documentUrl = $"{StringConstants.DocsBasePath}/pdf_password_protected.pdf"; + private string eventLog { get; set; } = $"Last event: ..., CurrentPage: 0, TotalPages: 0"; + + private void OnDocumentLoaded(PdfViewerEventArgs args) + => eventLog = $"Last event: OnDocumentLoaded, CurrentPage: {args.CurrentPage}, TotalPages: {args.TotalPages}"; + + private void OnPageChanged(PdfViewerEventArgs args) + => eventLog = $"Last event: OnPageChanged, CurrentPage: {args.CurrentPage}, TotalPages: {args.TotalPages}"; +} From 23f814c69f05ec2d10f6d17a6bd32590322c55d0 Mon Sep 17 00:00:00 2001 From: Vikram Reddy Date: Wed, 29 Oct 2025 12:55:32 +0530 Subject: [PATCH 3/7] PdfViewer - Demos updated --- ...fViewer_Demo_05_Password_Protected_A.razor | 17 +------------ ...word_Protected_B_Prompt_For_Password.razor | 25 ++++++++----------- 2 files changed, 11 insertions(+), 31 deletions(-) diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewer_Demo_05_Password_Protected_A.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewer_Demo_05_Password_Protected_A.razor index ad7a00be2..2be8ced72 100644 --- a/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewer_Demo_05_Password_Protected_A.razor +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewer_Demo_05_Password_Protected_A.razor @@ -1,18 +1,3 @@ -

@eventLog

- - -@code { - private string documentUrl = $"{StringConstants.DocsBasePath}/pdf_password_protected.pdf"; - private string eventLog { get; set; } = $"Last event: ..., CurrentPage: 0, TotalPages: 0"; - - private void OnDocumentLoaded(PdfViewerEventArgs args) - => eventLog = $"Last event: OnDocumentLoaded, CurrentPage: {args.CurrentPage}, TotalPages: {args.TotalPages}"; - - private void OnPageChanged(PdfViewerEventArgs args) - => eventLog = $"Last event: OnPageChanged, CurrentPage: {args.CurrentPage}, TotalPages: {args.TotalPages}"; -} + Password="12345" /> diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewer_Demo_05_Password_Protected_B_Prompt_For_Password.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewer_Demo_05_Password_Protected_B_Prompt_For_Password.razor index 40da0c954..7651c0af6 100644 --- a/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewer_Demo_05_Password_Protected_B_Prompt_For_Password.razor +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewer_Demo_05_Password_Protected_B_Prompt_For_Password.razor @@ -1,17 +1,12 @@ -

@eventLog

- - +@if (showPdfViewer) +{ + +} +else +{ + +} @code { - private string documentUrl = $"{StringConstants.DocsBasePath}/pdf_password_protected.pdf"; - private string eventLog { get; set; } = $"Last event: ..., CurrentPage: 0, TotalPages: 0"; - - private void OnDocumentLoaded(PdfViewerEventArgs args) - => eventLog = $"Last event: OnDocumentLoaded, CurrentPage: {args.CurrentPage}, TotalPages: {args.TotalPages}"; - - private void OnPageChanged(PdfViewerEventArgs args) - => eventLog = $"Last event: OnPageChanged, CurrentPage: {args.CurrentPage}, TotalPages: {args.TotalPages}"; -} + private bool showPdfViewer = false; +} \ No newline at end of file From 6aa91077ba964341e8ec4732785df5617af8b759 Mon Sep 17 00:00:00 2001 From: Vikram Reddy Date: Wed, 29 Oct 2025 21:27:13 +0530 Subject: [PATCH 4/7] Update PdfViewer URL to use a hosted PDF file Replaced the local file path in the `Url` property of the `` component with a publicly accessible URL pointing to a hosted PDF file on GitHub. This ensures the PDF file can be viewed in environments where the local file path is inaccessible. NOTE: This commit message is auto-generated using GitHub Copilot. --- .../Components/Pages/PdfViewer/PdfViewer_Demo_01_Examples.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewer_Demo_01_Examples.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewer_Demo_01_Examples.razor index 6c224f938..3a72042ff 100644 --- a/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewer_Demo_01_Examples.razor +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewer_Demo_01_Examples.razor @@ -1,7 +1,7 @@

@eventLog

From 2152690d7d8d9c92fe2577b693b0fbfde1c78fb9 Mon Sep 17 00:00:00 2001 From: Vikram Reddy Date: Thu, 30 Oct 2025 11:25:20 +0530 Subject: [PATCH 5/7] PDF Viewer demos updated --- .../Pages/PdfViewer/PdfViewerDocumentation.razor | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewerDocumentation.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewerDocumentation.razor index d8627aebc..51f6d6db9 100644 --- a/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewerDocumentation.razor +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewerDocumentation.razor @@ -36,10 +36,17 @@
+
+ To open a password-protected PDF document, set the Password parameter to the required password. +
+
+ If the Password parameter is not set and the PDF document is password-protected, the PDF Viewer component will prompt the user to enter the password. + In the following example, the PDF Viewer prompts the user to enter the password for the protected PDF document. Enter 12345 as the password to view the document. +
From 46689480cfd1cd93681de14f8e759e17e1d331b0 Mon Sep 17 00:00:00 2001 From: Vikram Reddy Date: Thu, 30 Oct 2025 11:34:29 +0530 Subject: [PATCH 6/7] PDF Viewer - Docs update --- docs/docs/05-components/pdf-viewer.mdx | 40 ++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/docs/docs/05-components/pdf-viewer.mdx b/docs/docs/05-components/pdf-viewer.mdx index 1c72d59d0..a51d4cae0 100644 --- a/docs/docs/05-components/pdf-viewer.mdx +++ b/docs/docs/05-components/pdf-viewer.mdx @@ -20,6 +20,7 @@ The Blazor PDF Viewer component allows users to view PDF files directly in the b | Name | Type | Default | Required | Description | Added Version | |:--|:--|:--|:--|:--|:--| | Orientation | `Orientation` | `Orientation.Portrait` | | Gets or sets the preferred orientation for the PDF viewer. | 2.1.0 | +| Password | string | null | | Gets or sets the password required to open password-protected PDF documents. | 3.5.0 | | Url | string | null | ✔️ | Gets or sets the URL of the PDF document to be displayed. PDF Viewer component supports base64 string as a URL. | 1.11.0 | ## Callback Events @@ -27,6 +28,7 @@ The Blazor PDF Viewer component allows users to view PDF files directly in the b | Event | Description | Added Version | |:--|:--|:--| | OnDocumentLoaded | This event fires immediately after the PDF document is loaded. | 1.11.0 | +| OnDocumentLoadError | This event fires if there is an error loading the PDF document. | 3.5.0 | | OnPageChanged | This event fires immediately after the page is changed. | 1.11.0 | ## Examples @@ -148,3 +150,41 @@ Below screenshot is added for demo purposes only. For additional info, refer to => eventLog = $"Last event: OnPageChanged, CurrentPage: {args.CurrentPage}, TotalPages: {args.TotalPages}"; } ``` + +### Password protected + +To open a password-protected PDF document, set the Password parameter to the required password. + +Blazor Bootstrap: Blazor PDF Viewer Component - Password protected + +```cshtml {} showLineNumbers + +``` + +[See demo here.](https://demos.blazorbootstrap.com/pdf-viewer#password-protected) + +### Prompt for password + +If the Password parameter is not set and the PDF document is password-protected, the PDF Viewer component will prompt the user to enter the password. +In the following example, the PDF Viewer prompts the user to enter the password for the protected PDF document. Enter 12345 as the password to view the document. + +Blazor Bootstrap: Blazor PDF Viewer Component - Prompt for password + +```cshtml {} showLineNumbers +@if (showPdfViewer) +{ + +} +else +{ + +} + +@code { + private bool showPdfViewer = false; +} +``` + +[See demo here.](https://demos.blazorbootstrap.com/pdf-viewer#prompt-for-password) From b91de61f0536ba7a3a5f61f0b3f857434d472b3e Mon Sep 17 00:00:00 2001 From: Vikram Reddy Date: Thu, 30 Oct 2025 19:45:56 +0530 Subject: [PATCH 7/7] Update PDF Viewer docs with examples and image URLs Updated `` tags in the documentation to include valid GitHub-hosted URLs. Added examples for handling password-protected PDFs in the `` component, including setting the `Password` parameter and prompting users for a password. Enhanced `alt` attributes for better visual representation of features. NOTE: This commit message is auto-generated using GitHub Copilot. --- docs/docs/05-components/pdf-viewer.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/05-components/pdf-viewer.mdx b/docs/docs/05-components/pdf-viewer.mdx index a51d4cae0..38a27f9a9 100644 --- a/docs/docs/05-components/pdf-viewer.mdx +++ b/docs/docs/05-components/pdf-viewer.mdx @@ -155,7 +155,7 @@ Below screenshot is added for demo purposes only. For additional info, refer to To open a password-protected PDF document, set the Password parameter to the required password. -Blazor Bootstrap: Blazor PDF Viewer Component - Password protected +Blazor Bootstrap: Blazor PDF Viewer Component - Password protected ```cshtml {} showLineNumbers Password paramet If the Password parameter is not set and the PDF document is password-protected, the PDF Viewer component will prompt the user to enter the password. In the following example, the PDF Viewer prompts the user to enter the password for the protected PDF document. Enter 12345 as the password to view the document. -Blazor Bootstrap: Blazor PDF Viewer Component - Prompt for password +Blazor Bootstrap: Blazor PDF Viewer Component - Prompt for password ```cshtml {} showLineNumbers @if (showPdfViewer)