@@ -3,8 +3,8 @@ Attribute VB_Name = "Plugin_resvg"
33'resvg Library Interface (SVG import)
44'Copyright 2022-2023 by Tanner Helland
55'Created: 28/February/22
6- 'Last updated: 15/October/22
7- 'Last update: fix load behavior during batch processing
6+ 'Last updated: 16/June/23
7+ 'Last update: rewrite against latest resvg (0.34.1)
88'
99'Per its documentation (available at https://github.com/RazrFalcon/resvg), resvg is...
1010'
@@ -30,7 +30,7 @@ Attribute VB_Name = "Plugin_resvg"
3030Option Explicit
3131
3232'Information on individual resvg calls can be saved to the debug log via this constant;
33- ' please DISABLE in production builds
33+ ' please DISABLE in production builds (as reporting is quite noisy!)
3434Private Const SVG_DEBUG_VERBOSE As Boolean = False
3535
3636Private Enum resvg_result
@@ -56,23 +56,6 @@ End Enum
5656 Private Const RESVG_OK = 0 , RESVG_ERROR_NOT_AN_UTF8_STR = 1 , RESVG_ERROR_FILE_OPEN_FAILED = 2 , RESVG_ERROR_MALFORMED_GZIP = 3 , RESVG_ERROR_ELEMENTS_LIMIT_REACHED = 4 , RESVG_ERROR_INVALID_SIZE = 5 , RESVG_ERROR_PARSING_FAILED = 6
5757#End If
5858
59- 'A "fit to" type.
60- ' (All types produce proportional scaling.)
61- Private Enum resvg_fit_to_type
62- 'Use an original image size.
63- RESVG_FIT_TO_TYPE_ORIGINAL
64- 'Fit an image to a specified width.
65- RESVG_FIT_TO_TYPE_WIDTH
66- 'Fit an image to a specified height.
67- RESVG_FIT_TO_TYPE_HEIGHT
68- 'Zoom an image using scaling factor.
69- RESVG_FIT_TO_TYPE_ZOOM
70- End Enum
71-
72- #If False Then
73- Private Const RESVG_FIT_TO_TYPE_ORIGINAL = 0 , RESVG_FIT_TO_TYPE_WIDTH = 0 , RESVG_FIT_TO_TYPE_HEIGHT = 0 , RESVG_FIT_TO_TYPE_ZOOM = 0
74- #End If
75-
7659'An image rendering method.
7760Private Enum resvg_image_rendering
7861 RESVG_IMAGE_RENDERING_OPTIMIZE_QUALITY
@@ -107,48 +90,28 @@ End Enum
10790
10891'A 2D transform representation.
10992Private Type resvg_transform
110- a As Double
111- b As Double
112- c As Double
113- d As Double
114- e As Double
115- f As Double
93+ a As Single
94+ b As Single
95+ c As Single
96+ d As Single
97+ e As Single
98+ f As Single
11699End Type
117100
118101'A size representation.
119102' (Width and height are guaranteed to be > 0.)
120103Private Type resvg_size
121- svg_width As Double
122- svg_height As Double
104+ svg_width As Single
105+ svg_height As Single
123106End Type
124107
125108'A rectangle representation.
126109' (Width *and* height are guarantee to be > 0.)
127110Private Type resvg_rect
128- x As Double
129- y As Double
130- Width As Double
131- Height As Double
132- End Type
133-
134- 'A path bbox representation.
135- ' (Width *or* height are guarantee to be > 0.)
136- Private Type resvg_path_bbox
137- x As Double
138- y As Double
139- Width As Double
140- Height As Double
141- End Type
142-
143- 'A "fit to" property.
144- Private Type resvg_fit_to
145- 'A fit type.
146- fit_type As resvg_fit_to_type
147- 'Fit to value
148- '* Not used by RESVG_FIT_TO_ORIGINAL.
149- '* Must be >= 1 for RESVG_FIT_TO_WIDTH and RESVG_FIT_TO_HEIGHT.
150- '* Must be > 0 for RESVG_FIT_TO_ZOOM.
151- fit_value As Single
111+ x As Single
112+ y As Single
113+ Width As Single
114+ Height As Single
152115End Type
153116
154117Private Declare Function resvg_transform_identity Lib "resvg " () As resvg_transform
@@ -177,15 +140,15 @@ Private Declare Function resvg_parse_tree_from_data Lib "resvg" (ByVal ptrToData
177140Private Declare Function resvg_is_image_empty Lib "resvg " (ByVal resvg_render_tree As Long ) As Long
178141Private Declare Function resvg_get_image_size Lib "resvg " (ByVal resvg_render_tree As Long ) As resvg_size
179142Private Declare Function resvg_get_image_viewbox Lib "resvg " (ByVal resvg_render_tree As Long ) As resvg_rect
180- Private Declare Function resvg_get_imgae_bbox Lib "resvg " (ByVal resvg_render_tree As Long , ByRef dst_resvg_rect As resvg_rect ) As Long
143+ Private Declare Function resvg_get_image_bbox Lib "resvg " (ByVal resvg_render_tree As Long , ByRef dst_resvg_rect As resvg_rect ) As Long
181144Private Declare Function resvg_node_exists Lib "resvg " (ByVal resvg_render_tree As Long , ByVal ptrToConstUtf8ID As Long ) As Long
182145Private Declare Function resvg_get_node_transform Lib "resvg " (ByVal resvg_render_tree As Long , ByVal ptrToConstUtf8ID As Long , ByRef dst_resvg_transform As resvg_transform ) As Long
183- Private Declare Function resvg_get_node_bbox Lib "resvg " (ByVal resvg_render_tree As Long , ByVal ptrToConstUtf8ID As Long , ByRef dst_resvg_path_bbox As resvg_path_bbox ) As Long
146+ Private Declare Function resvg_get_node_bbox Lib "resvg " (ByVal resvg_render_tree As Long , ByVal ptrToConstUtf8ID As Long , ByRef dst_resvg_path_bbox As resvg_rect ) As Long
184147Private Declare Sub resvg_tree_destroy Lib "resvg " (ByVal resvg_render_tree As Long )
185- Private Declare Sub resvg_render Lib "resvg " (ByVal resvg_render_tree As Long , ByRef fit_to As resvg_fit_to , ByRef srcTransform As resvg_transform , ByVal surfaceWidth As Long , ByVal surfaceHeight As Long , ByVal ptrToSurface As Long )
148+ Private Declare Sub resvg_render Lib "resvg " (ByVal resvg_render_tree As Long , ByRef srcTransform As resvg_transform , ByVal surfaceWidth As Long , ByVal surfaceHeight As Long , ByVal ptrToSurface As Long )
186149
187150'Note: node rendering needs custom resvg modifications to change the way fit_to is passed
188- 'Private Declare Sub resvg_render_node Lib "resvg" (ByVal resvg_render_tree As Long, ByVal ptrToConstUtf8ID As Long, ByVal fit_to As resvg_fit_to, ByVal srcTransform As resvg_transform, ByVal surfaceWidth As Long, ByVal surfaceHeight As Long, ByVal ptrToSurface As Long)
151+ 'Private Declare Sub resvg_render_node Lib "resvg" (ByVal resvg_render_tree As Long, ByVal ptrToConstUtf8ID As Long, ByVal srcTransform As resvg_transform, ByVal surfaceWidth As Long, ByVal surfaceHeight As Long, ByVal ptrToSurface As Long)
189152
190153'A single persistent SVG options handle is maintained for the life of a session.
191154' (Initializing this object is expensive because it needs to scan system fonts.)
@@ -208,7 +171,7 @@ Public Function GetVersion() As String
208171 'resvg does not provide an externally accessible version string by default.
209172 ' I do not expect users to custom-build it, so we return a hard-coded version
210173 ' against the copy supplied with a default PD install.
211- GetVersion = "0.28.0 "
174+ GetVersion = "0.34.1 "
212175
213176End Function
214177
@@ -420,11 +383,6 @@ Public Function LoadSVG_FromFile(ByRef srcFile As String, ByRef dstImage As pdIm
420383 'SVG renders will always be premultiplied
421384 dstDIB.SetInitialAlphaPremultiplicationState True
422385
423- 'Specify fitting behavior (we always use original fit - you'll see why in a moment)
424- Dim fitBehavior As resvg_fit_to
425- fitBehavior.fit_type = RESVG_FIT_TO_TYPE_ORIGINAL
426- fitBehavior.fit_value = 1 !
427-
428386 'If custom destination width/height is specified, we want to use the final transform matrix
429387 ' to apply the resize.
430388 Dim idMatrix As resvg_transform
@@ -439,10 +397,10 @@ Public Function LoadSVG_FromFile(ByRef srcFile As String, ByRef dstImage As pdIm
439397 Set cMatrix = New pd2DTransform
440398 cMatrix.ApplyScaling userWidth / intWidth, userHeight / intHeight
441399
400+ 'Pull the class into a bare list of floats, then relay those floats to a resvg matrix struct
442401 Dim tmpFloats() As Single
443402 If cMatrix.GetMatrixPoints(tmpFloats) Then
444403
445- 'resvg uses doubles, not floats
446404 With idMatrix
447405 .a = tmpFloats(0 )
448406 .b = tmpFloats(1 )
@@ -451,14 +409,15 @@ Public Function LoadSVG_FromFile(ByRef srcFile As String, ByRef dstImage As pdIm
451409 .e = tmpFloats(4 )
452410 .f = tmpFloats(5 )
453411 End With
454-
455- 'no Else required, since we've already initialized the matrix to its identity form
412+
413+ Else
414+ InternalError "Bad matrix retrieval in LoadSVG_FromFile"
456415 End If
457416
458417 End If
459418
460419 'Render!
461- resvg_render svgTree, fitBehavior, idMatrix, userWidth, userHeight, dstDIB.GetDIBPointer()
420+ resvg_render svgTree, idMatrix, userWidth, userHeight, dstDIB.GetDIBPointer()
462421 PDDebug.LogAction "Finished render"
463422
464423 'Finally, we need to swizzle RGBA order to BGRA order
@@ -498,21 +457,29 @@ End Sub
498457
499458'Do not call this function. It is only designed to be used for previews on the SVG import screen.
500459Public Function RenderToArbitraryDIB (ByVal hResvgTree As Long , ByRef dstDIB As pdDIB ) As Boolean
501-
502- 'Specify fitting behavior
503- Dim fitBehavior As resvg_fit_to
504- fitBehavior.fit_type = RESVG_FIT_TO_TYPE_ORIGINAL
505- fitBehavior.fit_value = 1 !
506-
460+
461+ If SVG_DEBUG_VERBOSE Then PDDebug.LogAction "Preparing to render tree #" & CStr(hResvgTree) & " to DIB..."
462+
507463 'If custom destination width/height is specified, we want to use the final transform matrix
508464 ' to apply the resize.
509465 Dim idMatrix As resvg_transform
510466 idMatrix = resvg_transform_identity()
511467
468+ If SVG_DEBUG_VERBOSE Then
469+ PDDebug.LogAction "Retrieved identity matrix OK"
470+ With idMatrix
471+ PDDebug.LogAction .a & ", " & .b & ", " & .c
472+ PDDebug.LogAction .d & ", " & .e & ", " & .f
473+ End With
474+ End If
475+
512476 'Scale to fit the destination DIB (if its size doesn't match the original width/height)
513477 Dim imgSize As resvg_size
514478 imgSize = resvg_get_image_size(hResvgTree)
515479
480+ If SVG_DEBUG_VERBOSE Then PDDebug.LogAction "Retrieved size is " & CStr(imgSize.svg_width) & " x " & CStr(imgSize.svg_height)
481+
482+ 'Calculate integer dimensions prior to positioning
516483 Dim intWidth As Long , intHeight As Long
517484 intWidth = Int(imgSize.svg_width)
518485 intHeight = Int(imgSize.svg_height)
@@ -523,12 +490,43 @@ Public Function RenderToArbitraryDIB(ByVal hResvgTree As Long, ByRef dstDIB As p
523490 ' for previews on the import screen - so its guaranteed that the passed DIB will always
524491 ' be the same aspect ratio as the source SVG.
525492 If (dstDIB.GetDIBWidth <> intWidth) Or (dstDIB.GetDIBHeight <> intHeight) Then
526- fitBehavior.fit_type = RESVG_FIT_TO_TYPE_ZOOM
527- fitBehavior.fit_value = dstDIB.GetDIBWidth / intWidth
493+
494+ 'Here's a nice twist - let's make our code more readable by using a pd2D class to
495+ ' produce the scale transform for us! (Ideally, we could also use this to apply
496+ ' skew and rotate in the future.)
497+ Dim cMatrix As pd2DTransform
498+ Set cMatrix = New pd2DTransform
499+ cMatrix.ApplyScaling dstDIB.GetDIBWidth / intWidth, dstDIB.GetDIBHeight / intHeight
500+
501+ Dim tmpFloats() As Single
502+ If cMatrix.GetMatrixPoints(tmpFloats) Then
503+ With idMatrix
504+ .a = tmpFloats(0 )
505+ .b = tmpFloats(1 )
506+ .c = tmpFloats(2 )
507+ .d = tmpFloats(3 )
508+ .e = tmpFloats(4 )
509+ .f = tmpFloats(5 )
510+ End With
511+ Else
512+ InternalError "Bad matrix retrieval in RenderToArbitraryDIB"
513+ End If
514+
515+ If SVG_DEBUG_VERBOSE Then
516+ PDDebug.LogAction "Scaling matrix will be applied: "
517+ With idMatrix
518+ PDDebug.LogAction .a & ", " & .b & ", " & .c
519+ PDDebug.LogAction .d & ", " & .e & ", " & .f
520+ End With
521+ End If
522+
528523 End If
529524
530525 'Render and swizzle
531- resvg_render hResvgTree, fitBehavior, idMatrix, dstDIB.GetDIBWidth, dstDIB.GetDIBHeight, dstDIB.GetDIBPointer()
526+ If SVG_DEBUG_VERBOSE Then PDDebug.LogAction "Attempting render to DIB with size " & dstDIB.GetDIBWidth & " x " & dstDIB.GetDIBHeight
527+ resvg_render hResvgTree, idMatrix, dstDIB.GetDIBWidth, dstDIB.GetDIBHeight, dstDIB.GetDIBPointer()
528+
529+ If SVG_DEBUG_VERBOSE Then PDDebug.LogAction "Render successful. Swizzling channels before exiting..."
532530 DIBs.SwizzleBR dstDIB
533531
534532End Function
0 commit comments