embroidery-viewer/src/lib/file-renderer/index.js
2025-06-04 15:31:53 -03:00

141 lines
4.2 KiB
JavaScript

import { supportedFormats } from '$lib/format-readers';
import { jDataView } from './jdataview';
import { Pattern } from './pattern';
/**
* Render the embroidery pattern file to the provided canvas and update views.
* @param {string} filename - The name of the file.
* @param {ProgressEvent<FileReader>} evt - The file load event.
* @param {HTMLCanvasElement} canvas - Canvas to render the pattern.
* @param {HTMLElement} colorView - Element to display colors.
* @param {HTMLElement} stitchesView - Element to display stitch count.
* @param {HTMLElement} sizeView - Element to display size.
* @param {{stitches: string, dimensions: string}} localizedStrings - Localized labels.
*/
function renderFile(
filename,
evt,
canvas,
colorView,
stitchesView,
sizeView,
localizedStrings,
) {
const fileExtension = filename.toLowerCase().split('.').pop();
const arrayBuffer = evt.target?.result;
if (!(fileExtension && arrayBuffer)) {
throw new Error('Invalid file extension or file data');
}
const view = new jDataView(arrayBuffer, 0, evt.total || 0);
const pattern = new Pattern();
const formatReader = supportedFormats[fileExtension];
if (!formatReader || typeof formatReader.read !== 'function') {
throw new Error(`Unsupported file format: ${fileExtension}`);
}
// @ts-ignore
formatReader.read(view, pattern);
pattern.moveToPositive();
pattern.drawShapeTo(canvas);
pattern.drawColorsTo(colorView);
pattern.drawStitchesCountTo(stitchesView, localizedStrings.stitches);
pattern.drawSizeValuesTo(sizeView, localizedStrings.dimensions);
}
/**
* Display a generic abort message.
* @param {HTMLElement} errorMessageRef - Element to display the message.
*/
function renderAbortMessage(errorMessageRef) {
errorMessageRef.textContent = 'Render aborted!';
}
/**
* Display a detailed error message based on error type.
* @param {string} errorName - The name of the error.
* @param {HTMLElement} errorMessageRef - Element to display the message.
*/
function renderErrorMessage(errorName, errorMessageRef) {
/** @type {string} */
let message;
switch (errorName) {
case 'NotFoundError':
message =
'The file could not be found at the time the read was processed.';
break;
case 'SecurityError':
message =
'<p>A file security error occurred. This can be due to:</p>' +
'<ul>' +
'<li>Accessing certain files deemed unsafe for Web applications.</li>' +
'<li>Performing too many read calls on file resources.</li>' +
'<li>The file has changed on disk since the user selected it.</li>' +
'</ul>';
break;
case 'NotReadableError':
message =
'The file cannot be read. This can occur if the file is open in another application.';
break;
case 'EncodingError':
message = 'The length of the data URL for the file is too long.';
break;
default:
message = 'Something went wrong!';
break;
}
errorMessageRef.innerHTML = message;
}
/**
* Read a file and render its pattern to canvas with error handling.
* @param {File} fileObject - The file to read.
* @param {HTMLCanvasElement} canvas - The canvas to render on.
* @param {HTMLElement} errorMessageRef - Element to show error messages.
* @param {HTMLElement} colorView - Element to display colors.
* @param {HTMLElement} stitchesView - Element to display stitch count.
* @param {HTMLElement} sizeView - Element to display size.
* @param {{stitches: string, dimensions: string}} localizedStrings - Localized strings.
* @returns {string} Empty string after starting file read.
*/
export default function renderFileToCanvas(
fileObject,
canvas,
errorMessageRef,
colorView,
stitchesView,
sizeView,
localizedStrings,
) {
const reader = new FileReader();
reader.onloadend = (evt) =>
renderFile(
fileObject.name,
evt,
canvas,
colorView,
stitchesView,
sizeView,
localizedStrings,
);
reader.onabort = () => renderAbortMessage(errorMessageRef);
reader.onerror = (evt) =>
renderErrorMessage(
// @ts-ignore
evt.target.error?.name || 'UnknownError',
errorMessageRef,
);
if (fileObject) {
reader.readAsArrayBuffer(fileObject);
}
return '';
}