@@ -79,7 +79,7 @@ class ColorSpaceUtils {
7979 }
8080
8181 try {
82- parsedCS = this . #parse( cs , options ) ;
82+ parsedCS = this . #parse( cs , options , /* topLevel = */ true ) ;
8383 } catch ( ex ) {
8484 if ( asyncIfNotCached && ! ( ex instanceof MissingDataException ) ) {
8585 return Promise . reject ( ex ) ;
@@ -124,39 +124,94 @@ class ColorSpaceUtils {
124124 return parsedCS ;
125125 }
126126
127- static #parse( cs , options ) {
128- const { xref, resources, pdfFunctionFactory, globalColorSpaceCache } =
129- options ;
127+ /**
128+ * NOTE: This method should *only* be invoked from `this.#parse`,
129+ * when parsing "default" ColorSpaces (i.e. /DefaultGray, /DefaultRGB,
130+ * and /DefaultCMYK).
131+ */
132+ static #defaultParse( cs , options , deviceCS ) {
133+ const { globalColorSpaceCache } = options ;
134+ let csRef , parsedCS ;
135+
136+ // Check if the ColorSpace is cached first, to avoid re-parsing it.
137+ if ( cs instanceof Ref ) {
138+ csRef = cs ;
139+
140+ const cachedCS = globalColorSpaceCache . getByRef ( csRef ) ;
141+ if ( cachedCS ) {
142+ return cachedCS ;
143+ }
144+ }
145+ try {
146+ parsedCS = this . #parse( cs , options ) ;
147+ } catch ( ex ) {
148+ if ( ex instanceof MissingDataException ) {
149+ throw ex ;
150+ }
151+ warn ( `Cannot parse default ColorSpace: "${ ex } ".` ) ;
152+ return deviceCS ;
153+ }
154+
155+ // The default ColorSpace must be compatible with the original one.
156+ if ( parsedCS . numComps !== deviceCS . numComps ) {
157+ warn (
158+ "Incorrect number of components in default ColorSpace, " +
159+ `expected "${ deviceCS . numComps } " and got "${ parsedCS . numComps } ".`
160+ ) ;
161+ return deviceCS ;
162+ }
163+ // Ensure that any `name`-checks still work as before.
164+ parsedCS . name = deviceCS . name ;
165+
166+ // Only cache the parsed ColorSpace globally, by reference.
167+ if ( csRef ) {
168+ globalColorSpaceCache . set ( /* name = */ null , csRef , parsedCS ) ;
169+ }
170+ return parsedCS ;
171+ }
172+
173+ static #parse( cs , options , topLevel = false ) {
174+ const { xref, pdfFunctionFactory, globalColorSpaceCache } = options ;
130175
131176 cs = xref . fetchIfRef ( cs ) ;
132177 if ( cs instanceof Name ) {
133178 switch ( cs . name ) {
134179 case "G" :
135- case "DeviceGray" :
180+ case "DeviceGray" : {
181+ const defaultCS = topLevel && this . #getResCS( "DefaultGray" , options ) ;
182+ if ( defaultCS ) {
183+ return this . #defaultParse( defaultCS , options , this . gray ) ;
184+ }
136185 return this . gray ;
186+ }
137187 case "RGB" :
138- case "DeviceRGB" :
188+ case "DeviceRGB" : {
189+ const defaultCS = topLevel && this . #getResCS( "DefaultRGB" , options ) ;
190+ if ( defaultCS ) {
191+ return this . #defaultParse( defaultCS , options , this . rgb ) ;
192+ }
139193 return this . rgb ;
194+ }
140195 case "DeviceRGBA" :
141196 return this . rgba ;
142197 case "CMYK" :
143- case "DeviceCMYK" :
198+ case "DeviceCMYK" : {
199+ const defaultCS = topLevel && this . #getResCS( "DefaultCMYK" , options ) ;
200+ if ( defaultCS ) {
201+ return this . #subParse( defaultCS , options , this . cmyk ) ;
202+ }
144203 return this . cmyk ;
204+ }
145205 case "Pattern" :
146206 return new PatternCS ( /* baseCS = */ null ) ;
147207 default :
148- if ( resources instanceof Dict ) {
149- const colorSpaces = resources . get ( "ColorSpace" ) ;
150- if ( colorSpaces instanceof Dict ) {
151- const resourcesCS = colorSpaces . get ( cs . name ) ;
152- if ( resourcesCS ) {
153- if ( resourcesCS instanceof Name ) {
154- return this . #parse( resourcesCS , options ) ;
155- }
156- cs = resourcesCS ;
157- break ;
158- }
208+ const resourcesCS = xref . fetchIfRef ( this . #getResCS( cs . name , options ) ) ;
209+ if ( resourcesCS ) {
210+ if ( resourcesCS instanceof Name ) {
211+ return this . #parse( resourcesCS , options ) ;
159212 }
213+ cs = resourcesCS ;
214+ break ;
160215 }
161216 // Fallback to the default gray color space.
162217 warn ( `Unrecognized ColorSpace: ${ cs . name } ` ) ;
@@ -276,6 +331,16 @@ class ColorSpaceUtils {
276331 return this . gray ;
277332 }
278333
334+ static #getResCS( name , { resources } ) {
335+ if ( resources instanceof Dict ) {
336+ const colorSpaces = resources . get ( "ColorSpace" ) ;
337+ if ( colorSpaces instanceof Dict ) {
338+ return colorSpaces . getRaw ( name ) ?? null ;
339+ }
340+ }
341+ return null ;
342+ }
343+
279344 static get gray ( ) {
280345 return shadow ( this , "gray" , new DeviceGrayCS ( ) ) ;
281346 }
0 commit comments