Skip to content

Commit 07d9cca

Browse files
committed
Change organization for multiple projects
1 parent 67f9142 commit 07d9cca

File tree

8 files changed

+123
-88
lines changed

8 files changed

+123
-88
lines changed

.eslintrc.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"env": {
3+
"browser": true
4+
},
5+
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
6+
"parser": "@typescript-eslint/parser",
7+
"plugins": ["@typescript-eslint"],
8+
"root": true,
9+
"rules": {
10+
"no-constant-condition": "off",
11+
"no-debugger": "off",
12+
"no-inner-declarations": "off",
13+
"no-mixed-spaces-and-tabs": "off"
14+
}
15+
}

.vscode/settings.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"files.exclude": {
3+
"**/.eslint*": true,
4+
"**/.git": true,
5+
"**/.vscode": true,
6+
"**/package*": true
7+
},
8+
"git.openRepositoryInParentFolders": "never"
9+
}

Reader.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/**
2+
* The reader class will help yielding bytes from a buffer.
3+
* It'll allow to rewind the pointer.
4+
*/
5+
export default class Reader {
6+
#bytes;
7+
#iterator;
8+
#offset = 0;
9+
10+
constructor(bytes) {
11+
this.#bytes = new Uint8Array(bytes);
12+
}
13+
14+
get bytes() {
15+
return this.#bytes;
16+
}
17+
18+
*#getIterator() {
19+
for (; this.#offset < this.#bytes.length; ) {
20+
yield this.#bytes[this.#offset++];
21+
}
22+
}
23+
24+
get offset() {
25+
return this.#offset;
26+
}
27+
28+
read(bytes = 1) {
29+
this.#iterator ||= this.#getIterator();
30+
31+
if (bytes > 1) {
32+
const view = new Uint8Array(this.#bytes.buffer, this.#offset, bytes);
33+
this.#offset += bytes;
34+
35+
return Array.from(view);
36+
}
37+
38+
const {done, value} = this.#iterator.next();
39+
if (done) throw new Error('End of buffer');
40+
return value;
41+
}
42+
43+
rewind(bytes = 1) {
44+
this.#offset -= bytes;
45+
}
46+
47+
get status() {
48+
const remaining = this.#bytes.length - this.#offset;
49+
return this.#offset !== this.#bytes.length
50+
? `Stopped reading at offset ${this.#offset}, still ${remaining} ${
51+
remaining > 1 ? 'bytes' : 'byte'
52+
} to read.`
53+
: 'Finished reading.';
54+
}
55+
}

gif/.vscode

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../.vscode

gif/Reader.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../Reader.js

gif/gif.js

Lines changed: 30 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
1-
const canvas = document.getElementById('canvas');
2-
const context = canvas.getContext('2d', {willReadFrequently: true});
3-
4-
const response = await fetch('nyan.gif');
5-
const bytes = await response.arrayBuffer();
1+
import {toASCII, toHex} from './utilities.js';
2+
import Reader from './Reader.js';
63

74
/**
85
* See GIF specification:
@@ -28,79 +25,14 @@ function objectToRGB(object) {
2825
return `rgb(${object.r} ${object.g} ${object.b})`;
2926
}
3027

31-
function toASCII(number) {
32-
return String.fromCharCode(number);
33-
}
34-
35-
function toBin(number, padded = true) {
36-
return `0b${number.toString(2).padStart(padded ? 8 : 0, '0')}`;
37-
}
38-
39-
function toHex(number, padded = true) {
40-
return `0x${number.toString(16).padStart(padded ? 2 : 0, '0')}`;
41-
}
42-
4328
function toUnsigned([a, b]) {
4429
return (b << 8) | a;
4530
}
4631

4732
/**
48-
* The reader class will help yielding bytes from a buffer.
49-
* It'll allow to rewind the pointer.
33+
* “Parser”
5034
*/
5135

52-
class Reader {
53-
#bytes;
54-
#iterator;
55-
#offset = 0;
56-
57-
constructor(bytes) {
58-
this.#bytes = new Uint8Array(bytes);
59-
}
60-
61-
get bytes() {
62-
return this.#bytes;
63-
}
64-
65-
*#getIterator() {
66-
for (; this.#offset < this.#bytes.length; ) {
67-
yield this.#bytes[this.#offset++];
68-
}
69-
}
70-
71-
get offset() {
72-
return this.#offset;
73-
}
74-
75-
read(bytes = 1) {
76-
this.#iterator ||= this.#getIterator();
77-
78-
if (bytes > 1) {
79-
const view = new Uint8Array(this.#bytes.buffer, this.#offset, bytes);
80-
this.#offset += bytes;
81-
82-
return Array.from(view);
83-
}
84-
85-
const {done, value} = this.#iterator.next();
86-
if (done) throw new Error('End of buffer');
87-
return value;
88-
}
89-
90-
rewind(bytes = 1) {
91-
this.#offset -= bytes;
92-
}
93-
94-
get status() {
95-
const remaining = this.#bytes.length - this.#offset;
96-
return this.#offset !== this.#bytes.length
97-
? `Stopped reading at offset ${this.#offset}, still ${remaining} ${
98-
remaining > 1 ? 'bytes' : 'byte'
99-
} to read.`
100-
: 'Finished reading.';
101-
}
102-
}
103-
10436
function assertExtension(reader, LABEL) {
10537
const [introducer, label] = reader.read(2);
10638

@@ -491,23 +423,9 @@ function parseTrailer(reader) {
491423
}
492424
}
493425

494-
const cache = new Map(); // Prepare a cache to store rendered images so we don't have to re-render them
495-
const reader = new Reader(bytes);
496-
const gif = parseGIFDataStream(reader);
497-
const images = gif.data.filter((d) => d.rendering);
498-
let currentImageIndex = 0;
499-
500-
console.info(reader.status);
501-
console.log('Parsed:', gif);
502-
503-
const {backgroundColorIndex, globalColorTable, height, width} =
504-
gif.logicalScreen;
505-
506-
// Set the canvas with the GIF's size and background color
507-
canvas.width = width;
508-
canvas.height = height;
509-
context.fillStyle = objectToRGB(globalColorTable[backgroundColorIndex]);
510-
context.fillRect(0, 0, width, height);
426+
/**
427+
* “App”
428+
*/
511429

512430
// Convert an array of decompressed color indexes to an array of RGBA values
513431
function arrayToImageData(data, {image}) {
@@ -681,6 +599,30 @@ function render(image) {
681599
return render(image);
682600
}
683601

602+
const canvas = document.getElementById('canvas');
603+
const context = canvas.getContext('2d', {willReadFrequently: true});
604+
605+
const response = await fetch('nyan.gif');
606+
const bytes = await response.arrayBuffer();
607+
608+
const cache = new Map(); // Prepare a cache to store rendered images so we don't have to re-render them
609+
const reader = new Reader(bytes);
610+
const gif = parseGIFDataStream(reader);
611+
const images = gif.data.filter((d) => d.rendering);
612+
let currentImageIndex = 0;
613+
614+
console.info(reader.status);
615+
console.log('Parsed:', gif);
616+
617+
const {backgroundColorIndex, globalColorTable, height, width} =
618+
gif.logicalScreen;
619+
620+
// Set the canvas with the GIF's size and background color
621+
canvas.width = width;
622+
canvas.height = height;
623+
context.fillStyle = objectToRGB(globalColorTable[backgroundColorIndex]);
624+
context.fillRect(0, 0, width, height);
625+
684626
if (images.length > 1) {
685627
loop();
686628
} else {

gif/utilities.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../utilities.js

utilities.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
export function toASCII(number) {
2+
return String.fromCharCode(number);
3+
}
4+
5+
export function toBin(number, padded = true) {
6+
return `0b${number.toString(2).padStart(padded ? 8 : 0, '0')}`;
7+
}
8+
9+
export function toHex(number, padded = true) {
10+
return `0x${number.toString(16).padStart(padded ? 2 : 0, '0')}`;
11+
}

0 commit comments

Comments
 (0)