@@ -244,7 +244,7 @@ impl Resvg {
244244 if !bbox. width . is_finite ( ) || !bbox. height . is_finite ( ) {
245245 return ;
246246 }
247- let padding = padding. unwrap_or ( 0.0 ) as f32 ;
247+ let pixel_padding = padding. unwrap_or ( 0.0 ) as f32 ;
248248 let square = square. unwrap_or ( false ) ;
249249
250250 let mut x = bbox. x as f32 ;
@@ -265,15 +265,109 @@ impl Resvg {
265265 height = max_dimension;
266266 }
267267
268- // Apply padding
269- let final_x = x - padding;
270- let final_y = y - padding;
271- let final_width = width + ( padding * 2.0 ) ;
272- let final_height = height + ( padding * 2.0 ) ;
273-
274- self . tree . view_box . rect =
275- usvg:: NonZeroRect :: from_xywh ( final_x, final_y, final_width, final_height) . unwrap ( ) ;
276- self . tree . size = usvg:: Size :: from_wh ( final_width, final_height) . unwrap ( ) ;
268+ // Get current tree size before any modifications
269+ let current_tree_size = self . tree . size ;
270+
271+ // Check if fitTo is being used (not Original)
272+ match & self . js_options . fit_to {
273+ options:: FitToDef :: Original => {
274+ // Case 1: No fitTo - crop to bbox size, then center and scale content to fit (bbox_size - padding*2)
275+ // Calculate the content size (bbox size minus padding), clamp to 0 for negative values
276+ let content_width = ( width - pixel_padding * 2.0 ) . max ( 0.0 ) ;
277+ let content_height = ( height - pixel_padding * 2.0 ) . max ( 0.0 ) ;
278+
279+ // The final SVG size should be the bbox size
280+ let final_svg_width = width;
281+ let final_svg_height = height;
282+
283+ // Handle edge case: if content size is 0, create viewBox outside visible area for transparent result
284+ if content_width == 0.0 || content_height == 0.0 {
285+ // Create a viewBox that's positioned outside the visible area to produce transparent result
286+ self . tree . view_box . rect =
287+ usvg:: NonZeroRect :: from_xywh ( x + width, y + height, 1.0 , 1.0 ) . unwrap ( ) ;
288+ self . tree . size =
289+ usvg:: Size :: from_wh ( final_svg_width, final_svg_height) . unwrap ( ) ;
290+ } else {
291+ // Calculate the scale factor to fit the content within the padding
292+ let scale_x = content_width / width;
293+ let scale_y = content_height / height;
294+ let scale = scale_x. min ( scale_y) ;
295+
296+ // Create a viewBox that shows the original bbox area, scaled and centered
297+ let bbox_center_x = x + width / 2.0 ;
298+ let bbox_center_y = y + height / 2.0 ;
299+
300+ let viewbox_width = width / scale;
301+ let viewbox_height = height / scale;
302+
303+ let viewbox_x = bbox_center_x - viewbox_width / 2.0 ;
304+ let viewbox_y = bbox_center_y - viewbox_height / 2.0 ;
305+
306+ self . tree . view_box . rect = usvg:: NonZeroRect :: from_xywh (
307+ viewbox_x,
308+ viewbox_y,
309+ viewbox_width,
310+ viewbox_height,
311+ )
312+ . unwrap ( ) ;
313+ self . tree . size =
314+ usvg:: Size :: from_wh ( final_svg_width, final_svg_height) . unwrap ( ) ;
315+ }
316+ }
317+ _ => {
318+ // Case 2: fitTo is used - padding is absolute pixels within the target size
319+ match self . js_options . fit_to . fit_to ( current_tree_size) {
320+ Ok ( ( target_width, target_height, _) ) => {
321+ // Calculate the content size in the final render (target size minus padding), clamp to 0 for negative values
322+ let content_target_width =
323+ ( target_width as f32 - pixel_padding * 2.0 ) . max ( 0.0 ) ;
324+ let content_target_height =
325+ ( target_height as f32 - pixel_padding * 2.0 ) . max ( 0.0 ) ;
326+
327+ // Handle edge case: if content size is 0, create viewBox outside visible area for transparent result
328+ if content_target_width == 0.0 || content_target_height == 0.0 {
329+ // Create a viewBox that's positioned outside the visible area to produce transparent result
330+ self . tree . view_box . rect =
331+ usvg:: NonZeroRect :: from_xywh ( x + width, y + height, 1.0 , 1.0 )
332+ . unwrap ( ) ;
333+ self . tree . size =
334+ usvg:: Size :: from_wh ( target_width as f32 , target_height as f32 )
335+ . unwrap ( ) ;
336+ } else {
337+ // Calculate what SVG size we need to achieve the target final size after fitTo
338+ let required_svg_width =
339+ width * target_width as f32 / content_target_width;
340+ let required_svg_height =
341+ height * target_height as f32 / content_target_height;
342+
343+ // Create a viewBox that centers the original bbox within the required SVG size
344+ let bbox_center_x = x + width / 2.0 ;
345+ let bbox_center_y = y + height / 2.0 ;
346+
347+ let viewbox_x = bbox_center_x - required_svg_width / 2.0 ;
348+ let viewbox_y = bbox_center_y - required_svg_height / 2.0 ;
349+
350+ self . tree . view_box . rect = usvg:: NonZeroRect :: from_xywh (
351+ viewbox_x,
352+ viewbox_y,
353+ required_svg_width,
354+ required_svg_height,
355+ )
356+ . unwrap ( ) ;
357+ self . tree . size =
358+ usvg:: Size :: from_wh ( required_svg_width, required_svg_height)
359+ . unwrap ( ) ;
360+ }
361+ }
362+ Err ( _) => {
363+ // Fallback to no padding
364+ self . tree . view_box . rect =
365+ usvg:: NonZeroRect :: from_xywh ( x, y, width, height) . unwrap ( ) ;
366+ self . tree . size = usvg:: Size :: from_wh ( width, height) . unwrap ( ) ;
367+ }
368+ }
369+ }
370+ }
277371 }
278372
279373 #[ napi]
@@ -412,7 +506,7 @@ impl Resvg {
412506 if !bbox. width . is_finite ( ) || !bbox. height . is_finite ( ) {
413507 return ;
414508 }
415- let padding = padding. unwrap_or ( 0.0 ) as f32 ;
509+ let pixel_padding = padding. unwrap_or ( 0.0 ) as f32 ;
416510 let square = square. unwrap_or ( false ) ;
417511
418512 let mut x = bbox. x as f32 ;
@@ -433,15 +527,109 @@ impl Resvg {
433527 height = max_dimension;
434528 }
435529
436- // Apply padding
437- let final_x = x - padding;
438- let final_y = y - padding;
439- let final_width = width + ( padding * 2.0 ) ;
440- let final_height = height + ( padding * 2.0 ) ;
441-
442- self . tree . view_box . rect =
443- usvg:: NonZeroRect :: from_xywh ( final_x, final_y, final_width, final_height) . unwrap ( ) ;
444- self . tree . size = usvg:: Size :: from_wh ( final_width, final_height) . unwrap ( ) ;
530+ // Get current tree size before any modifications
531+ let current_tree_size = self . tree . size ;
532+
533+ // Check if fitTo is being used (not Original)
534+ match & self . js_options . fit_to {
535+ options:: FitToDef :: Original => {
536+ // Case 1: No fitTo - crop to bbox size, then center and scale content to fit (bbox_size - padding*2)
537+ // Calculate the content size (bbox size minus padding), clamp to 0 for negative values
538+ let content_width = ( width - pixel_padding * 2.0 ) . max ( 0.0 ) ;
539+ let content_height = ( height - pixel_padding * 2.0 ) . max ( 0.0 ) ;
540+
541+ // The final SVG size should be the bbox size
542+ let final_svg_width = width;
543+ let final_svg_height = height;
544+
545+ // Handle edge case: if content size is 0, create viewBox outside visible area for transparent result
546+ if content_width == 0.0 || content_height == 0.0 {
547+ // Create a viewBox that's positioned outside the visible area to produce transparent result
548+ self . tree . view_box . rect =
549+ usvg:: NonZeroRect :: from_xywh ( x + width, y + height, 1.0 , 1.0 ) . unwrap ( ) ;
550+ self . tree . size =
551+ usvg:: Size :: from_wh ( final_svg_width, final_svg_height) . unwrap ( ) ;
552+ } else {
553+ // Calculate the scale factor to fit the content within the padding
554+ let scale_x = content_width / width;
555+ let scale_y = content_height / height;
556+ let scale = scale_x. min ( scale_y) ;
557+
558+ // Create a viewBox that shows the original bbox area, scaled and centered
559+ let bbox_center_x = x + width / 2.0 ;
560+ let bbox_center_y = y + height / 2.0 ;
561+
562+ let viewbox_width = width / scale;
563+ let viewbox_height = height / scale;
564+
565+ let viewbox_x = bbox_center_x - viewbox_width / 2.0 ;
566+ let viewbox_y = bbox_center_y - viewbox_height / 2.0 ;
567+
568+ self . tree . view_box . rect = usvg:: NonZeroRect :: from_xywh (
569+ viewbox_x,
570+ viewbox_y,
571+ viewbox_width,
572+ viewbox_height,
573+ )
574+ . unwrap ( ) ;
575+ self . tree . size =
576+ usvg:: Size :: from_wh ( final_svg_width, final_svg_height) . unwrap ( ) ;
577+ }
578+ }
579+ _ => {
580+ // Case 2: fitTo is used - padding is absolute pixels within the target size
581+ match self . js_options . fit_to . fit_to ( current_tree_size) {
582+ Ok ( ( target_width, target_height, _) ) => {
583+ // Calculate the content size in the final render (target size minus padding), clamp to 0 for negative values
584+ let content_target_width =
585+ ( target_width as f32 - pixel_padding * 2.0 ) . max ( 0.0 ) ;
586+ let content_target_height =
587+ ( target_height as f32 - pixel_padding * 2.0 ) . max ( 0.0 ) ;
588+
589+ // Handle edge case: if content size is 0, create viewBox outside visible area for transparent result
590+ if content_target_width == 0.0 || content_target_height == 0.0 {
591+ // Create a viewBox that's positioned outside the visible area to produce transparent result
592+ self . tree . view_box . rect =
593+ usvg:: NonZeroRect :: from_xywh ( x + width, y + height, 1.0 , 1.0 )
594+ . unwrap ( ) ;
595+ self . tree . size =
596+ usvg:: Size :: from_wh ( target_width as f32 , target_height as f32 )
597+ . unwrap ( ) ;
598+ } else {
599+ // Calculate what SVG size we need to achieve the target final size after fitTo
600+ let required_svg_width =
601+ width * target_width as f32 / content_target_width;
602+ let required_svg_height =
603+ height * target_height as f32 / content_target_height;
604+
605+ // Create a viewBox that centers the original bbox within the required SVG size
606+ let bbox_center_x = x + width / 2.0 ;
607+ let bbox_center_y = y + height / 2.0 ;
608+
609+ let viewbox_x = bbox_center_x - required_svg_width / 2.0 ;
610+ let viewbox_y = bbox_center_y - required_svg_height / 2.0 ;
611+
612+ self . tree . view_box . rect = usvg:: NonZeroRect :: from_xywh (
613+ viewbox_x,
614+ viewbox_y,
615+ required_svg_width,
616+ required_svg_height,
617+ )
618+ . unwrap ( ) ;
619+ self . tree . size =
620+ usvg:: Size :: from_wh ( required_svg_width, required_svg_height)
621+ . unwrap ( ) ;
622+ }
623+ }
624+ Err ( _) => {
625+ // Fallback to no padding
626+ self . tree . view_box . rect =
627+ usvg:: NonZeroRect :: from_xywh ( x, y, width, height) . unwrap ( ) ;
628+ self . tree . size = usvg:: Size :: from_wh ( width, height) . unwrap ( ) ;
629+ }
630+ }
631+ }
632+ }
445633 }
446634
447635 #[ wasm_bindgen( js_name = imagesToResolve) ]
0 commit comments