@@ -395,6 +395,11 @@ export interface RenderSVGOptions {
395395 * Default: `1`
396396 */
397397 scale ?: number ;
398+ /**
399+ * The most pixels to render, and the most pixels in any embedded image. Default: `268402689` (16383²), `Infinity`
400+ * for no limit
401+ */
402+ maxPixels ?: number ;
398403 /**
399404 * Fonts for `<text>` (TrueType, OpenType): each text gets the face its `font-family`, `font-weight`, `font-style`
400405 * and `font-stretch` match best among them, by the names, weights and styles in the fonts (like browsers match
@@ -674,13 +679,15 @@ export class Image {
674679 * @param height The height in pixels
675680 */
676681 constructor ( width : number , height : number ) {
677- width = ~ ~ width ;
678- height = ~ ~ height ;
682+ width = Math . trunc ( finite ( width , 'width' ) ) ;
683+ height = Math . trunc ( finite ( height , 'height' ) ) ;
679684
680685 if ( width < 1 )
681686 throw new RangeError ( 'Image has to be at least 1 pixel wide' ) ;
682687 if ( height < 1 )
683688 throw new RangeError ( 'Image has to be at least 1 pixel high' ) ;
689+ if ( width > 0x7fffffff ) throw new RangeError ( 'Image width is too large' ) ;
690+ if ( height > 0x7fffffff ) throw new RangeError ( 'Image height is too large' ) ;
684691
685692 this . __width__ = width ;
686693 this . __height__ = height ;
@@ -2708,7 +2715,8 @@ export class Image {
27082715 static renderSVG ( svg : string | BinaryData , options ?: RenderSVGOptions ) : Promise < Image > ;
27092716 static async renderSVG ( svg : string | BinaryData , options : RenderSVGOptions = { } ) : Promise < Image > {
27102717 checkOptions ( options , 'renderSVG(svg, { width: 512 })' ) ;
2711- const { width : givenWidth , height : givenHeight , scale, fonts = [ ] , images : givenImages = { } } = options ;
2718+ const { width : givenWidth , height : givenHeight , scale, maxPixels = MAX_PIXELS , fonts = [ ] , images : givenImages = { } } = options ;
2719+ if ( ! ( Number ( maxPixels ) > 0 ) ) throw new RangeError ( `maxPixels must be a positive number, not ${ maxPixels } ` ) ;
27122720 const sizes = [ givenWidth , givenHeight , scale ] . filter ( value => value !== undefined ) . length ;
27132721 if ( sizes > 1 ) throw new TypeError ( 'renderSVG() takes one of width, height and scale' ) ;
27142722 const mode = givenWidth !== undefined ? 'width' : givenHeight !== undefined ? 'height' : 'scale' ;
@@ -2741,18 +2749,18 @@ export class Image {
27412749 images . set ( href , { width : value . width , height : value . height , pixels : value . bitmap } ) ;
27422750 } else if ( ImageType . getType ( value ) === 'gif' ) {
27432751 // (a GIF's first frame)
2744- const decoded = gif . decode ( view ( value ) , true ) ;
2752+ const decoded = gif . decode ( view ( value ) , true , maxPixels ) ;
27452753 images . set ( href , { width : decoded . width , height : decoded . height , pixels : gif . composite ( decoded ) [ 0 ] . pixels } ) ;
27462754 } else {
2747- const image = await Image . decode ( value ) ;
2755+ const image = await Image . decode ( value , { maxPixels } ) ;
27482756 images . set ( href , { width : image . width , height : image . height , pixels : image . bitmap } ) ;
27492757 }
27502758 } catch {
27512759 // (images that can't be decoded aren't drawn, like resvg's)
27522760 }
27532761 }
27542762
2755- const { width, height, pixels} = svgRenderer . render ( source , mode , size , images , ( Array . isArray ( fonts ) ? fonts : [ fonts ] ) . map ( font => view ( font ) ) ) ;
2763+ const { width, height, pixels} = svgRenderer . render ( source , mode , size , images , ( Array . isArray ( fonts ) ? fonts : [ fonts ] ) . map ( font => view ( font ) ) , maxPixels ) ;
27562764 const image = new Image ( width , height ) ;
27572765 image . bitmap . set ( pixels ) ;
27582766
0 commit comments