@@ -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,92 @@ 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 } ${ parsedCS . numComps }  
160+       ) ; 
161+       return  deviceCS ; 
162+     } 
163+ 
164+     // Only cache the parsed ColorSpace globally, by reference. 
165+     if  ( csRef )  { 
166+       globalColorSpaceCache . set ( /* name = */  null ,  csRef ,  parsedCS ) ; 
167+     } 
168+     return  parsedCS ; 
169+   } 
170+ 
171+   static  #parse( cs ,  options ,  topLevel  =  false )  { 
172+     const  {  xref,  pdfFunctionFactory,  globalColorSpaceCache }  =  options ; 
130173
131174    cs  =  xref . fetchIfRef ( cs ) ; 
132175    if  ( cs  instanceof  Name )  { 
133176      switch  ( cs . name )  { 
134177        case  "G" :
135-         case  "DeviceGray" :
178+         case  "DeviceGray" : { 
179+           const  defaultCS  =  topLevel  &&  this . #getResCS( "DefaultGray" ,  options ) ; 
180+           if  ( defaultCS )  { 
181+             return  this . #defaultParse( defaultCS ,  options ,  this . gray ) ; 
182+           } 
136183          return  this . gray ; 
184+         } 
137185        case  "RGB" :
138-         case  "DeviceRGB" :
186+         case  "DeviceRGB" : { 
187+           const  defaultCS  =  topLevel  &&  this . #getResCS( "DefaultRGB" ,  options ) ; 
188+           if  ( defaultCS )  { 
189+             return  this . #defaultParse( defaultCS ,  options ,  this . rgb ) ; 
190+           } 
139191          return  this . rgb ; 
192+         } 
140193        case  "DeviceRGBA" :
141194          return  this . rgba ; 
142195        case  "CMYK" :
143-         case  "DeviceCMYK" :
196+         case  "DeviceCMYK" : { 
197+           const  defaultCS  =  topLevel  &&  this . #getResCS( "DefaultCMYK" ,  options ) ; 
198+           if  ( defaultCS )  { 
199+             return  this . #subParse( defaultCS ,  options ,  this . cmyk ) ; 
200+           } 
144201          return  this . cmyk ; 
202+         } 
145203        case  "Pattern" :
146204          return  new  PatternCS ( /* baseCS = */  null ) ; 
147205        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-               } 
206+           const  resourcesCS  =  xref . fetchIfRef ( this . #getResCS( cs . name ,  options ) ) ; 
207+           if  ( resourcesCS )  { 
208+             if  ( resourcesCS  instanceof  Name )  { 
209+               return  this . #parse( resourcesCS ,  options ) ; 
159210            } 
211+             cs  =  resourcesCS ; 
212+             break ; 
160213          } 
161214          // Fallback to the default gray color space. 
162215          warn ( `Unrecognized ColorSpace: ${ cs . name }  ) ; 
@@ -276,6 +329,16 @@ class ColorSpaceUtils {
276329    return  this . gray ; 
277330  } 
278331
332+   static  #getResCS( name ,  {  resources } )  { 
333+     if  ( resources  instanceof  Dict )  { 
334+       const  colorSpaces  =  resources . get ( "ColorSpace" ) ; 
335+       if  ( colorSpaces  instanceof  Dict )  { 
336+         return  colorSpaces . getRaw ( name )  ??  null ; 
337+       } 
338+     } 
339+     return  null ; 
340+   } 
341+ 
279342  static  get  gray ( )  { 
280343    return  shadow ( this ,  "gray" ,  new  DeviceGrayCS ( ) ) ; 
281344  } 
0 commit comments