@@ -14,6 +14,7 @@ import { GridBackground } from '@/components/grid-background';
14
14
import NextImage from 'next/image' ;
15
15
import { MobileNav } from '@/components/mobile-nav' ;
16
16
import ConverterFaq from '@/components/faq/converter-faq' ;
17
+ import html2canvas from 'html2canvas' ;
17
18
18
19
export default function ConverterPage ( ) {
19
20
const [ svgCode , setSvgCode ] = useState < string > ( '<svg xmlns="http://www.w3.org/2000/svg" width="400" height="400" viewBox="0 0 400 400" fill="none">\n <rect width="400" height="400" rx="200" fill="#2563eb"/>\n <circle cx="200" cy="200" r="80" fill="black"/>\n <rect x="240" y="240" width="120" height="120" rx="20" fill="white" transform="rotate(-45 240 240)"/>\n</svg>' ) ;
@@ -87,51 +88,64 @@ export default function ConverterPage() {
87
88
URL . revokeObjectURL ( url ) ;
88
89
} ;
89
90
90
- const convertSvgToImage = ( ) => {
91
+ const convertSvgToImage = async ( ) => {
91
92
if ( ! svgCode ) return ;
92
93
93
- const parser = new DOMParser ( ) ;
94
- const svgDoc = parser . parseFromString ( svgCode , 'image/svg+xml' ) ;
95
- const svgElement = svgDoc . documentElement ;
96
-
97
- // Create a canvas element
98
- const canvas = document . createElement ( 'canvas' ) ;
99
- const ctx = canvas . getContext ( '2d' ) ;
100
- if ( ! ctx ) return ;
101
-
102
- // Set canvas dimensions based on SVG and scale
103
- const svgWidth = parseInt ( svgElement . getAttribute ( 'width' ) || '400' ) ;
104
- const svgHeight = parseInt ( svgElement . getAttribute ( 'height' ) || '400' ) ;
105
-
106
- // For ICO format, we need to ensure the dimensions are appropriate
107
- if ( format === 'ico' ) {
108
- canvas . width = icoSize ;
109
- canvas . height = icoSize ;
110
- } else {
111
- canvas . width = svgWidth * scale ;
112
- canvas . height = svgHeight * scale ;
113
- }
114
-
115
- // Create an image from the SVG
116
- const img = document . createElement ( 'img' ) ;
117
- const svgBlob = new Blob ( [ svgCode ] , { type : 'image/svg+xml;charset=utf-8' } ) ;
118
- const url = URL . createObjectURL ( svgBlob ) ;
119
-
120
- img . onload = ( ) => {
121
- // Draw the image on the canvas
122
- ctx . drawImage ( img , 0 , 0 , canvas . width , canvas . height ) ;
94
+ try {
95
+ // 创建一个临时的 div 来放置 SVG
96
+ const tempDiv = document . createElement ( 'div' ) ;
97
+ tempDiv . innerHTML = svgCode ;
98
+ tempDiv . style . position = 'absolute' ;
99
+ tempDiv . style . left = '-9999px' ;
100
+ document . body . appendChild ( tempDiv ) ;
101
+
102
+ // 获取 SVG 元素
103
+ const svgElement = tempDiv . querySelector ( 'svg' ) ;
104
+ if ( ! svgElement ) {
105
+ throw new Error ( 'No SVG element found' ) ;
106
+ }
107
+
108
+ // 设置 SVG 尺寸
109
+ const svgWidth = parseInt ( svgElement . getAttribute ( 'width' ) || '400' ) ;
110
+ const svgHeight = parseInt ( svgElement . getAttribute ( 'height' ) || '400' ) ;
123
111
124
- // Convert canvas to data URL
112
+ // 根据格式设置输出尺寸
113
+ let outputWidth = svgWidth * scale ;
114
+ let outputHeight = svgHeight * scale ;
115
+
116
+ if ( format === 'ico' ) {
117
+ outputWidth = icoSize ;
118
+ outputHeight = icoSize ;
119
+ }
120
+
121
+ // 使用 html2canvas 转换
122
+ const canvas = await html2canvas ( tempDiv , {
123
+ width : outputWidth ,
124
+ height : outputHeight ,
125
+ scale : 2 , // 提高输出质量
126
+ useCORS : true ,
127
+ backgroundColor : null ,
128
+ logging : false ,
129
+ } ) ;
130
+
131
+ // 转换为 data URL
125
132
const dataUrl = format === 'ico'
126
- ? canvas . toDataURL ( 'image/png' ) // ICO will be converted from PNG
133
+ ? canvas . toDataURL ( 'image/png' )
127
134
: canvas . toDataURL ( `image/${ format } ` ) ;
128
- setDataUrl ( dataUrl ) ;
129
135
130
- // Clean up
131
- URL . revokeObjectURL ( url ) ;
132
- } ;
133
-
134
- img . src = url ;
136
+ setDataUrl ( dataUrl ) ;
137
+
138
+ // 清理临时元素
139
+ document . body . removeChild ( tempDiv ) ;
140
+
141
+ } catch ( error ) {
142
+ console . error ( 'Error converting SVG:' , error ) ;
143
+ toast ( {
144
+ title : "转换失败" ,
145
+ description : "无法将 SVG 转换为目标格式" ,
146
+ variant : "destructive" ,
147
+ } ) ;
148
+ }
135
149
} ;
136
150
137
151
const handleDownloadImage = async ( ) => {
0 commit comments