Initial commit

This commit is contained in:
Leonardo Murça 2022-11-10 17:46:23 -03:00
commit a950194247
18 changed files with 2670 additions and 0 deletions

24
.gitignore vendored Normal file
View file

@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

3
.vscode/extensions.json vendored Normal file
View file

@ -0,0 +1,3 @@
{
"recommendations": ["svelte.svelte-vscode"]
}

47
README.md Normal file
View file

@ -0,0 +1,47 @@
# Svelte + Vite
This template should help get you started developing with Svelte in Vite.
## Recommended IDE Setup
[VS Code](https://code.visualstudio.com/) + [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode).
## Need an official Svelte framework?
Check out [SvelteKit](https://github.com/sveltejs/kit#readme), which is also powered by Vite. Deploy anywhere with its serverless-first approach and adapt to various platforms, with out of the box support for TypeScript, SCSS, and Less, and easily-added support for mdsvex, GraphQL, PostCSS, Tailwind CSS, and more.
## Technical considerations
**Why use this over SvelteKit?**
- It brings its own routing solution which might not be preferable for some users.
- It is first and foremost a framework that just happens to use Vite under the hood, not a Vite app.
This template contains as little as possible to get started with Vite + Svelte, while taking into account the developer experience with regards to HMR and intellisense. It demonstrates capabilities on par with the other `create-vite` templates and is a good starting point for beginners dipping their toes into a Vite + Svelte project.
Should you later need the extended capabilities and extensibility provided by SvelteKit, the template has been structured similarly to SvelteKit so that it is easy to migrate.
**Why `global.d.ts` instead of `compilerOptions.types` inside `jsconfig.json` or `tsconfig.json`?**
Setting `compilerOptions.types` shuts out all other types not explicitly listed in the configuration. Using triple-slash references keeps the default TypeScript setting of accepting type information from the entire workspace, while also adding `svelte` and `vite/client` type information.
**Why include `.vscode/extensions.json`?**
Other templates indirectly recommend extensions via the README, but this file allows VS Code to prompt the user to install the recommended extension upon opening the project.
**Why enable `checkJs` in the JS template?**
It is likely that most cases of changing variable types in runtime are likely to be accidental, rather than deliberate. This provides advanced typechecking out of the box. Should you like to take advantage of the dynamically-typed nature of JavaScript, it is trivial to change the configuration.
**Why is HMR not preserving my local component state?**
HMR state preservation comes with a number of gotchas! It has been disabled by default in both `svelte-hmr` and `@sveltejs/vite-plugin-svelte` due to its often surprising behavior. You can read the details [here](https://github.com/rixo/svelte-hmr#svelte-hmr).
If you have state that's important to retain within a component, consider creating an external store which would not be replaced by HMR.
```js
// store.js
// An extremely simple external store
import { writable } from 'svelte/store'
export default writable(0)
```

25
index.html Normal file
View file

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8" />
<meta name="description" content="Free online embroidery files viewer." />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="author" content="Leonardo Murça" />
<meta property="og:locale" content="en-us">
<meta property="og:type" content="website">
<meta property="og:title" content="Embroidery Viewer">
<meta property="og:description" content="Free online embroidery files viewer." />
<meta property="og:url" content="https://embroideryviewer.xyz/">
<meta property="og:site_name" content="Embroidery Viewer">
<title>Embroidery Viewer</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

33
jsconfig.json Normal file
View file

@ -0,0 +1,33 @@
{
"compilerOptions": {
"moduleResolution": "Node",
"target": "ESNext",
"module": "ESNext",
/**
* svelte-preprocess cannot figure out whether you have
* a value or a type, so tell TypeScript to enforce using
* `import type` instead of `import` for Types.
*/
"importsNotUsedAsValues": "error",
"isolatedModules": true,
"resolveJsonModule": true,
/**
* To have warnings / errors of the Svelte compiler at the
* correct position, enable source maps by default.
*/
"sourceMap": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
/**
* Typecheck JS in `.svelte` and `.js` files by default.
* Disable this if you'd like to use dynamic types.
*/
"checkJs": true
},
/**
* Use global.d.ts instead of compilerOptions.types
* to avoid limiting type declarations.
*/
"include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.svelte"]
}

1078
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

19
package.json Normal file
View file

@ -0,0 +1,19 @@
{
"name": "embroidery-viewer",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^1.1.0",
"svelte": "^3.52.0",
"vite": "^3.2.3"
},
"dependencies": {
"jdataview": "^2.5.0"
}
}

1
public/vite.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

22
src/App.svelte Normal file
View file

@ -0,0 +1,22 @@
<script>
import Counter from './lib/Counter.svelte'
</script>
<header>
<h1>Embroidery Viewer</h1>
</header>
<main>
<Counter />
</main>
<footer>
<p>Copyright © 2022 Leonardo Murça.</p>
</footer>
<style>
main {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
}
</style>

29
src/app.css Normal file
View file

@ -0,0 +1,29 @@
:root {
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
font-size: 16px;
line-height: 24px;
font-weight: 400;
font-synthesis: none;
text-rendering: optimizeLegibility;
background-color: #f4f4f4;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
}
body {
display: flex;
justify-content: center;
margin: 0;
width: 100%;
min-height: 100vh;
}
#app {
display: flex;
flex-direction: column;
align-items: center;
width: 80%;
background-color: #e5e5e5;
z-index: 10;
}

143
src/lib/Counter.svelte Normal file
View file

@ -0,0 +1,143 @@
<script>
import { startFileRead } from './main';
let files;
const acceptedFiles = [".pes"];
const maxFileSize = 700000;
function onSubmitHandler(evt) {
evt.stopPropagation();
evt.preventDefault();
for (var i = 0, file; (file = files[i]); i++) {
const canvasContainer = document.getElementById("canvas-container")
const canvasCard = document.createElement(`div`)
const canvasEl = document.createElement(`canvas`)
const fileNameEl = document.createElement(`p`)
canvasCard.id = `canvas-card-${i}`
canvasCard.style['display'] = "flex"
canvasCard.style['flex-direction'] = "column"
canvasCard.style['justify-content'] = "center"
canvasCard.style['align-items'] = "center"
canvasCard.style['width'] = "550px"
canvasCard.style['height'] = "550px"
canvasCard.style['margin-bottom'] = "15px"
canvasCard.style['border'] = "2px solid black"
canvasEl.id = `mycanvas-${i}`
canvasEl.style["height"] = "80%";
canvasEl.style["width"] = "fit-content";
fileNameEl.textContent = file.name
canvasCard.appendChild(canvasEl)
canvasCard.appendChild(fileNameEl)
canvasContainer.appendChild(canvasCard)
if (file) {
startFileRead(file, canvasEl);
}
}
}
function handleDragOver(evt) {
evt.stopPropagation();
evt.preventDefault();
}
function onDropHandler(evt) {
evt.stopPropagation();
evt.preventDefault();
onChangeFileHandler(evt)
}
function onChangeFileHandler(evt) {
const changedFiles = evt.dataTransfer ? evt.dataTransfer.files : evt.target.files;
let filesToUpload = [];
for (var i = 0, file; (file = changedFiles[i]); i++) {
if (file) {
if (file.size <= maxFileSize) {
filesToUpload.push(file);
} else {
console.log("File too large!")
console.log(file)
}
}
}
files = filesToUpload
}
function handleOnClick(evt) {
document.getElementById("file-input").click();
}
function handleOnKeydown(evt) {
console.log(evt)
}
</script>
<form
on:submit={onSubmitHandler}
id="form"
action="#"
enctype="multipart/form-data">
<h2>Upload files</h2>
<p>Max file size is <strong>{maxFileSize/1000}kb</strong>. Accepted formats: <strong>{acceptedFiles.join(",")}</strong>.</p>
<div id="dropzone" on:keydown={handleOnKeydown} on:click={handleOnClick} on:dragover={handleDragOver} on:drop={onDropHandler}>
<label id="file-label" for="file-input">Drag and drop files here or click to upload.</label>
<input id="file-input" type="file" name="files[]" accept={acceptedFiles.join(",")} multiple on:change={onChangeFileHandler} />
</div>
<input type="submit" value="Render files">
</form>
<div id="canvas-container" style="width: 100%; heigth: 100vh;"></div>
<style>
input[type="submit"] {
width: 100%;
font-size: 30px;
margin-top: 20px;
}
input[type="submit"]:hover {
cursor: pointer;
background-color: black;
color: white;
}
#dropzone {
display: flex;
height: 100px;
width: 500px;
border: 5px dotted black;
padding: 15px;
z-index: 10;
}
#file-label {
z-index: -1;
font-weight: 600;
}
#file-input {
display: none;
}
#canvas-container {
display: flex;
width: 100%;
justify-content: space-evenly;
flex-wrap: wrap;
}
#dropzone:hover {
cursor: pointer;
border: 5px dotted #7FB77E;
color: #7FB77E;
}
</style>

848
src/lib/jdataview.js Normal file
View file

@ -0,0 +1,848 @@
// @ts-nocheck
//
// jDataView by Vjeux <vjeuxx@gmail.com> - Jan 2010
// Continued by RReverser <me@rreverser.com> - Feb 2013
//
// A unique way to work with a binary file in the browser
// http://github.com/jDataView/jDataView
// http://jDataView.github.io/
var compatibility = {
// NodeJS Buffer in v0.5.5 and newer
NodeBuffer: "Buffer" in globalThis && "readInt16LE" in Buffer.prototype,
DataView:
"DataView" in globalThis &&
("getFloat64" in DataView.prototype || // Chrome
"getFloat64" in new DataView(new ArrayBuffer(1))), // Node
ArrayBuffer: "ArrayBuffer" in globalThis,
PixelData:
"CanvasPixelArray" in globalThis &&
"ImageData" in globalThis &&
"document" in globalThis,
};
var createPixelData = function (byteLength, buffer) {
var data = createPixelData.context2d.createImageData(
(byteLength + 3) / 4,
1
).data;
data.byteLength = byteLength;
if (buffer !== undefined) {
for (var i = 0; i < byteLength; i++) {
data[i] = buffer[i];
}
}
return data;
};
createPixelData.context2d = document.createElement("canvas").getContext("2d");
var dataTypes = {
Int8: 1,
Int16: 2,
Int32: 4,
Uint8: 1,
Uint16: 2,
Uint32: 4,
Float32: 4,
Float64: 8,
};
var nodeNaming = {
Int8: "Int8",
Int16: "Int16",
Int32: "Int32",
Uint8: "UInt8",
Uint16: "UInt16",
Uint32: "UInt32",
Float32: "Float",
Float64: "Double",
};
function arrayFrom(arrayLike, forceCopy) {
return !forceCopy && arrayLike instanceof Array
? arrayLike
: Array.prototype.slice.call(arrayLike);
}
function defined(value, defaultValue) {
return value !== undefined ? value : defaultValue;
}
export function jDataView(buffer, byteOffset, byteLength, littleEndian) {
/* jshint validthis:true */
if (buffer instanceof jDataView) {
var result = buffer.slice(byteOffset, byteOffset + byteLength);
result._littleEndian = defined(littleEndian, result._littleEndian);
return result;
}
if (!(this instanceof jDataView)) {
return new jDataView(buffer, byteOffset, byteLength, littleEndian);
}
this.buffer = buffer = jDataView.wrapBuffer(buffer);
// Check parameters and existing functionnalities
this._isArrayBuffer =
compatibility.ArrayBuffer && buffer instanceof ArrayBuffer;
this._isPixelData =
compatibility.PixelData && buffer instanceof CanvasPixelArray;
this._isDataView = compatibility.DataView && this._isArrayBuffer;
this._isNodeBuffer = compatibility.NodeBuffer && buffer instanceof Buffer;
// Handle Type Errors
if (
!this._isNodeBuffer &&
!this._isArrayBuffer &&
!this._isPixelData &&
!(buffer instanceof Array)
) {
throw new TypeError("jDataView buffer has an incompatible type");
}
// Default Values
this._littleEndian = !!littleEndian;
var bufferLength = "byteLength" in buffer ? buffer.byteLength : buffer.length;
this.byteOffset = byteOffset = defined(byteOffset, 0);
this.byteLength = byteLength = defined(byteLength, bufferLength - byteOffset);
if (!this._isDataView) {
this._checkBounds(byteOffset, byteLength, bufferLength);
} else {
this._view = new DataView(buffer, byteOffset, byteLength);
}
// Create uniform methods (action wrappers) for the following data types
this._engineAction = this._isDataView
? this._dataViewAction
: this._isNodeBuffer
? this._nodeBufferAction
: this._isArrayBuffer
? this._arrayBufferAction
: this._arrayAction;
}
function getCharCodes(string) {
if (compatibility.NodeBuffer) {
return new Buffer(string, "binary");
}
var Type = compatibility.ArrayBuffer ? Uint8Array : Array,
codes = new Type(string.length);
for (var i = 0, length = string.length; i < length; i++) {
codes[i] = string.charCodeAt(i) & 0xff;
}
return codes;
}
// mostly internal function for wrapping any supported input (String or Array-like) to best suitable buffer format
jDataView.wrapBuffer = function (buffer) {
switch (typeof buffer) {
case "number":
if (compatibility.NodeBuffer) {
buffer = new Buffer(buffer);
buffer.fill(0);
} else if (compatibility.ArrayBuffer) {
buffer = new Uint8Array(buffer).buffer;
} else if (compatibility.PixelData) {
buffer = createPixelData(buffer);
} else {
buffer = new Array(buffer);
for (var i = 0; i < buffer.length; i++) {
buffer[i] = 0;
}
}
return buffer;
case "string":
buffer = getCharCodes(buffer);
/* falls through */
default:
if (
"length" in buffer &&
!(
(compatibility.NodeBuffer && buffer instanceof Buffer) ||
(compatibility.ArrayBuffer && buffer instanceof ArrayBuffer) ||
(compatibility.PixelData && buffer instanceof CanvasPixelArray)
)
) {
if (compatibility.NodeBuffer) {
buffer = new Buffer(buffer);
} else if (compatibility.ArrayBuffer) {
if (!(buffer instanceof ArrayBuffer)) {
buffer = new Uint8Array(buffer).buffer;
// bug in Node.js <= 0.8:
if (!(buffer instanceof ArrayBuffer)) {
buffer = new Uint8Array(arrayFrom(buffer, true)).buffer;
}
}
} else if (compatibility.PixelData) {
buffer = createPixelData(buffer.length, buffer);
} else {
buffer = arrayFrom(buffer);
}
}
return buffer;
}
};
function pow2(n) {
return n >= 0 && n < 31 ? 1 << n : pow2[n] || (pow2[n] = Math.pow(2, n));
}
// left for backward compatibility
jDataView.createBuffer = function () {
return jDataView.wrapBuffer(arguments);
};
function Uint64(lo, hi) {
this.lo = lo;
this.hi = hi;
}
jDataView.Uint64 = Uint64;
Uint64.prototype = {
valueOf: function () {
return this.lo + pow2(32) * this.hi;
},
toString: function () {
return Number.prototype.toString.apply(this.valueOf(), arguments);
},
};
Uint64.fromNumber = function (number) {
var hi = Math.floor(number / pow2(32)),
lo = number - hi * pow2(32);
return new Uint64(lo, hi);
};
function Int64(lo, hi) {
Uint64.apply(this, arguments);
}
jDataView.Int64 = Int64;
Int64.prototype =
"create" in Object ? Object.create(Uint64.prototype) : new Uint64();
Int64.prototype.valueOf = function () {
if (this.hi < pow2(31)) {
return Uint64.prototype.valueOf.apply(this, arguments);
}
return -(pow2(32) - this.lo + pow2(32) * (pow2(32) - 1 - this.hi));
};
Int64.fromNumber = function (number) {
var lo, hi;
if (number >= 0) {
var unsigned = Uint64.fromNumber(number);
lo = unsigned.lo;
hi = unsigned.hi;
} else {
hi = Math.floor(number / pow2(32));
lo = number - hi * pow2(32);
hi += pow2(32);
}
return new Int64(lo, hi);
};
jDataView.prototype = {
_offset: 0,
_bitOffset: 0,
compatibility: compatibility,
_checkBounds: function (byteOffset, byteLength, maxLength) {
// Do additional checks to simulate DataView
if (typeof byteOffset !== "number") {
throw new TypeError("Offset is not a number.");
}
if (typeof byteLength !== "number") {
throw new TypeError("Size is not a number.");
}
if (byteLength < 0) {
throw new RangeError("Length is negative.");
}
if (
byteOffset < 0 ||
byteOffset + byteLength > defined(maxLength, this.byteLength)
) {
throw new RangeError("Offsets are out of bounds.");
}
},
_action: function (type, isReadAction, byteOffset, littleEndian, value) {
return this._engineAction(
type,
isReadAction,
defined(byteOffset, this._offset),
defined(littleEndian, this._littleEndian),
value
);
},
_dataViewAction: function (
type,
isReadAction,
byteOffset,
littleEndian,
value
) {
// Move the internal offset forward
this._offset = byteOffset + dataTypes[type];
return isReadAction
? this._view["get" + type](byteOffset, littleEndian)
: this._view["set" + type](byteOffset, value, littleEndian);
},
_nodeBufferAction: function (
type,
isReadAction,
byteOffset,
littleEndian,
value
) {
// Move the internal offset forward
this._offset = byteOffset + dataTypes[type];
var nodeName =
nodeNaming[type] +
(type === "Int8" || type === "Uint8" ? "" : littleEndian ? "LE" : "BE");
byteOffset += this.byteOffset;
return isReadAction
? this.buffer["read" + nodeName](byteOffset)
: this.buffer["write" + nodeName](value, byteOffset);
},
_arrayBufferAction: function (
type,
isReadAction,
byteOffset,
littleEndian,
value
) {
var size = dataTypes[type],
TypedArray = globalThis[type + "Array"],
typedArray;
littleEndian = defined(littleEndian, this._littleEndian);
// ArrayBuffer: we use a typed array of size 1 from original buffer if alignment is good and from slice when it's not
if (
size === 1 ||
((this.byteOffset + byteOffset) % size === 0 && littleEndian)
) {
typedArray = new TypedArray(this.buffer, this.byteOffset + byteOffset, 1);
this._offset = byteOffset + size;
return isReadAction ? typedArray[0] : (typedArray[0] = value);
} else {
var bytes = new Uint8Array(
isReadAction
? this.getBytes(size, byteOffset, littleEndian, true)
: size
);
typedArray = new TypedArray(bytes.buffer, 0, 1);
if (isReadAction) {
return typedArray[0];
} else {
typedArray[0] = value;
this._setBytes(byteOffset, bytes, littleEndian);
}
}
},
_arrayAction: function (type, isReadAction, byteOffset, littleEndian, value) {
return isReadAction
? this["_get" + type](byteOffset, littleEndian)
: this["_set" + type](byteOffset, value, littleEndian);
},
// Helpers
_getBytes: function (length, byteOffset, littleEndian) {
littleEndian = defined(littleEndian, this._littleEndian);
byteOffset = defined(byteOffset, this._offset);
length = defined(length, this.byteLength - byteOffset);
this._checkBounds(byteOffset, length);
byteOffset += this.byteOffset;
this._offset = byteOffset - this.byteOffset + length;
var result = this._isArrayBuffer
? new Uint8Array(this.buffer, byteOffset, length)
: (this.buffer.slice || Array.prototype.slice).call(
this.buffer,
byteOffset,
byteOffset + length
);
return littleEndian || length <= 1 ? result : arrayFrom(result).reverse();
},
// wrapper for external calls (do not return inner buffer directly to prevent it's modifying)
getBytes: function (length, byteOffset, littleEndian, toArray) {
var result = this._getBytes(
length,
byteOffset,
defined(littleEndian, true)
);
return toArray ? arrayFrom(result) : result;
},
_setBytes: function (byteOffset, bytes, littleEndian) {
var length = bytes.length;
// needed for Opera
if (length === 0) {
return;
}
littleEndian = defined(littleEndian, this._littleEndian);
byteOffset = defined(byteOffset, this._offset);
this._checkBounds(byteOffset, length);
if (!littleEndian && length > 1) {
bytes = arrayFrom(bytes, true).reverse();
}
byteOffset += this.byteOffset;
if (this._isArrayBuffer) {
new Uint8Array(this.buffer, byteOffset, length).set(bytes);
} else {
if (this._isNodeBuffer) {
new Buffer(bytes).copy(this.buffer, byteOffset);
} else {
for (var i = 0; i < length; i++) {
this.buffer[byteOffset + i] = bytes[i];
}
}
}
this._offset = byteOffset - this.byteOffset + length;
},
setBytes: function (byteOffset, bytes, littleEndian) {
this._setBytes(byteOffset, bytes, defined(littleEndian, true));
},
getString: function (byteLength, byteOffset, encoding) {
if (this._isNodeBuffer) {
byteOffset = defined(byteOffset, this._offset);
byteLength = defined(byteLength, this.byteLength - byteOffset);
this._checkBounds(byteOffset, byteLength);
this._offset = byteOffset + byteLength;
return this.buffer.toString(
encoding || "binary",
this.byteOffset + byteOffset,
this.byteOffset + this._offset
);
}
var bytes = this._getBytes(byteLength, byteOffset, true),
string = "";
byteLength = bytes.length;
for (var i = 0; i < byteLength; i++) {
string += String.fromCharCode(bytes[i]);
}
if (encoding === "utf8") {
string = decodeURIComponent(escape(string));
}
return string;
},
setString: function (byteOffset, subString, encoding) {
if (this._isNodeBuffer) {
byteOffset = defined(byteOffset, this._offset);
this._checkBounds(byteOffset, subString.length);
this._offset =
byteOffset +
this.buffer.write(
subString,
this.byteOffset + byteOffset,
encoding || "binary"
);
return;
}
if (encoding === "utf8") {
subString = unescape(encodeURIComponent(subString));
}
this._setBytes(byteOffset, getCharCodes(subString), true);
},
getChar: function (byteOffset) {
return this.getString(1, byteOffset);
},
setChar: function (byteOffset, character) {
this.setString(byteOffset, character);
},
tell: function () {
return this._offset;
},
seek: function (byteOffset) {
this._checkBounds(byteOffset, 0);
/* jshint boss: true */
return (this._offset = byteOffset);
},
skip: function (byteLength) {
return this.seek(this._offset + byteLength);
},
slice: function (start, end, forceCopy) {
function normalizeOffset(offset, byteLength) {
return offset < 0 ? offset + byteLength : offset;
}
start = normalizeOffset(start, this.byteLength);
end = normalizeOffset(defined(end, this.byteLength), this.byteLength);
return forceCopy
? new jDataView(
this.getBytes(end - start, start, true, true),
undefined,
undefined,
this._littleEndian
)
: new jDataView(
this.buffer,
this.byteOffset + start,
end - start,
this._littleEndian
);
},
alignBy: function (byteCount) {
this._bitOffset = 0;
if (defined(byteCount, 1) !== 1) {
return this.skip(byteCount - (this._offset % byteCount || byteCount));
} else {
return this._offset;
}
},
// Compatibility functions
_getFloat64: function (byteOffset, littleEndian) {
var b = this._getBytes(8, byteOffset, littleEndian),
sign = 1 - 2 * (b[7] >> 7),
exponent = ((((b[7] << 1) & 0xff) << 3) | (b[6] >> 4)) - ((1 << 10) - 1),
// Binary operators such as | and << operate on 32 bit values, using + and Math.pow(2) instead
mantissa =
(b[6] & 0x0f) * pow2(48) +
b[5] * pow2(40) +
b[4] * pow2(32) +
b[3] * pow2(24) +
b[2] * pow2(16) +
b[1] * pow2(8) +
b[0];
if (exponent === 1024) {
if (mantissa !== 0) {
return NaN;
} else {
return sign * Infinity;
}
}
if (exponent === -1023) {
// Denormalized
return sign * mantissa * pow2(-1022 - 52);
}
return sign * (1 + mantissa * pow2(-52)) * pow2(exponent);
},
_getFloat32: function (byteOffset, littleEndian) {
var b = this._getBytes(4, byteOffset, littleEndian),
sign = 1 - 2 * (b[3] >> 7),
exponent = (((b[3] << 1) & 0xff) | (b[2] >> 7)) - 127,
mantissa = ((b[2] & 0x7f) << 16) | (b[1] << 8) | b[0];
if (exponent === 128) {
if (mantissa !== 0) {
return NaN;
} else {
return sign * Infinity;
}
}
if (exponent === -127) {
// Denormalized
return sign * mantissa * pow2(-126 - 23);
}
return sign * (1 + mantissa * pow2(-23)) * pow2(exponent);
},
_get64: function (Type, byteOffset, littleEndian) {
littleEndian = defined(littleEndian, this._littleEndian);
byteOffset = defined(byteOffset, this._offset);
var parts = littleEndian ? [0, 4] : [4, 0];
for (var i = 0; i < 2; i++) {
parts[i] = this.getUint32(byteOffset + parts[i], littleEndian);
}
this._offset = byteOffset + 8;
return new Type(parts[0], parts[1]);
},
getInt64: function (byteOffset, littleEndian) {
return this._get64(Int64, byteOffset, littleEndian);
},
getUint64: function (byteOffset, littleEndian) {
return this._get64(Uint64, byteOffset, littleEndian);
},
_getInt32: function (byteOffset, littleEndian) {
var b = this._getBytes(4, byteOffset, littleEndian);
return (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0];
},
_getUint32: function (byteOffset, littleEndian) {
return this._getInt32(byteOffset, littleEndian) >>> 0;
},
_getInt16: function (byteOffset, littleEndian) {
return (this._getUint16(byteOffset, littleEndian) << 16) >> 16;
},
_getUint16: function (byteOffset, littleEndian) {
var b = this._getBytes(2, byteOffset, littleEndian);
return (b[1] << 8) | b[0];
},
_getInt8: function (byteOffset) {
return (this._getUint8(byteOffset) << 24) >> 24;
},
_getUint8: function (byteOffset) {
return this._getBytes(1, byteOffset)[0];
},
_getBitRangeData: function (bitLength, byteOffset) {
var startBit = (defined(byteOffset, this._offset) << 3) + this._bitOffset,
endBit = startBit + bitLength,
start = startBit >>> 3,
end = (endBit + 7) >>> 3,
b = this._getBytes(end - start, start, true),
wideValue = 0;
/* jshint boss: true */
if ((this._bitOffset = endBit & 7)) {
this._bitOffset -= 8;
}
for (var i = 0, length = b.length; i < length; i++) {
wideValue = (wideValue << 8) | b[i];
}
return {
start: start,
bytes: b,
wideValue: wideValue,
};
},
getSigned: function (bitLength, byteOffset) {
var shift = 32 - bitLength;
return (this.getUnsigned(bitLength, byteOffset) << shift) >> shift;
},
getUnsigned: function (bitLength, byteOffset) {
var value =
this._getBitRangeData(bitLength, byteOffset).wideValue >>>
-this._bitOffset;
return bitLength < 32 ? value & ~(-1 << bitLength) : value;
},
_setBinaryFloat: function (
byteOffset,
value,
mantSize,
expSize,
littleEndian
) {
var signBit = value < 0 ? 1 : 0,
exponent,
mantissa,
eMax = ~(-1 << (expSize - 1)),
eMin = 1 - eMax;
if (value < 0) {
value = -value;
}
if (value === 0) {
exponent = 0;
mantissa = 0;
} else if (isNaN(value)) {
exponent = 2 * eMax + 1;
mantissa = 1;
} else if (value === Infinity) {
exponent = 2 * eMax + 1;
mantissa = 0;
} else {
exponent = Math.floor(Math.log(value) / Math.LN2);
if (exponent >= eMin && exponent <= eMax) {
mantissa = Math.floor((value * pow2(-exponent) - 1) * pow2(mantSize));
exponent += eMax;
} else {
mantissa = Math.floor(value / pow2(eMin - mantSize));
exponent = 0;
}
}
var b = [];
while (mantSize >= 8) {
b.push(mantissa % 256);
mantissa = Math.floor(mantissa / 256);
mantSize -= 8;
}
exponent = (exponent << mantSize) | mantissa;
expSize += mantSize;
while (expSize >= 8) {
b.push(exponent & 0xff);
exponent >>>= 8;
expSize -= 8;
}
b.push((signBit << expSize) | exponent);
this._setBytes(byteOffset, b, littleEndian);
},
_setFloat32: function (byteOffset, value, littleEndian) {
this._setBinaryFloat(byteOffset, value, 23, 8, littleEndian);
},
_setFloat64: function (byteOffset, value, littleEndian) {
this._setBinaryFloat(byteOffset, value, 52, 11, littleEndian);
},
_set64: function (Type, byteOffset, value, littleEndian) {
if (!(value instanceof Type)) {
value = Type.fromNumber(value);
}
littleEndian = defined(littleEndian, this._littleEndian);
byteOffset = defined(byteOffset, this._offset);
var parts = littleEndian ? { lo: 0, hi: 4 } : { lo: 4, hi: 0 };
for (var partName in parts) {
this.setUint32(
byteOffset + parts[partName],
value[partName],
littleEndian
);
}
this._offset = byteOffset + 8;
},
setInt64: function (byteOffset, value, littleEndian) {
this._set64(Int64, byteOffset, value, littleEndian);
},
setUint64: function (byteOffset, value, littleEndian) {
this._set64(Uint64, byteOffset, value, littleEndian);
},
_setUint32: function (byteOffset, value, littleEndian) {
this._setBytes(
byteOffset,
[value & 0xff, (value >>> 8) & 0xff, (value >>> 16) & 0xff, value >>> 24],
littleEndian
);
},
_setUint16: function (byteOffset, value, littleEndian) {
this._setBytes(
byteOffset,
[value & 0xff, (value >>> 8) & 0xff],
littleEndian
);
},
_setUint8: function (byteOffset, value) {
this._setBytes(byteOffset, [value & 0xff]);
},
setUnsigned: function (byteOffset, value, bitLength) {
var data = this._getBitRangeData(bitLength, byteOffset),
wideValue = data.wideValue,
b = data.bytes;
wideValue &= ~(~(-1 << bitLength) << -this._bitOffset); // clearing bit range before binary "or"
wideValue |=
(bitLength < 32 ? value & ~(-1 << bitLength) : value) << -this._bitOffset; // setting bits
for (var i = b.length - 1; i >= 0; i--) {
b[i] = wideValue & 0xff;
wideValue >>>= 8;
}
this._setBytes(data.start, b, true);
},
};
var proto = jDataView.prototype;
for (var type in dataTypes) {
(function (type) {
proto["get" + type] = function (byteOffset, littleEndian) {
return this._action(type, true, byteOffset, littleEndian);
};
proto["set" + type] = function (byteOffset, value, littleEndian) {
this._action(type, false, byteOffset, littleEndian, value);
};
})(type);
}
proto._setInt32 = proto._setUint32;
proto._setInt16 = proto._setUint16;
proto._setInt8 = proto._setUint8;
proto.setSigned = proto.setUnsigned;
for (var method in proto) {
if (method.slice(0, 3) === "set") {
(function (type) {
proto["write" + type] = function () {
Array.prototype.unshift.call(arguments, undefined);
this["set" + type].apply(this, arguments);
};
})(method.slice(3));
}
}
if (typeof module !== "undefined" && typeof module.exports === "object") {
module.exports = jDataView;
} else if (typeof define === "function" && define.amd) {
define([], function () {
return jDataView;
});
} else {
var oldGlobalThis = globalThis.jDataView;
(globalThis.jDataView = jDataView).noConflict = function () {
globalThis.jDataView = oldGlobalThis;
return this;
};
}

64
src/lib/main.js Normal file
View file

@ -0,0 +1,64 @@
import { jDataView } from "./jdataview";
import { pesRead } from "./pesformat";
import { Pattern } from "./pattern";
String.prototype.endsWith = function (suffix) {
return this.indexOf(suffix, this.length - suffix.length) !== -1;
};
function displayFileText(filename, evt, canvas) {
const view = jDataView(evt.target.result, 0, evt.size);
const pattern = new Pattern();
filename = filename.toLowerCase();
if (filename.endsWith("pes")) {
pesRead(view, pattern);
}
pattern.moveToPositive();
pattern.drawShape(canvas);
}
function handleFileReadAbort(evt) {
alert("File read aborted.");
}
function handleFileReadError(evt) {
let message;
switch (evt.target.error.name) {
case "NotFoundError":
alert("The file could not be found at the time the read was processed.");
break;
case "SecurityError":
message = "<p>A file security error occured. This can be due to:</p>";
message +=
"<ul><li>Accessing certain files deemed unsafe for Web applications.</li>";
message += "<li>Performing too many read calls on file resources.</li>";
message +=
"<li>The file has changed on disk since the user selected it.</li></ul>";
alert(message);
break;
case "NotReadableError":
alert(
"The file cannot be read. This can occur if the file is open in another application."
);
break;
case "EncodingError":
alert("The length of the data URL for the file is too long.");
break;
default:
alert("File error code " + evt.target.error.name);
}
}
export function startFileRead(fileObject, canvas) {
const reader = new FileReader();
reader.onloadend = function (x) {
displayFileText.apply(null, [fileObject.name, x, canvas]);
};
reader.abort = handleFileReadAbort;
reader.onerror = handleFileReadError;
if (fileObject) {
reader.readAsArrayBuffer(fileObject);
}
}

177
src/lib/pattern.js Normal file
View file

@ -0,0 +1,177 @@
function Stitch(x, y, flags, color) {
this.flags = flags;
this.x = x;
this.y = y;
this.color = color;
}
function Color(r, g, b, description) {
this.r = r;
this.g = g;
this.b = b;
this.description = description;
}
const stitchTypes = {
normal: 0,
jump: 1,
trim: 2,
stop: 4,
end: 8,
};
function Pattern() {
this.colors = [];
this.stitches = [];
this.hoop = {};
this.lastX = 0;
this.lastY = 0;
this.top = 0;
this.bottom = 0;
this.left = 0;
this.right = 0;
this.currentColorIndex = 0;
}
Pattern.prototype.addColorRgb = function (r, g, b, description) {
this.colors[this.colors.length] = new Color(r, g, b, description);
};
Pattern.prototype.addColor = function (color) {
this.colors[this.colors.length] = color;
};
Pattern.prototype.addStitchAbs = function (x, y, flags, isAutoColorIndex) {
if ((flags & stitchTypes.end) === stitchTypes.end) {
this.calculateBoundingBox();
this.fixColorCount();
}
if (
(flags & stitchTypes.stop) === stitchTypes.stop &&
this.stitches.length === 0
) {
return;
}
if ((flags & stitchTypes.stop) === stitchTypes.stop && isAutoColorIndex) {
this.currentColorIndex += 1;
}
this.stitches[this.stitches.length] = new Stitch(
x,
y,
flags,
this.currentColorIndex
);
};
Pattern.prototype.addStitchRel = function (dx, dy, flags, isAutoColorIndex) {
if (this.stitches.length !== 0) {
let nx = this.lastX + dx,
ny = this.lastY + dy;
this.lastX = nx;
this.lastY = ny;
this.addStitchAbs(nx, ny, flags, isAutoColorIndex);
} else {
this.addStitchAbs(dx, dy, flags, isAutoColorIndex);
}
};
Pattern.prototype.calculateBoundingBox = function () {
let i = 0,
stitchCount = this.stitches.length,
pt;
if (stitchCount === 0) {
this.bottom = 1;
this.right = 1;
return;
}
this.left = 99999;
this.top = 99999;
this.right = -99999;
this.bottom = -99999;
for (i = 0; i < stitchCount; i += 1) {
pt = this.stitches[i];
if (!(pt.flags & stitchTypes.trim)) {
this.left = this.left < pt.x ? this.left : pt.x;
this.top = this.top < pt.y ? this.top : pt.y;
this.right = this.right > pt.x ? this.right : pt.x;
this.bottom = this.bottom > pt.y ? this.bottom : pt.y;
}
}
};
Pattern.prototype.moveToPositive = function () {
let i = 0,
stitchCount = this.stitches.length;
for (i = 0; i < stitchCount; i += 1) {
this.stitches[i].x -= this.left;
this.stitches[i].y -= this.top;
}
this.right -= this.left;
this.left = 0;
this.bottom -= this.top;
this.top = 0;
};
Pattern.prototype.invertPatternVertical = function () {
let i = 0,
temp = -this.top,
stitchCount = this.stitches.length;
for (i = 0; i < stitchCount; i += 1) {
this.stitches[i].y = -this.stitches[i].y;
}
this.top = -this.bottom;
this.bottom = temp;
};
Pattern.prototype.addColorRandom = function () {
this.colors[this.colors.length] = new Color(
Math.round(Math.random() * 256),
Math.round(Math.random() * 256),
Math.round(Math.random() * 256),
"random"
);
};
Pattern.prototype.fixColorCount = function () {
let maxColorIndex = 0,
stitchCount = this.stitches.length,
i;
for (i = 0; i < stitchCount; i += 1) {
maxColorIndex = Math.max(maxColorIndex, this.stitches[i].color);
}
while (this.colors.length <= maxColorIndex) {
this.addColorRandom();
}
this.colors.splice(maxColorIndex + 1, this.colors.length - maxColorIndex - 1);
};
Pattern.prototype.drawShape = function (canvas) {
canvas.width = this.right;
canvas.height = this.bottom;
if (canvas.getContext) {
const ctx = canvas.getContext("2d");
let color = this.colors[this.stitches[0].color];
ctx.beginPath();
ctx.strokeStyle = "rgb(" + color.r + "," + color.g + "," + color.b + ")";
for (let i = 0; i < this.stitches.length; i++) {
const currentStitch = this.stitches[i];
if (
currentStitch.flags === stitchTypes.jump ||
currentStitch.flags === stitchTypes.trim ||
currentStitch.flags === stitchTypes.stop
) {
ctx.stroke();
color = this.colors[currentStitch.color];
ctx.beginPath();
ctx.strokeStyle =
"rgb(" + color.r + "," + color.g + "," + color.b + ")";
ctx.moveTo(currentStitch.x, currentStitch.y);
}
ctx.lineTo(currentStitch.x, currentStitch.y);
}
ctx.stroke();
}
};
export { Pattern, Color, stitchTypes };

140
src/lib/pesformat.js Normal file
View file

@ -0,0 +1,140 @@
import { Color, stitchTypes } from "./pattern";
const namedColors = [
new Color(0, 0, 0, "Unknown"),
new Color(14, 31, 124, "Prussian Blue"),
new Color(10, 85, 163, "Blue"),
new Color(0, 135, 119, "Teal Green"),
new Color(75, 107, 175, "Cornflower Blue"),
new Color(237, 23, 31, "Red"),
new Color(209, 92, 0, "Reddish Brown"),
new Color(145, 54, 151, "Magenta"),
new Color(228, 154, 203, "Light Lilac"),
new Color(145, 95, 172, "Lilac"),
new Color(158, 214, 125, "Mint Green"),
new Color(232, 169, 0, "Deep Gold"),
new Color(254, 186, 53, "Orange"),
new Color(255, 255, 0, "Yellow"),
new Color(112, 188, 31, "Lime Green"),
new Color(186, 152, 0, "Brass"),
new Color(168, 168, 168, "Silver"),
new Color(125, 111, 0, "Russet Brown"),
new Color(255, 255, 179, "Cream Brown"),
new Color(79, 85, 86, "Pewter"),
new Color(0, 0, 0, "Black"),
new Color(11, 61, 145, "Ultramarine"),
new Color(119, 1, 118, "Royal Purple"),
new Color(41, 49, 51, "Dark Gray"),
new Color(42, 19, 1, "Dark Brown"),
new Color(246, 74, 138, "Deep Rose"),
new Color(178, 118, 36, "Light Brown"),
new Color(252, 187, 197, "Salmon Pink"),
new Color(254, 55, 15, "Vermillion"),
new Color(240, 240, 240, "White"),
new Color(106, 28, 138, "Violet"),
new Color(168, 221, 196, "Seacrest"),
new Color(37, 132, 187, "Sky Blue"),
new Color(254, 179, 67, "Pumpkin"),
new Color(255, 243, 107, "Cream Yellow"),
new Color(208, 166, 96, "Khaki"),
new Color(209, 84, 0, "Clay Brown"),
new Color(102, 186, 73, "Leaf Green"),
new Color(19, 74, 70, "Peacock Blue"),
new Color(135, 135, 135, "Gray"),
new Color(216, 204, 198, "Warm Gray"),
new Color(67, 86, 7, "Dark Olive"),
new Color(253, 217, 222, "Flesh Pink"),
new Color(249, 147, 188, "Pink"),
new Color(0, 56, 34, "Deep Green"),
new Color(178, 175, 212, "Lavender"),
new Color(104, 106, 176, "Wisteria Violet"),
new Color(239, 227, 185, "Beige"),
new Color(247, 56, 102, "Carmine"),
new Color(181, 75, 100, "Amber Red"),
new Color(19, 43, 26, "Olive Green"),
new Color(199, 1, 86, "Dark Fuschia"),
new Color(254, 158, 50, "Tangerine"),
new Color(168, 222, 235, "Light Blue"),
new Color(0, 103, 62, "Emerald Green"),
new Color(78, 41, 144, "Purple"),
new Color(47, 126, 32, "Moss Green"),
new Color(255, 204, 204, "Flesh Pink"),
new Color(255, 217, 17, "Harvest Gold"),
new Color(9, 91, 166, "Electric Blue"),
new Color(240, 249, 112, "Lemon Yellow"),
new Color(227, 243, 91, "Fresh Green"),
new Color(255, 153, 0, "Orange"),
new Color(255, 240, 141, "Cream Yellow"),
new Color(255, 200, 200, "Applique"),
];
function readPecStitches(file, pattern) {
let stitchNumber = 0,
stitchType,
val1,
val2,
byteCount = file.byteLength;
while (file.tell() < byteCount) {
val1 = file.getUint8();
val2 = file.getUint8();
stitchType = stitchTypes.normal;
if (val1 === 0xff && val2 === 0x00) {
pattern.addStitchRel(0, 0, stitchTypes.end, true);
break;
}
if (val1 === 0xfe && val2 === 0xb0) {
file.getInt8();
pattern.addStitchRel(0, 0, stitchTypes.stop, true);
stitchNumber += 1;
} else {
if (val1 & 0x80) {
if (val1 & 0x20) {
stitchType = stitchTypes.trim;
}
if (val1 & 0x10) {
stitchType = stitchTypes.jump;
}
val1 = ((val1 & 0x0f) << 8) + val2;
if (val1 & 0x800) {
val1 -= 0x1000;
}
val2 = file.getUint8();
} else if (val1 >= 0x40) {
val1 -= 0x80;
}
if (val2 & 0x80) {
if (val2 & 0x20) {
stitchType = stitchTypes.trim;
}
if (val2 & 0x10) {
stitchType = stitchTypes.jump;
}
val2 = ((val2 & 0x0f) << 8) + file.getUint8();
if (val2 & 0x800) {
val2 -= 0x1000;
}
} else if (val2 > 0x3f) {
val2 -= 0x80;
}
pattern.addStitchRel(val1, val2, stitchType, true);
stitchNumber += 1;
}
}
}
export function pesRead(file, pattern) {
let x, numColors, pecstart;
pecstart = file.getInt32(8, true);
file.seek(pecstart + 48);
numColors = file.getInt8() + 1;
for (x = 0; x < numColors; x += 1) {
pattern.addColor(namedColors[file.getInt8()]);
}
file.seek(pecstart + 532);
readPecStitches(file, pattern);
pattern.addStitchRel(0, 0, stitchTypes.end);
}
export const pecReadStitches = readPecStitches;
export const pecColors = namedColors;

8
src/main.js Normal file
View file

@ -0,0 +1,8 @@
import './app.css'
import App from './App.svelte'
const app = new App({
target: document.getElementById('app')
})
export default app

2
src/vite-env.d.ts vendored Normal file
View file

@ -0,0 +1,2 @@
/// <reference types="svelte" />
/// <reference types="vite/client" />

7
vite.config.js Normal file
View file

@ -0,0 +1,7 @@
import { defineConfig } from 'vite'
import { svelte } from '@sveltejs/vite-plugin-svelte'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [svelte()]
})