tokimeki-image-editor 0.4.4 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import '../styles/tokens.css';
|
|
3
3
|
import { _ } from 'svelte-i18n';
|
|
4
4
|
import { Redo2, Undo2, RotateCcw, ImagePlus, Check, Sparkles, Download, LoaderCircle } from 'lucide-svelte';
|
|
5
|
-
import { createEditorState, loadImageFromFile, loadImageFromUrl, applyImageToState, setMode, applyCrop, applyTransformUpdate, applyAdjustmentsUpdate, applyFilter, setBlurAreas, setStampAreas, setAnnotations, setViewport, resetState, handleZoom as coreHandleZoom, saveToHistory as coreSaveToHistory, handleUndo as coreHandleUndo, handleRedo as coreHandleRedo, canUndo, canRedo, getKeyboardAction, applyKeyboardAction, exportImage,
|
|
6
|
-
import { calculateFitScale } from '../utils/canvas';
|
|
5
|
+
import { createEditorState, loadImageFromFile, loadImageFromUrl, applyImageToState, setMode, applyCrop, applyTransformUpdate, applyAdjustmentsUpdate, applyFilter, setBlurAreas, setStampAreas, setAnnotations, setViewport, resetState, handleZoom as coreHandleZoom, saveToHistory as coreSaveToHistory, handleUndo as coreHandleUndo, handleRedo as coreHandleRedo, canUndo, canRedo, getKeyboardAction, applyKeyboardAction, exportImage, getDroppedFile, getInputFile, handleDragOver } from '../utils/editor-core';
|
|
6
|
+
import { calculateFitScale, downloadImage } from '../utils/canvas';
|
|
7
7
|
import { haptic } from '../utils/haptics';
|
|
8
8
|
import BottomDock from './BottomDock.svelte';
|
|
9
9
|
import IconButton from './IconButton.svelte';
|
|
@@ -180,9 +180,12 @@ function handleAnnotationsChange(annotations) {
|
|
|
180
180
|
}
|
|
181
181
|
async function handleExport() {
|
|
182
182
|
haptic('success');
|
|
183
|
-
await downloadExportedImage(state);
|
|
184
183
|
const result = await exportImage(state);
|
|
185
|
-
if (result
|
|
184
|
+
if (!result)
|
|
185
|
+
return;
|
|
186
|
+
const filename = `edited-image-${Date.now()}.${state.exportOptions.format}`;
|
|
187
|
+
downloadImage(result.dataUrl, filename);
|
|
188
|
+
if (onExport)
|
|
186
189
|
onExport(result.dataUrl);
|
|
187
190
|
}
|
|
188
191
|
async function handleComplete() {
|
|
@@ -131,10 +131,6 @@ export interface ExportResult {
|
|
|
131
131
|
* Export editor state to image
|
|
132
132
|
*/
|
|
133
133
|
export declare function exportImage(state: EditorState): Promise<ExportResult | null>;
|
|
134
|
-
/**
|
|
135
|
-
* Download exported image
|
|
136
|
-
*/
|
|
137
|
-
export declare function downloadExportedImage(state: EditorState): Promise<void>;
|
|
138
134
|
/**
|
|
139
135
|
* Add a new annotation to state
|
|
140
136
|
*/
|
|
@@ -352,29 +352,23 @@ export async function exportImage(state) {
|
|
|
352
352
|
return null;
|
|
353
353
|
const exportCanvas = await applyTransformWithWebGPU(state.imageData.original, state.transform, state.adjustments, state.cropArea, state.blurAreas, state.stampAreas, state.annotations);
|
|
354
354
|
const format = state.exportOptions.format === 'jpeg' ? 'image/jpeg' : 'image/png';
|
|
355
|
-
|
|
355
|
+
// Single async encode (toBlob) — avoids synchronous toDataURL blocking the main thread
|
|
356
356
|
const blob = await new Promise((resolve) => {
|
|
357
357
|
exportCanvas.toBlob(b => resolve(b), format, state.exportOptions.quality);
|
|
358
358
|
});
|
|
359
|
-
|
|
360
|
-
const
|
|
359
|
+
// Convert blob to data URL without re-encoding (just base64-wraps the existing bytes)
|
|
360
|
+
const dataUrl = await new Promise((resolve) => {
|
|
361
|
+
const reader = new FileReader();
|
|
362
|
+
reader.onload = () => resolve(reader.result);
|
|
363
|
+
reader.readAsDataURL(blob);
|
|
364
|
+
});
|
|
365
|
+
// Dimensions directly from the export canvas (already crop+rotation adjusted)
|
|
366
|
+
return {
|
|
361
367
|
dataUrl,
|
|
362
368
|
blob,
|
|
363
|
-
width:
|
|
364
|
-
height:
|
|
369
|
+
width: exportCanvas.width,
|
|
370
|
+
height: exportCanvas.height
|
|
365
371
|
};
|
|
366
|
-
bitmap.close();
|
|
367
|
-
return result;
|
|
368
|
-
}
|
|
369
|
-
/**
|
|
370
|
-
* Download exported image
|
|
371
|
-
*/
|
|
372
|
-
export async function downloadExportedImage(state) {
|
|
373
|
-
const result = await exportImage(state);
|
|
374
|
-
if (!result)
|
|
375
|
-
return;
|
|
376
|
-
const filename = `edited-image-${Date.now()}.${state.exportOptions.format}`;
|
|
377
|
-
downloadImage(result.dataUrl, filename);
|
|
378
372
|
}
|
|
379
373
|
// ============================================================================
|
|
380
374
|
// ANNOTATION HELPERS (for QuickDrawEditor)
|