8000 allow converting SVG to PNG · ggml-org/llama.cpp@3458907 · GitHub
[go: up one dir, main page]

Skip to content

Commit 3458907

Browse files
committed
allow converting SVG to PNG
1 parent c2c2030 commit 3458907

File tree

2 files changed

+78
-3
lines changed

2 files changed

+78
-3
lines changed

tools/server/public/index.html.gz

127 Bytes
Binary file not shown.

tools/server/webui/src/components/useChatExtraContext.tsx

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,26 @@ export function useChatExtraContext(): ChatExtraContextApi {
3737
break;
3838
}
3939

40-
if (mimeType.startsWith('image/') && mimeType !== 'image/svg+xml') {
40+
if (mimeType.startsWith('image/')) {
4141
if (!serverProps?.modalities?.vision) {
4242
toast.error('Multimodal is not supported by this server or model.');
4343
break;
4444
}
4545
const reader = new FileReader();
46-
reader.onload = (event) => {
46+
reader.onload = async (event) => {
4747
if (event.target?.result) {
48+
let base64Url = event.target.result as string;
49+
50+
if (mimeType === 'image/svg+xml') {
51+
// Convert SVG to PNG
52+
base64Url = await svgBase64UrlToPngDataURL(base64Url);
53+
}
54+
4855
addItems([
4956
{
5057
type: 'imageFile',
5158
name: file.name,
52-
base64Url: event.target.result as string,
59+
base64Url,
5360
},
5461
]);
5562
}
@@ -172,3 +179,71 @@ export function isLikelyNotBinary(str: string): boolean {
172 8000 179
const ratio = suspiciousCharCount / sampleLength;
173180
return ratio <= options.suspiciousCharThresholdRatio;
174181
}
182+
183+
// WARN: vibe code below
184+
// Converts a Base64URL encoded SVG string to a PNG Data URL using browser Canvas API.
185+
function svgBase64UrlToPngDataURL(base64UrlSvg: string): Promise<string> {
186+
const backgroundColor = 'white'; // Default background color for PNG
187+
188+
return new Promise((resolve, reject) => {
189+
try {
190+
// 1. Convert Base64URL to standard Base64, then decode to SVG string
191+
let base64 = base64UrlSvg
192+
.split(',')
193+
.pop()!
194+
.replace(/-/g, '+')
195+
.replace(/_/g, '/');
196+
const padding = base64.length % 4;
197+
if (padding) {
198+
base64 += '='.repeat(4 - padding);
199+
}
200+
const svgString = atob(base64);
201+
202+
const img = new Image();
203+
204+
img.onload = () => {
205+
const canvas = document.createElement('canvas');
206+
const ctx = canvas.getContext('2d');
207+
208+
if (!ctx) {
209+
reject(new Error('Failed to get 2D canvas context.'));
210+
return;
211+
}
212+
213+
// Use provided dimensions or SVG's natural dimensions, with fallbacks
214+
// Fallbacks (e.g., 300x300) are for SVGs without explicit width/height
215+
// or when naturalWidth/Height might be 0 before full processing.
216+
const targetWidth = img.naturalWidth || 300;
217+
const targetHeight = img.naturalHeight || 300;
218+
219+
canvas.width = targetWidth;
220+
canvas.height = targetHeight;
221+
222+
if (backgroundColor) {
223+
ctx.fillStyle = backgroundColor;
224+
ctx.fillRect(0, 0, canvas.width, canvas.height);
225+
}
226+
227+
ctx.drawImage(img, 0, 0, targetWidth, targetHeight);
228+
resolve(canvas.toDataURL('image/png'));
229+
};
230+
231+
img.onerror = () => {
232+
reject(
233+
new Error('Failed to load SVG image. Ensure the SVG data is valid.')
234+
);
235+
};
236+
237+
// 2. Load SVG string into an Image element.
238+
// The SVG string must be re-encoded to standard Base64 for the data URL.
239+
// Alternatively, for non-Base64 SVG in data URL:
240+
// img.src = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(svgString);
241+
img.src = 'data:image/svg+xml;base64,' + btoa(svgString);
242+
} catch (error) {
243+
const message = error instanceof Error ? error.message : String(error);
244+
const errorMessage = `Error converting SVG to PNG: ${message}`;
245+
toast.error(errorMessage);
246+
reject(new Error(errorMessage));
247+
}
248+
});
249+
}

0 commit comments

Comments
 (0)
0