From cfc2f36f5c00f17317fe68e1fc74be4566d1767a Mon Sep 17 00:00:00 2001 From: "chris.greening" Date: Tue, 16 May 2017 12:01:03 +0100 Subject: [PATCH] Adds additional parameter so background color of canvas can be set --- src/display/api.js | 12 +- src/display/canvas.js | 6 +- test/pdfs/.gitignore | 1 + test/pdfs/transparent.pdf | 276 ++++++++++++++++++++++++++++++++++++++ test/unit/api_spec.js | 24 +--- test/unit/custom_spec.js | 110 +++++++++++++++ test/unit/jasmine-boot.js | 3 +- test/unit/test_utils.js | 24 +++- 8 files changed, 429 insertions(+), 27 deletions(-) create mode 100644 test/pdfs/transparent.pdf create mode 100644 test/unit/custom_spec.js diff --git a/src/display/api.js b/src/display/api.js index dc256148c..701203883 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -717,6 +717,11 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() { * @property {Object} canvasFactory - (optional) The factory that will be used * when creating canvases. The default value is * {DOMCanvasFactory}. + * @property {Object} background - (optional) Background to use for the canvas. + * Can use any valid canvas.fillStyle: A DOMString parsed as + * CSS value, a CanvasGradient object (a linear or + * radial gradient) or a CanvasPattern object (a repetitive + * image). The default value is 'rgb(255,255,255)'. */ /** @@ -2128,7 +2133,12 @@ var InternalRenderTask = (function InternalRenderTaskClosure() { this.objs, this.canvasFactory, params.imageLayer); - this.gfx.beginDrawing(params.transform, params.viewport, transparency); + this.gfx.beginDrawing({ + transform: params.transform, + viewport: params.viewport, + transparency, + background: params.background, + }); this.operatorListIdx = 0; this.graphicsReady = true; if (this.graphicsReadyCallback) { diff --git a/src/display/canvas.js b/src/display/canvas.js index 800df9eaa..6093e6822 100644 --- a/src/display/canvas.js +++ b/src/display/canvas.js @@ -705,8 +705,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { CanvasGraphics.prototype = { - beginDrawing: function CanvasGraphics_beginDrawing(transform, viewport, - transparency) { + beginDrawing({ transform, viewport, transparency, + background = null, }) { // For pdfs that use blend modes we have to clear the canvas else certain // blend modes can look wrong since we'd be blending with a white // backdrop. The problem with a transparent backdrop though is we then @@ -716,7 +716,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { var height = this.ctx.canvas.height; this.ctx.save(); - this.ctx.fillStyle = 'rgb(255, 255, 255)'; + this.ctx.fillStyle = background || 'rgb(255, 255, 255)'; this.ctx.fillRect(0, 0, width, height); this.ctx.restore(); diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index 60a986a9e..64926f486 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -280,3 +280,4 @@ !issue7878.pdf !font_ascent_descent.pdf !issue8097_reduced.pdf +!transparent.pdf diff --git a/test/pdfs/transparent.pdf b/test/pdfs/transparent.pdf new file mode 100644 index 000000000..f8e5d7aeb --- /dev/null +++ b/test/pdfs/transparent.pdf @@ -0,0 +1,276 @@ +%PDF-1.5 % +8 0 obj <>/OCGs[13 0 R 29 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 12 0 obj <>stream + + + + + 2016-05-02T12:31:35Z + Adobe InDesign CC 2015 (Macintosh) + 2016-05-03T12:20:44+01:00 + 2016-05-03T12:20:44+01:00 + + + + 256 + 256 + JPEG + /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7 FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq 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 dirsVdirsVdirsVf/9k= + + + + Mac OS X 10.11.4 Quartz PDFContext + 1 + False + False + + 200.000000 + 200.000000 + Points + + + + Cyan + Magenta + Yellow + Black + + + + + + Default Swatch Group + 0 + + + + application/pdf + proof:pdf + uuid:19e521e5-bfc2-a34c-9c8c-b2cc6216c7da + uuid:3e555664-3dbd-494b-9d14-9443fd4b6b80 + + + + + + + + + + + + + + + + + + + + + + + + + endstream endobj 3 0 obj <> endobj 2 0 obj <>/Resources<>/Properties<>>>/Rotate 0/Thumb 34 0 R/TrimBox[0.0 0.0 200.0 200.0]/Type/Page>> endobj 31 0 obj <>stream +HWn5OvJ@Vq".KT>O2Cap5nrwã3|hχ3q8[q/E|b~?ə:>oƛlLxyɜQt+P >m ٘y:m>g+./67+w2CNβVKN!ּZ Cc 6f:o"cj6#ȒDmjl +r.ahܨ- J JlVq^q-咦犰d QHnG}\cCDQax_$[C,Cp4.w!dD#޲6ꑥ)"Z4Gy), x2E|`CNmhl%⋊yBMn+=X; Y: b~aU +*V}ȑ!:ctWgFTӕR[ϤؕNܝ#I +*k%oޡs J;EDTHK@񧰂A +L=k(2B} U53UUM~ZkT<޻Z)&@ Pb_ڂrΕJ;ەߵ(_i72Ib8\TBӔIS'4VGWJ dw׵GlsR /xfdڅ93T: RaM#0w~olfhs{Y׾hoiw endstream endobj 34 0 obj <>stream +8;Xp,SJFJ[;&d+M]/Da-3Z)l%?m+,4#&Qi2ip8X@#HHBf^nHCO6lh4GF>2]o($Ra` +c6't+J,fZOe#CO.~> endstream endobj 35 0 obj [/Indexed/DeviceRGB 255 36 0 R] endobj 36 0 obj <>stream +8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0 +b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup` +E1r!/,*0[*9.aFIR2&b-C#soRZ7Dl%MLY\.?d>Mn +6%Q2oYfNRF$$+ON<+]RUJmC0InDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j$XKrcYp0n+Xl_nU*O( +l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 29 0 obj <> endobj 37 0 obj [/View/Design] endobj 38 0 obj <>>> endobj 33 0 obj <> endobj 32 0 obj <> endobj 39 0 obj <> endobj 40 0 obj <>stream +%!PS-Adobe-3.0 %%Creator: Adobe Illustrator(R) 17.0 %%AI8_CreatorVersion: 19.2.1 %%For: (chris) () %%Title: (wine_bottle.pdf) %%CreationDate: 03/05/2016 12:20 %%Canvassize: 16383 %%BoundingBox: -86 -86 115 115 %%HiResBoundingBox: -85.8269996643066 -85.8269996643066 114.173000335693 114.173000335693 %%DocumentProcessColors: Cyan Magenta Yellow Black %AI5_FileFormat 13.0 %AI12_BuildNumber: 147 %AI3_ColorUsage: Color %AI7_ImageSettings: 0 %%CMYKProcessColor: 1 1 1 1 ([Registration]) %AI3_Cropmarks: -85.8269996643066 -85.8269996643066 114.173000335693 114.173000335693 %AI3_TemplateBox: 13.5 14.5 13.5 14.5 %AI3_TileBox: -265.326999664307 -365.826999664307 293.673000335693 417.173000335693 %AI3_DocumentPreview: None %AI5_ArtSize: 14400 14400 %AI5_RulerUnits: 2 %AI9_ColorModel: 2 %AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 %AI5_TargetResolution: 800 %AI5_NumLayers: 1 %AI17_Begin_Content_if_version_gt:17 1 %AI9_OpenToView: -1258 665 1 2568 1362 26 0 0 -5 38 0 0 0 1 1 0 1 1 0 1 %AI17_Alternate_Content %AI9_OpenToView: -1258 665 1 2568 1362 26 0 0 -5 38 0 0 0 1 1 0 1 1 0 1 %AI17_End_Versioned_Content %AI5_OpenViewLayers: 7 %%PageOrigin:-292 -382 %AI7_GridSettings: 72 8 72 8 1 0 0.800000011920929 0.800000011920929 0.800000011920929 0.899999976158142 0.899999976158142 0.899999976158142 %AI9_Flatten: 1 %AI12_CMSettings: 00.MS %%EndComments endstream endobj 41 0 obj <>stream +%%BoundingBox: -86 -86 115 115 %%HiResBoundingBox: -85.8269996643066 -85.8269996643066 114.173000335693 114.173000335693 %AI7_Thumbnail: 128 128 8 %%BeginData: 6254 Hex Bytes %0000330000660000990000CC0033000033330033660033990033CC0033FF %0066000066330066660066990066CC0066FF009900009933009966009999 %0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 %00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 %3333663333993333CC3333FF3366003366333366663366993366CC3366FF %3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 %33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 %6600666600996600CC6600FF6633006633336633666633996633CC6633FF %6666006666336666666666996666CC6666FF669900669933669966669999 %6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 %66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF %9933009933339933669933999933CC9933FF996600996633996666996699 %9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 %99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF %CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 %CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 %CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF %CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC %FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 %FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 %FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 %000011111111220000002200000022222222440000004400000044444444 %550000005500000055555555770000007700000077777777880000008800 %000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB %DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF %00FF0000FFFFFF0000FF00FFFFFF00FFFFFF %524C45FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFF %FDDFFF7D002705270527052727FD76FF52050027052700270027FD76FF53 %F827F8270027F82727FD76FF52270527002705270028FD76FF53F8270027 %F827000527FD76FF7D270527052705270052FD76FF7DF8270027F8270005 %27FD76FF7D270027052700270052FD76FF7DF805F8270027F80527FD76FF %7D270027052705270052FD76FF7DF827F8270027F80527FD76FF53270527 %00270527F852FD76FF7DF8270027F827000527FD76FF5327052705270527 %0052FD76FF7DF8270027F827000527FD76FF53050027052700270028FD76 %FF7DF827F8270027F80527FD76FF53270027052705270052FD76FF7DF827 %F8270027F82727FD76FF52270527002705270028FD76FF52F8270027F827 %000500FD76FF27270527052705270027A8FD75FF27F8270027F8270027F8 %7DFD74FFA80527002705270027050552FD74FF52050027F8270027F827F8 %27FD74FF520027052705270527052727FD74FF05270027F8270027F82700 %057DFD72FF7D27002705270027052700270052FD72FF52F827F8270027F8 %270027F80527FD72FF27270527052705270527052705277DFD70FF7D2700 %27F8270027F8270027F827F852FD70FF53F8270527002705270027052700 %2727FD70FF2705F8270027F8270027F8270027F8057DFD6EFF7D27002705 %27052705270527052705270052FD6EFF52F827F8270027F8270027F82700 %27F82727FD6EFF2727052700270527002705270027052700277DFD6CFF7D %05F8270027F8270027F8270027F8270027F852FD6CFF7DF8270527052705 %270527052705270527052727FD6CFF2705F8270027F8270027F8270027F8 %270027F8277EFD6AFFA827052700270527002705270027052700270527F8 %7DFD6AFF7DF8270027F8270027F8270027F8270027F827000527FD6AFF52 %270527052705270527052705270527052705270028FD6AFF27F8270027F8 %270027F8270027F8270027F8270027F8A8FD69FF27270027052700270527 %00270527002705270027050552FD68FF52050027F8270027F8270027F827 %0027F8270027F827F852FD68FF7D00270527052705270527052705270527 %05270527052727FD68FF27050027F8270027F8270027F8270027F8270027 %F8270027A8FD67FF27002705270027052700270527002705270027052700 %27007DFD67FF0005F8270027F8270027F8270027F8270027F8270027F805 %52FD66FF7E2700270527052705270527052705270527052705270527007D %FD66FF7DF827F8270027F8270027F8270027F8270027F8270027F80528FD %66FF7D2705270027052700270527002705270027052700270527F852FD66 %FF7DF8270027F8270027F8270027F8270027F8270027F827000527FD66FF %7D27052705270527052705270527052705270527052705270052FD66FF7D %F8270027F8270027F8270027F8270027F8270027F827000527FD66FF7D27 %002705270027052700270527002705270027052700270052FD66FF7DF805 %F8270027F8270027F8270027F8270027F8270027F80527FD66FF7D270027 %05270527052705270527052705270527052705270052FD66FF7DF827F827 %0027F8270027F8270027F8270027F8270027F80527FD66FF7D2705270027 %052700270527002705270027052700270527F852FD66FF7DF8270027F827 %0027F8270027F8270027F8270027F827000527FD66FF7D27052705270527 %052705270527052705270527052705270052FD66FF7DF8270027F8270027 %F8270027F8270027F8270027F827000527FD66FF7D270027052700270527 %00270527002705270027052700270052FD66FF7DF805F8270027F8270027 %F8270027F8270027F8270027F80527FD66FF7D2700270527052705270527 %0527052705270527052705270052FD66FF7DF827F8270027F8270027F827 %0027F8270027F8270027F80527FD66FF7D27052700270527002705270027 %05270027052700270527F852FD66FF7DF8270027F8270027F8270027F827 %0027F8270027F827000527FD66FF7D270527052705270527052705270527 %05270527052705270052FD66FF7DF8270027F8270027F8270027F8270027 %F8270027F827000527FD66FF7D2700270527002705270027052700270527 %0027052700270052FD66FF7DF805F8270027F8270027F8270027F8270027 %F8270027F80527FD66FF7D27002705270527052705270527052705270527 %052705270052FD66FF7DF827F8270027F8270027F8270027F8270027F827 %0027F80527FD66FF7D270527002705270027052700270527002705270027 %0527F852FD66FF7DF8270027F8270027F8270027F8270027F8270027F827 %000527FD66FF7D2705270527052705270527052705270527052705270527 %0052FD66FF7DF8270027F8270027F8270027F8270027F8270027F8270005 %27FD66FF7D27002705270027052700270527002705270027052700270052 %FD66FF7DF805F8270027F8270027F8270027F8270027F8270027F80527FD %66FF7D27002705270527052705270527052705270527052705270052FD66 %FF7DF827F8270027F8270027F8270027F8270027F8270027F80527FD66FF %7D2705270027052700270527002705270027052700270527F852FD66FF7D %F8270027F8270027F8270027F8270027F8270027F827000527FD66FF7D27 %052705270527052705270527052705270527052705270052FD66FF7DF827 %0027F8270027F8270027F8270027F8270027F827000527FD66FF7D270027 %05270027052700270527002705270027052700270052FD66FF7DF805F827 %0027F8270027F8270027F8270027F8270027F80527FD66FF7D2700270527 %0527052705270527052705270527052705270052FD66FF7DF827F8270027 %F8270027F8270027F8270027F8270027F80527FD66FF7D27052700270527 %00270527002705270027052700270527F852FD66FFA8F8270027F8270027 %F8270027F8270027F8270027F827000052FD67FF590027F8270527002705 %2700270527002705270027002727FD69FF7D525227282727002700270027 %002705272728287D53FD72FFFD05A8FDFCFFFDFCFFFDFCFFFDFCFFFDFCFF %FDFCFFFDD5FFFF %%EndData endstream endobj 42 0 obj <>stream +HWn:;p"jG,YJ9I6NAKZ(ʉXc[q7?v?v:jys,)QB"CEgg7Gױ@ *S&C<է;}k8x"K<}FytaƩ3Q5)#~!" 9ʉ \)UPegT_jeM{#F zbxxq/ W ōqmG1DOFgh+PrRh\t=:\Ck(#Ef{%m6$ܷ Y鞍?ASJ`~zv}ܵP@8Rf_\pXtեz B r1ywÁY%(Ёdl]? XȒV{CCP 0I @גϕLd+9 ^aqC#R=y#Jj7螪)hAvXH,M =9}<\$5\n7ހʻ2sHP R"E3)Pc5PD\B4 +;\Z=i l*IrBt$] +g:ϰF.Iv羬,EuUgEGAʌs6iP@=* Eb6%t2BNGTѭJ'4ʘND/htGj0KQkv#ۯ J-8M[ct3d\}GdFrHK ]boVc|l;>/O = l 嫅" *9j] ^o,tr@8\X16mڦSRRb$WۚF[rGA' gf|P>C: u4\ϟ//a~=x 6tdLQjѾ5^$sAd*P ݁8ωLA= JYMO7\XaIF'"QȔo_ׯ ]07 ^.Kg$H4 M +gVF?7nu- TNW){ŚO 2Kۇ_6~6H9 Yl[:R7"u$NQ6k2)*u cy.o֢[v ʑ[ܘ9UWdk#ɐ,^}MQE"X׎;W$lFFc&vq [Be.T(zRi" +^)Q:9*f$B"-wgJ!I/Z c) +9e96}p@X 3NeJ',M8Y\Yחj"~[|ˈ Âua _an1p R=4\{D]?IYZyBoIz%& eny!/;2Mɢ1B)Bސw=#zp L-F2Y`Fksq`aHjo>2Jlnc?^VVE{ ǔϲ>h(b^]½,c28bJrsm:VEe˲]^W^}yUj犲pg"$FeK$q$*J H}?Wb)Dф8 +"+D(! `,ӣM JJNs],|hV9SɞQ:&񜤣*Ex%IS*]GGLQօ-t Q%`,Bl'RSUټrB=O':",/4b )KSu7a@#Vsj[H_{LԴ r*S 3vͺsO32h pЁmӌ 8ymWelҏgEei/cUBªVS~}EEuUϚ׽:lfSlM߅ꛂ y0Y2h>0Z2N6$C;w3f\SIҬϘ+PBd՞c +.#D+lݰPw H8ӎO;쐸K=Iu8q۾.;)[ڳ3ҏ$4!s+K4sCJ CLJs&5XRΎ4΁x/ۓ=dŭ}cL8&{bzUmiTRs? Jza%;\_Gj$>)Rސ5J3͜ⱺ̢UI/KF}(uz5c#X6{ɘԜ2W'z]tfvYVmSVɊú|_)Tu7@1RaQ2~"Z$ZCKJV+^ɹEi +*M /OĨl)0W\C|=.H%ҟQq,?m=46<#1%bpJ³~q;o-Bc}7GHL#|TS8X͕zx&kb[jNưVYLdJ|^1iؤ4a4[fh,Bx]~h's Z=2yޕa]1ziuiRO Od2͡?`ڭSX3CK,Bt0z;(՚d8w"JtQ,;c7O27j[ գea.ޱj}&+/B7Y}$so1>8 +?>܇@] +?5}2i?!3mn3ńJ(s|7>7@V5d=o FMTctĵ'<]FfL}z`m͇l' П0bhq1߯/7Uğ ecWd{~**G V΂ ]Ǿ@a2f@W-ЍI1'y:uwJkۑKDUmQ*P +Fs%FFJju;bȒD32aG,jp'2񨞨K;e*הhؿ/ GA|1;oFW*h;CgB?`T?;> \lYsѠoRܝ-NY0G"o v{o)Hxod{Y}&W {Ǔշkb M +dŦklT[&疰T#*Ymtj g7 h{)}D|ks`rrj,e~ymz mQݿB4&#D)Ε +` ~kL\u4׬?&[VtgW0p`b}/~'G{u.''C@ DPB,#Q@0;tҥ/]!ۙysdgLG dJBa\} +i\P^[Ӎ4~:WeȄZ^ًOR"=dUg>%:5*ϩ7dDQ2=Wwo&S&؞FlM\Oi;C=9\R*@Π}KKż$Br2Lt&sNev.!!TUujy?͙`|%|Fa| !oǠ*o0`Tn ^AJvp&إmOϩuROaK?uoi~9b͒~s(=y`ECTY=vkly>^H`^t!|7^Ƽy.UTz +~ AdJ6~ۑ_N$mr|1gm}Q> OFq$d6Z/57eQ@r~ZL`S[GJ* +u:}3*{9FZ*%w6dl#LAIae(yc!>_V yl=FsL<|-k6\_9 wώAp’t,%RPFE' ɯ2IMFN5ůG +t;Rᶵ} .ȎV]Ca1sk {ާMDDUdH\WIQ`lƪd(dI\Rqɯ[D1XNPJ\ӭmٯ 9'νLsF6ƹ56a>CABZbiC+>D-#%NDQ NnEHԟ_$. hc#apU.;\H5}Zཐs~,(m] +>4l +[y 3y=V$i?Wَ$@{AƐҰ2Sz}Ϟv䕃9}AՕM͏+`|-NIo[2/hܖySXD;rb"K5 }$W%SCPD-<D@ɁOeb FԔ+ӆ-D)<6([,>@O3ڙD'#> +|Yd""Y -xO3%˹*YqpoDhYEX$u WT| ʟ=S <:8>Vd)S BgᒟsA?U ņ$yv\J[5ׄEۿ_Rt<;^2 c vߐ80'6R?UMJ hdy f-geH)DUGJݛ܄հZtA99/1m=Ⱦ4MaW_mEnxxZ2<K"cXSf9VBQ{3W0'ZߧX5$Mnr]3r?Sz +=vV"[2׭{/0-Zl:jW DᅽsL GT܈< **td;zJvo rf@|> 3P z7`49rUoj霐-szlsiW¯PLk&?.F)T!NS!)XX=,"+ S7TA1HP4ֱ"˦nhh&)hcIPD44 O)w74YF~l0`cXQAY!%Y2!r-%Z3s1Ƽ$e +hBѽťPtiHWd W1c2c$u۰ Ru_g = + @M_tB +4ܖZ0eK"P~B$遬*Xf@9N"?$PwթHڼ.kB-MZ.3#e'Eь? +`)wa(HDoX{>̪+{4 4 5M@iD0 ~"Q2Ժӎʫ 2:hc  b7PP(9aX"!QНr +lPҿV4[?Ȓ~PްR%ҨP}Ma4`2"@<*gsqߐp7bMOi-ݬc]5&1o]}@O'*stxy1؜gꮈDBq=iD`W1)ő#niWyk˓Va׬V1/X@'uѸ#?/Ca7hl86ǭ]ǓY{`øY`k顠(c()a!3Cߤ4yLmn(^'Q# +(Q5{9Q +&B(dm- `B +Q! J2ey83(^UmMaF̫`]ijl4 I2:ets u~}4I= "XY=G4JǓo`?ekUD9"VU$Z!"j<ydYỽM>^)xV#| Gy }܂Y:an~!/_YTQ Zk{耷Ό07Ꮓ/ myv,g N^44b3'\8WDžÛ~Ip:vx͛W}b~ۂ: +zDU0Gn_|"c~ZT0-O~\hZ63f|]>gt#N{lk3LF^1qD 5휦Eΰ' WnĨ#eK5Ϧk_ʃ!/F6Y>[;rIw \lȕu.]D)t{V¿%/{ʍ"'@iu'x +n7A+iU:3az%:hDi4>С6͚@W$J+ :k@g8 vg%*(VC5G5: ́ ZjBAm?( Pl@o.?JAkAW{:Hak;iu1Q@M|G kuGTй]Q@.K +j|,l#x4ꍩYZ_-5fՎ[ev׈4_Ƞ羨BuqHn<aлw3z745N)ʾ oa\_(qKaOA+4K3?Kz5Y<rM:Mh[P )R$ADDtzJ,_FiڴzNp8k[bo84̐.aoԽqlBkROw;|7<,?^$#vz/<&?p]=Nso7j{o?"~|9NPN[K_Q'^!").!hBP#w%4OϫnilN] M#TȧFheN>\Zujy;-Nہjא+^Lz4,g۬ބ|v ]o|! sj|V>{a?5Ox,ujǿ<`кZY]tSN)zqٹcsAc~ڱ"F=:0 @SaB;עa|Q@_L@6nK +@hv:?:zjËjmlOdh$=,HEnS FGz^dLuUWS:OFy3eS{d k7I3+?!'1Z\GPɋ)@aX~z |+UZ`syP? Wb,0.ܩͱ^:ULi?ݬn5oii ^ +:39#ʃȚHǚXqυg,d(,_67J}b'qCҶW9AGſCCCq_nnIFR,ÊJMwǰGS3E/g +tu_WVWr%+}7; VejsR<)J^SOhuB=}nރlHЍ +dz|nTs{=!C]&NzRO䮔kYZ\ ]fȝYK#+G?-b2 rnVHm73Oil +V/{Q/^x 듾{76|&u=`/e\I^JYL +!WEN'>+rmpĮr^d,toА]´Sݜdߚ8sO1UoGLD͈+F-ENS4uOX`_&FAB6JUs4I2Zl ŅpYh~}-$<6w~2~6uIW}>PұeoM"fq-Z vnĢܽ2ưވJBFuic-qkAo&hFBdczM +󗺲zGeQ2İTX}ut!K)Pi4[fc+4 `P°arCQdڑ6׈OݒyJ)QDb~g^,04=y}9ΡZفo|Fa&]v by>xH_R0lt2?^Y^_o.jҲ!y6b`e`[@ufcWc[c>;v@XEVu.,D}⹜Wt=iU<wA$BǛYҵDr(<#*.8 +"؎$VRjsˣ_]/Tfd7\i{RK֡fd1_^i_p]30R;\iرsL<uWj])P;aE\+fU l8q5n5p}?PlY{2{5{t&AX ٟ}!;*MM>E;I Pa}6\ ϱa.`l(2\ ӘJLWx?w.B% ()CH&CŎJЖ1"ئ\=e;鰾^TTf +DC[ ^fZjrGZD9ZB*wp+ZKFy=J/ߜJіڰchX]1vdjynC$CO.'R5yOn"L/LA1!@ ŃK [9 +`<-.od\r˕Scs*_W~ȕNxP]tJ16Q)bx=ucOO6d}w/Ojsho|1*/9F8 J]]ExB; _ooԼNBs o~ƭ43N]84Q8/m9>Y8FO)/>tXKM[j8kmV?i4s1.O +|~fz$v A_)F)&*NtkL^ SΩa6;-Vzgc)R[]Eճ&9)~w&Nc1̨d1lib5"Ore \R3Šĭk@md^!"g/U("j'FZsTR&ԧK6گzH0$V d_N[ӱ/ +*uIyXz :S'<3I akfpʏFa3G‹r *uJ~6sV'?f[fdʮy,#_ξjݧm]YJRvYA9Óϫ?&v4SIܴ{6rsmf>hUNL'4de 9 *Ԯi+3%9&+ϗܖ0oTzIWpgcHϩ'!aw+5v?eNl-@3zN)$ ,|`9=r~ZOo2V>C,ebܖ;ʉmxM~q QkkNR\UNy9b1Y +iB⥴a࠸}Ot['B% MؿSbjdՋ\1 c}&k^0ư!+9%.VNvt쌅I,Fi}NN{r莣7p+tC:|^Ys_7B-L`.^vB$qWU9 :A3f=;cڊ u~D=7P* G`&ph\r@uFfrY@I,yL>7Ð4 tP3{i<ږPo0 MejAD&Ez;u|x R]˄ +K!n=ue9qabV'¯"ޑ~Nw08 +Tκ-pmrD{q'g6eNM;KDN6c}g u m[ ɺh'c4N&v"*YٺֹdZU!c1)}X ṙ1-1r3 32|h!c082eFsX_*?ɣ f\ַ@|ofK#/B/?UTRM[Rl}QWR{9AdW3ۊF+vd2^-W ;WקHPLKfo Y-GB2ð<*Zp0CnŇ8 )9=KqG}G@ _ĎM +Yw@.Dx)퉱%mFД~W2658?QAz⟔tsFBykj/-)s:2AA8Tn,Yoxb=w:4wT>HFË ;Pb+=/ee䷘Ԏy)Ab*@- ؐ޺O7Mon2BbD#jop؆!zg SDy W `t)sY (G/,%2Y겑TfrH{ 1@DG] ,%D&BI +AKh%\LDR/]Υp +cwoa}9cߠ׫/ir2Jv0p>wהx2q%m21r(0 h($D7p"PvBO~3;#oN3z;C3Rj?8#{gdq:dGxX'rN~ś'D^,ΝXzNݕn*h\I+<^PZQisW,>stream +HWZH}<@ aFpF! &$ݡrԩv']RM{U)E$m#I㬖Mt6˗/KZcԭh#Y+)-?I8V^Wq.yFH )ҕ]ɾNj1]*|n+?tPCv`xp>q<6(R]jx)y`PݐNh!ļʊbuڪ3-R\;ۏ,#u?1y 1P)3+[,Z?Iw3Hk,eL|ޘ_X3CH\/鶉_SrdzM>Mܞg=Ew:e3($`@wLF(;v 2 nM8/>BD~NU9pO + +e y >qm2՟X!D]XTccT8Q< sQA`SɄH $$nצ9ABWhAcц^&e(1ÿM1"mA FIi3 e2I^XBD`⌧.`P yYd$.p*;mL%Wd O_Ѡ!-&(Y‡%8 T܆aN o2Y6oPqlzCŽ_x1J|c('. J㳒bn[lCc|AjzrԀ׻M]~3+'3$X[m yz쭩='?9aT%L5 Hݎ+ SJ$:c;}.f\\A՗bі{rP0 :vNՅ5Z~ѽKI1^HhfJnXbG(h@jI&BZDHnp?5X: &NW +.a 0]s B_q+Rn-:c:Zd4LV0?Uh|r40gɛMjxsOJĻגX!+v¬<|jwN?8ƶj˖,c&Ӊ{ r$0Ɫg H> [ acHw;;"3lw1zGP?$9"5I~{JFfL^ݬNx@|&u ^(%Aʊ + ޳ߟ+ Pz9Y*:v{[Pd|h@.99܎ZQ1s ,{=vq*CC"82U{!f +a8ca7RPcHWp!puc'x }Vv"+ai1V)43 Ø#IoD&g=҈2$ww_0#|!vy ;Me0E:cPGc~E'PLEჿHt"+\ I3XڕwrJ,! kU/tZFѕ(X;G6 +}Ooq C0Oo o=B 6%g q80s2>|(qb>cߠ0 nqQ\&}*TD+;+Km2JN**ڦ.øA*t0H_)00U^a1Ϳ! +L<*@0BP}6))I"^L̺cJ+h132?Z瘆a0w f?A-cSd8; `Hrt~s*pn/U\#XFAD}i$OQk*|fB-]‡2 +7auis +;9f$62Yl=eOh{ASur9{p +̽tpZ~znNS;ZBϿNzs4J}rHyZX B#>wR\VPJfyG)gt]Fj^HRFCg~PͺA*a.M1[Ss Ow2r*%v hO MP?(?": )I +T5s5CgD\(]]&N_rJ0x+{L%P{ѵ@], ̻~$fEOwIM ެĹ6$PBCٺ| *Ɋޕ7[> + +Z I%QZ60 XKc_qc4|;*d,0 kzqǟ)|L&5EY?ȊF`*7&=IOd GG̑Kfvw[B[ +/Nx1Wnώ׾`#|eTEl ,@5+%5 +=E) I~vI2KW K˘~Pi$Bw<1}O6 +1k2F2ڞו=.Te}×>,`P5;<= 41+qc@Ĭ/`48{>NszVeٷ+9'DBrs(ف䲭4@&l炫dl;USI ϒ R) \Tnor벓P^4 <G1\YꩬԖ~to|Uf/ PVHLSؕD:= d~ &bO8i'Y@ĉ8LsU!/ڊ)'|!9u5X +UfH`P_ORƉ)"!aB5ϯ76y垬+wS}\OJ+IjB[6FxQI'@"ք*]HOC`"(K疒Tfeen@D?#ȝ9gvmN+©k>[Ržݞy5v iM'I;pUB-ˡwr bM(.1 і=*?ʑ#K{ִ @ Q?w(};-wѩ 3&} +"w `E$;A_R)c \DTgfTzwt}VkB]PrΧq,'[7ҤBC_HXL_TݫqW"HǞs'X?N+(Vr&_DNs _ դ,d{ ]Vc8¥5QtZQ<;M8D?a`Μ^p tǔCi҉`>G'reJZ-%7_cz&]޾8nde~Cs;wa@|ex)4Z%Zo)~+ݭב_<:PdۍɊr(ǰJyi6XXcowWi@⭊ +ͰUK~Pcno|a.I~}A| iߢ;D}àGk 4j6h:\V"ZV,j; +9׎KfnbX rn~dmlVk9>?l?ws1xgW11I n|T:n6} (y 5ŽW)wG|wo]яHf/X$TB3plh2Ujt٘ϑBL%/OeT>WGKjϏ(k"Q +VY +)'c7S.MFqz|Xl1}=c%ad"ЖL5Aɠ#b_x]f)Url8N$,ܔsI d>lk=gWY%j8CMYS22NeO@1`W]i58 DE~##Υ)7F F> !zd1z2L ~f/ {ްxZ&ЊOX{g>_yjV%(yٗ3*2F D'$ȱ+tfu_aWZ\9@`Zh=z:^`b2];Ә#&y/k#5BP'>)MPH'\ᅍB?2p2*pD #M/{S; Av?m-!RNfع 5ϲxX..vIaz}T%t)ƚpLo1,SL=Z[_B&_}b? ކjπ Vm#9yVř34UƵFPTZCĶn`MOq3͗ ,-&ؑKЫnij3DCz>%{cOu"mk+'N[m6s} [-&R4-9{31agK^sя$5:yӴbu~לXaMa!.zfUЕtKiTfÊ**ؾ@2O^R}of]OӥlݦU39ƍ\ f66jMbZGͺL@\#tG,G 't`fP2`K :~olvD{ˑxElSԦgs_}GSae^'ﯨo.hSwd5_@_N*LAHdVv[=ab,P5LF/ +Bq +B0ARYxgr*u;jLB=ɦy<yc:X;c{ͱud̰Ø)#k7 +Oc79]v?䒋;?3QzRheOz_ pZ +v=O~R6ܤ=s^H IauDAcy^N>[vtɦW:QM,Vת5Qm2O^R}` x9GQjnk<TQq3>o#]|ߣ^KGլ~ۡ&pZBI1Ds dJ-&R4-9{31a4) Kjq}XR*gLOF:QqPII$z׍wMElǗ 5hA)qXiP%'ESP$>B8U'imSZ!Ć/5JrNPNtЄ+ f kބ@vՃACSwS0`{; uSf8TX 2yy6YB8zVa=/&fX 7cۄ#l>GmR1[D5AlRJDmF>Igcbv>~1{;?Q?^b &/ Ba9b_5/A9z +% vBCvsN"YO+ 2p'J畠LViZݑ$N067 vL6AT\t$(/aE5ꛬݧ'zϩ(aR3xuH/Sy bz *Ȝ&^ٙ8]gua&މ1O]_…^H|gn:.v_{AYTSx}yNÉ|%װL%IP^[3 +@HB$@d2" +2\$ہwV'kx$t<| <-臬pZ /=CO䰚ܞU&{0b tME, xgl J90xϒp(J]ynjBӡKS(Уq1 F 8/.wLa߃C=fZ*ʣ- <Z}+`l鹪\W6*LpnˣK.^$qEߡ21/}_P%l+OH$D2z/޲5CQY~G.QaB*دϊdž,bd+ŽafK-?'!@{ Au2? p +qy.bQ cj+xgӉR]aWA>g)ȗXքcgG- { +=d&Gju03Mqʕ7) ½,F#ފWoTuгPP6aB^pB̅x6OkE P>ںv1P+= uXLeq%]\񪸝Ln'+ds˶Jsp(PnjsX5*W'IEb?R"ME>b DA|#fۼ3m^fۼT138Qn }Pȇ' 9yb={HԎz18\eѪXAry)ÚȦ7:W3.)J!WQ쿘.jQ.HVp5f6D!ڲ!r*{?;! 9뾕ʳow nP_%! /irXg0m>%dvqg!L ,܅ap!aAP(3vD? ^Car6 + :y(PoF򒣯8UEEo5t0[AN̈9G퀂EK5؞w!mE Eq gGgi +B}zs ;boA@U:/!0Ry\6 emkԊ+ lsi8<>Pv(iA gP\Br +PpZoTt'TW +1؞˪,1[_ݘ}#U,SU|ҝlH=ntV=/aeFl468tkFPoV|9ݍ v1CŊ>_Fc6tl|yzNNa-_|(}78 {7?:1@, +{eQB?<|Jkױ09V], +*p7k;Ud]$aI1m H/DƥoN:N䵱"|L$5٬STa|b\U3vTG0vڱ_s⍆Ѥfsk-r݆4Xp|fa|ۣ͂Ïd48N.&E0B%`(۳z' ˗GafW[ +;#o>e +[ jT8[ zӬ)G<-x +7CูTa!LHi0^ဵ,J(~tČJƥ{`4 ($9? +P%C4lb!Z{.=H X`ޝy֍(H_L(Wki!(iMP?P/呦 6 q#}B V/X#}o&e`rT)ʀ{Gc3,GNx +AXρ*g_^pEڃ(rD4 +#_@_?eVErDOpd7,2vWq,QPQO>{~3`Ӿ^`tuթSw>6dl}מL9wwcOnoko8}y~8x7mT:+#f+nޞ-]֋/޼~CwU/<nuW=֭ͭՎ6#=} w_foٖ%']g8\٤b!CIc.pf-//GgM{uugVl1If^5@!&mvQUzS)Gu} حG魵>{n[}qgyڦVKΧwg73xkb\C6fI%> KE;{So $BRbkSjGB9G%h59\LFrQP/ 8o\:FrgФGSDM싖Cܩsg+$@b'Pb 9c'A3 u8 !wxetbIfT6GX%DĊK,^J|ɤ\=ԋ>Mj2Y cv@jbD˰X&$ u|G +D$Y[p&I!XP19G9 S`S Lc ۙը!c E.@kRR/QKct6l(<V&{Vڎc)4 X&Pt^PbS 2RAd͵ T l[ΐ焾Hhz4X5XlȖ;mB@mroEO"I'gF&U9"cuA$} i8@l\bNDu}ň϶tJbFsDq1`bV )|s}uB푺^DЅITP1Ilˉc mdBgAjteKȜWy2(enLIWf:4>LT hJ\yb&"=pK}PG![’mgC>!UAv6) vmAH(];cd.8d``kQaܐHRDXs Hxu#zzdc(1xd"T2T3Ƥ2=EԼK1T8.Fk{BD͌wV˜R {Ŋ)S`xEVci b(脌/JRD:@8 sLĒs`1Wb6nJZj +-lrpCP%AhC'E #ax F3BDJC裭`,< Q;"x^,z(_E`1f̶B|KT-ə 5j=fJ68h"QRԾ;60p6ѯD4֙`0Ilu?d(Cj<FHyzB72`quy G%#! |Հ9lO> 3`4M` \SP> NBc ?jҠ +q1Yf҈"_ĘD!0+Lpy߮g?6sD૱q"[WapD1ANLQJE=E%e n!* C '=uB7%F_ҧ, nDK@t`TmZͥeƖ`F`(c0aQn[$A&kQKG"8±7х]Z2^V1jc@Ǻ VcI)ӬQAx$WAʿ@+uo}opH@UVVf M^B|}8\/U)'mtX_30Toc.>#y`]b(ʢĂM-@ݳYLC`Ԅ`Ml9uϲhރdLc6F]t'O~vy?kj]o0̌6&7Mk5̋86F$LtuYm:ݬIsfSO@dңYQzeu?Nts8v&8[wDENs$ QIxY b7mDxq=|v 0EWZvEwja;քKs̹'vV% [@=t_eiI.J5<7_V)VX`-ƉK2wLEU$Ye zn ۍhi9[ AKPz0F/gN!`𾜢䵗Wݫ'_? 1;=rYE$ǖ>m99Ӄ! +Fs.3:?!pbnȞc=hwOq:7v(8Ջj %{X:wٴhժܚύdRa}=S8Wc_q[u㥁=}C2TK5_girmQm .֞ٙ*d73*F2<7Ğ.㽍v[m(Į\BB3p k1#t󐴭/)64- +y-";y8^t5ꛨe7=k9x5-~wFP6W[,y<#$+L&kja&4;g[&@INĹd6!6aD Co"yvL@(Ɏ_j\)Vgؗf=>혞mf|zvZɒ=;:N_S:.z|"bvudʶKgZlaEH[mkıKFvG?kQ}_ﲭ79bҎ&sIeQRn1dc_i6\9'~A#4 r;JL%N6O'_l7fJ>b.W}JLU'VA6 e_-roj>@F,}>qb]s:!.ڎAp/@[b۾:&83\gwTG!1!ϻ~B,{ ',-l opn >~pRﵗ"rzס GEO t6yW F'*DC$aPHW/ UC]S>iatv_aa=]'MNWُ2OG,i'- +UQ}ZϔioT#-zKYѦs6ؖVc0[7K!ao̹:dya@UgWO 3h[z=GV&H~3UѸ6b-zp ḭpaefAc؛B{K{pPHxob؍! VMBOk"}t 8/pƣZ)nI9ؿME山b/e0 ';&fvT@ ; :aŷwyMO4k.w0v 1­Y-Va%fm>?يK +@[qPEƍ7u}+Tq."Vb +Fk+dvqR aJb:q x0f(U|-&S8|Ijf2肓Bu/8Ƕg|]T-3UENjɫګQ=)^;enwL21 9cLjga%,'zHq^|dW~ˍ>ԏ endstream endobj 13 0 obj <> endobj 21 0 obj [/View/Design] endobj 22 0 obj <>>> endobj 30 0 obj [29 0 R] endobj 44 0 obj <> endobj xref 0 45 0000000001 65535 f +0000000004 00000 f +0000010945 00000 n +0000010872 00000 n +0000000005 00000 f +0000000006 00000 f +0000000007 00000 f +0000000009 00000 f +0000000016 00000 n +0000000010 00000 f +0000000011 00000 f +0000000000 00000 f +0000000162 00000 n +0000055159 00000 n +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000055230 00000 n +0000055261 00000 n +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000013747 00000 n +0000055346 00000 n +0000011279 00000 n +0000014047 00000 n +0000013934 00000 n +0000012963 00000 n +0000013186 00000 n +0000013234 00000 n +0000013818 00000 n +0000013849 00000 n +0000014121 00000 n +0000014304 00000 n +0000015694 00000 n +0000022184 00000 n +0000038292 00000 n +0000055371 00000 n +trailer <<4A8039ECEBF045F1AB088ACBEA60B925>]>> startxref 55548 %%EOF \ No newline at end of file diff --git a/test/unit/api_spec.js b/test/unit/api_spec.js index 9cbfe02d0..bc7d6adcd 100644 --- a/test/unit/api_spec.js +++ b/test/unit/api_spec.js @@ -13,6 +13,9 @@ * limitations under the License. */ +import { + buildGetDocumentParams, NodeFileReaderFactory, TEST_PDFS_PATH +} from './test_utils'; import { createPromiseCapability, FontType, InvalidPDFException, isNodeJS, MissingPDFException, PasswordException, PasswordResponses, StreamType, @@ -24,29 +27,8 @@ import { import { getDocument, PDFDocumentProxy, PDFPageProxy } from '../../src/display/api'; -import { NodeFileReaderFactory } from './test_utils'; import { PDFJS } from '../../src/display/global'; -const TEST_PDFS_PATH = { - dom: '../pdfs/', - node: './test/pdfs/', -}; - -function buildGetDocumentParams(filename, options) { - let params = Object.create(null); - if (isNodeJS()) { - params.data = NodeFileReaderFactory.fetch({ - path: TEST_PDFS_PATH.node + filename, - }); - } else { - params.url = new URL(TEST_PDFS_PATH.dom + filename, window.location).href; - } - for (let option in options) { - params[option] = options[option]; - } - return params; -} - describe('api', function() { let basicApiFileName = 'basicapi.pdf'; let basicApiFileLength = 105779; // bytes diff --git a/test/unit/custom_spec.js b/test/unit/custom_spec.js new file mode 100644 index 000000000..0a31c27e4 --- /dev/null +++ b/test/unit/custom_spec.js @@ -0,0 +1,110 @@ +/* Copyright 2017 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { buildGetDocumentParams } from './test_utils'; +import { DOMCanvasFactory } from '../../src/display/dom_utils'; +import { getDocument } from '../../src/display/api'; +import { isNodeJS } from '../../src/shared/util'; +import { PDFJS } from '../../src/display/global'; + +function getTopLeftPixel(canvasContext) { + let imgData = canvasContext.getImageData(0, 0, 1, 1); + return { + r: imgData.data[0], + g: imgData.data[1], + b: imgData.data[2], + a: imgData.data[3], + }; +} + +describe('custom canvas rendering', function() { + let transparentGetDocumentParams = buildGetDocumentParams('transparent.pdf'); + + let CanvasFactory; + let loadingTask; + let page; + + beforeAll(function(done) { + if (isNodeJS()) { + PDFJS.pdfjsNext = true; + // NOTE: To support running the canvas-related tests in Node.js, + // a `NodeCanvasFactory` would need to be added (in test_utils.js). + } else { + CanvasFactory = new DOMCanvasFactory(); + } + loadingTask = getDocument(transparentGetDocumentParams); + loadingTask.promise.then(function(doc) { + return doc.getPage(1); + }).then(function(data) { + page = data; + done(); + }).catch(function (reason) { + done.fail(reason); + }); + }); + + afterAll(function(done) { + CanvasFactory = null; + page = null; + loadingTask.destroy().then(done); + }); + + it('renders to canvas with a default white background', function(done) { + if (isNodeJS()) { + pending('TODO: Support Canvas testing in Node.js.'); + } + var viewport = page.getViewport(1); + var canvasAndCtx = CanvasFactory.create(viewport.width, viewport.height); + + page.render({ + canvasContext: canvasAndCtx.context, + viewport, + }).then(function() { + var { r, g, b, a } = getTopLeftPixel(canvasAndCtx.context); + CanvasFactory.destroy(canvasAndCtx); + expect(r).toEqual(255); + expect(g).toEqual(255); + expect(b).toEqual(255); + expect(a).toEqual(255); + done(); + }).catch(function (reason) { + done(reason); + }); + }); + + it('renders to canvas with a custom background', function(done) { + if (isNodeJS()) { + pending('TODO: Support Canvas testing in Node.js.'); + } + var viewport = page.getViewport(1); + var canvasAndCtx = CanvasFactory.create(viewport.width, viewport.height); + + page.render({ + canvasContext: canvasAndCtx.context, + viewport, + background: 'rgba(255,0,0,1.0)' + }).then(function() { + var { r, g, b, a } = getTopLeftPixel(canvasAndCtx.context); + CanvasFactory.destroy(canvasAndCtx); + expect(r).toEqual(255); + expect(g).toEqual(0); + expect(b).toEqual(0); + expect(a).toEqual(255); + done(); + }).catch(function (reason) { + done(reason); + }); + }); +}); diff --git a/test/unit/jasmine-boot.js b/test/unit/jasmine-boot.js index 83e4b51a7..d96521b2e 100644 --- a/test/unit/jasmine-boot.js +++ b/test/unit/jasmine-boot.js @@ -52,7 +52,8 @@ function initializePDFJS(callback) { 'pdfjs-test/unit/network_spec', 'pdfjs-test/unit/parser_spec', 'pdfjs-test/unit/primitives_spec', 'pdfjs-test/unit/stream_spec', 'pdfjs-test/unit/type1_parser_spec', 'pdfjs-test/unit/ui_utils_spec', - 'pdfjs-test/unit/unicode_spec', 'pdfjs-test/unit/util_spec' + 'pdfjs-test/unit/unicode_spec', 'pdfjs-test/unit/util_spec', + 'pdfjs-test/unit/custom_spec' ].map(function (moduleName) { return SystemJS.import(moduleName); })).then(function (modules) { diff --git a/test/unit/test_utils.js b/test/unit/test_utils.js index 5754a4572..6104dc789 100644 --- a/test/unit/test_utils.js +++ b/test/unit/test_utils.js @@ -13,7 +13,7 @@ * limitations under the License. */ -import { CMapCompressionType } from '../../src/shared/util'; +import { CMapCompressionType, isNodeJS } from '../../src/shared/util'; class NodeFileReaderFactory { static fetch(params) { @@ -23,6 +23,26 @@ class NodeFileReaderFactory { } } +const TEST_PDFS_PATH = { + dom: '../pdfs/', + node: './test/pdfs/', +}; + +function buildGetDocumentParams(filename, options) { + let params = Object.create(null); + if (isNodeJS()) { + params.data = NodeFileReaderFactory.fetch({ + path: TEST_PDFS_PATH.node + filename, + }); + } else { + params.url = new URL(TEST_PDFS_PATH.dom + filename, window.location).href; + } + for (let option in options) { + params[option] = options[option]; + } + return params; +} + class NodeCMapReaderFactory { constructor({ baseUrl = null, isCompressed = false, }) { this.baseUrl = baseUrl; @@ -57,4 +77,6 @@ class NodeCMapReaderFactory { export { NodeFileReaderFactory, NodeCMapReaderFactory, + buildGetDocumentParams, + TEST_PDFS_PATH, };