diff --git a/example/index.html b/example/index.html
index 5484dbf..5fbfb90 100644
--- a/example/index.html
+++ b/example/index.html
@@ -16,7 +16,7 @@
.grid-item {
margin: 0;
padding: 0;
- width: 50vw;
+ width: 33.333333vw;
height: 50vh;
line-height: 0;
position: relative;
@@ -57,14 +57,21 @@
+
diff --git a/example/package-lock.json b/example/package-lock.json
index aa4b57d..3094a04 100644
--- a/example/package-lock.json
+++ b/example/package-lock.json
@@ -8,9 +8,6 @@
"name": "fast-image-sequence examples",
"version": "1.0.0",
"license": "MIT",
- "dependencies": {
- "@mediamonks/fast-image-sequence": "^0.1.0"
- },
"devDependencies": {
"vite": "^5.1.6"
}
@@ -453,14 +450,6 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
- "node_modules/@mediamonks/fast-image-sequence": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/@mediamonks/fast-image-sequence/-/fast-image-sequence-0.1.3.tgz",
- "integrity": "sha512-MhsiOC6Jx0L3bgGlPYyx5XL8TD+YwW9oW+avR3Q9cZ+q1VxDGPBYSH0e1Ms3Sb6X8G1zLnfRQ/pYt7qjnTkI7g==",
- "engines": {
- "node": ">=16.0.0"
- }
- },
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.0.tgz",
diff --git a/example/src/exampleLoadTar.js b/example/src/exampleLoadTar.js
new file mode 100644
index 0000000..9166200
--- /dev/null
+++ b/example/src/exampleLoadTar.js
@@ -0,0 +1,65 @@
+import {FastImageSequence} from '../../src/index';
+
+const prevButton = document.getElementById('prev-button-2');
+const nextButton = document.getElementById('next-button-2');
+const progress = document.getElementById('slider-input-2');
+
+function blobToDataURL(blob) {
+ return new Promise((resolve, reject) => {
+ const reader = new FileReader();
+ reader.onload = _e => resolve(reader.result);
+ reader.onerror = _e => reject(reader.error);
+ reader.onabort = _e => reject(new Error("Read aborted"));
+ reader.readAsDataURL(blob);
+ });
+}
+
+export async function initExampleLoadTar(container) {
+ // load tar file with lowres previews
+ fetch('lowrespreviews.tar').then(async (response) => {
+ const blob = await response.blob();
+ const dataURL = await blobToDataURL(blob);
+
+ const fastImageSequence = new FastImageSequence(container, {
+ name: 'PlayWithControlTest',
+ frames: 89,
+ src: [
+ {
+ tarURL: dataURL,
+ imageURL: (i) => `${('' + (i + 1)).padStart(4, '0')}.jpg`,
+ }
+ ],
+ // optional arguments:
+ loop: true, // default false
+ objectFit: 'contain', // default 'cover'
+ fillStyle: '#00000000', // default #00000000
+ clearCanvas: false, // default false
+ showDebugInfo: true,
+ });
+
+ await fastImageSequence.ready();
+
+ fastImageSequence.tick((dt) => {
+ if (fastImageSequence.playing) {
+ progress.value = fastImageSequence.progress;
+ }
+ });
+
+ prevButton.addEventListener('click', () => {
+ fastImageSequence.play(-30);
+ });
+ nextButton.addEventListener('click', () => {
+ fastImageSequence.play(30);
+ });
+ progress.addEventListener('mousedown', (e) => {
+ fastImageSequence.stop();
+ });
+ progress.addEventListener('input', () => {
+ if (fastImageSequence.paused) {
+ fastImageSequence.progress = progress.value;
+ }
+ });
+
+ fastImageSequence.play(30);
+ });
+}
diff --git a/example/src/exampleWithControl.js b/example/src/exampleWithControl.js
index cf9afde..e104897 100644
--- a/example/src/exampleWithControl.js
+++ b/example/src/exampleWithControl.js
@@ -1,8 +1,8 @@
import {FastImageSequence} from '../../src/index';
-const prevButton = document.getElementById('prev-button');
-const nextButton = document.getElementById('next-button');
-const progress = document.getElementById('slider-input');
+const prevButton = document.getElementById('prev-button-1');
+const nextButton = document.getElementById('next-button-1');
+const progress = document.getElementById('slider-input-1');
export async function initExampleWithControl(container) {
const fastImageSequence = new FastImageSequence(container, {
diff --git a/example/src/index.js b/example/src/index.js
index 3a5314a..2a828ac 100644
--- a/example/src/index.js
+++ b/example/src/index.js
@@ -2,8 +2,10 @@ import {initExampleWithControl} from "./exampleWithControl.js";
import {initExamplePlayBackwards} from "./examplePlayBackwards.js";
import {initExampleStillImage} from "./exampleStillImage.js";
import {constructDestructTest} from "./exampleConstructDestructTest.js";
+import {initExampleLoadTar} from "./exampleLoadTar.js";
initExampleWithControl(document.getElementsByClassName('grid-item')[0]);
initExamplePlayBackwards(document.getElementsByClassName('grid-item')[1]);
initExampleStillImage(document.getElementsByClassName('grid-item')[2]);
-constructDestructTest(document.getElementsByClassName('grid-item')[3]);
\ No newline at end of file
+constructDestructTest(document.getElementsByClassName('grid-item')[3]);
+initExampleLoadTar(document.getElementsByClassName('grid-item')[4]);
\ No newline at end of file
diff --git a/package.json b/package.json
index 3298afe..c9439d9 100644
--- a/package.json
+++ b/package.json
@@ -51,8 +51,5 @@
},
"engines": {
"node": ">=16.0.0"
- },
- "dependencies": {
- "@mediamonks/fast-image-sequence": "^0.6.4"
}
}
diff --git a/src/lib/FastImageSequence.ts b/src/lib/FastImageSequence.ts
index 0314e0c..659210b 100644
--- a/src/lib/FastImageSequence.ts
+++ b/src/lib/FastImageSequence.ts
@@ -2,6 +2,7 @@ import Frame from "./Frame.js";
import {createLogElement, logToScreen} from "./LogToScreen.js";
import ImageSource, {type ImageSourceOptions, INPUT_SRC} from "./ImageSource.js";
import ImageSourceTar from "./ImageSourceTar.js";
+import ImageSourceFetch from "./ImageSourceFetch.js";
export function isMobile(): boolean {
return (typeof navigator !== "undefined" && /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent));
@@ -147,7 +148,7 @@ export class FastImageSequence {
if (src.tarURL !== undefined) {
return new ImageSourceTar(this, index, src);
} else {
- return new ImageSource(this, index, src);
+ return new ImageSourceFetch(this, index, src);
}
});
@@ -204,6 +205,18 @@ export class FastImageSequence {
this.frame = (this.options.frames - 1) * value;
}
+ /**
+ * Get the first ImageSource from the sources array.
+ * @returns {ImageSource} - The first ImageSource object in the sources array.
+ */
+ public get src() {
+ return this.sources[0] as ImageSource;
+ }
+
+ private get index(): number {
+ return this.wrapIndex(this.frame);
+ }
+
/**
* Returns a promise that resolves when the image sequence is ready to play.
*/
@@ -221,18 +234,6 @@ export class FastImageSequence {
});
}
- /**
- * Get the first ImageSource from the sources array.
- * @returns {ImageSource} - The first ImageSource object in the sources array.
- */
- public get src() {
- return this.sources[0] as ImageSource;
- }
-
- private get index(): number {
- return this.wrapIndex(this.frame);
- }
-
/**
* Register a tick function to be called on every frame update.
*
@@ -331,7 +332,7 @@ export class FastImageSequence {
this.clearCanvas = true;
}
- public setLoadingPriority() {
+ private setLoadingPriority() {
const priorityIndex = this.index;// this.wrapIndex(Math.min(this.spread / 2 - 2, (this.frame - this.prevFrame) * (dt * 60)) + this.frame);
this.frames.forEach((image) => {
image.priority = Math.abs(image.index + 0.25 - priorityIndex);
diff --git a/src/lib/ImageSource.ts b/src/lib/ImageSource.ts
index 541a23e..f65cfc5 100644
--- a/src/lib/ImageSource.ts
+++ b/src/lib/ImageSource.ts
@@ -1,7 +1,5 @@
import {clamp, type FastImageSequence, isMobile} from "./FastImageSequence.js";
import ImageElement from "./ImageElement.js";
-import {getImageFetchWorker, releaseImageFetchWorker} from "./ImageFetch.js";
-import {loadImage} from "./DownloadFile.js";
export const INPUT_SRC = 0;
export const INPUT_TAR = 1;
@@ -70,7 +68,7 @@ export default class ImageSource {
}
public getImageURL(index: number): string | undefined {
- return this.options.imageURL ? new URL(this.options.imageURL(index), window.location.href).href : undefined;
+ return undefined;
}
public async loadResources() {
@@ -78,6 +76,7 @@ export default class ImageSource {
throw new Error(`No image available for index 0 in ImageSource${this.index} (${this.images[0]?.imageURL})`);
}
+ this.setMaxCachedImages(this.options.maxCachedImages);
this.initialized = true;
}
@@ -111,39 +110,14 @@ export default class ImageSource {
public async fetchImage(imageElement: ImageElement) {
return new Promise((resolve, reject) => {
- if (imageElement.imageURL) {
- imageElement.loading = true;
-
- const loadingDone = (image: ImageBitmap | HTMLImageElement) => {
- if (imageElement.loading) {
- imageElement.image = image;
- resolve(image);
- }
- };
-
- const loadingError = (e: any) => {
- imageElement.reset();
- reject(e);
- };
-
- if (this.options.useWorker) {
- const worker = getImageFetchWorker();
- worker.load(this.index, imageElement.imageURL).then((imageBitmap) => {
- loadingDone(imageBitmap);
- releaseImageFetchWorker(worker);
- }).catch(e => loadingError(e));
- } else {
- const imgElement = new Image();
- loadImage(imgElement, imageElement.imageURL).then(() => {
- loadingDone(imgElement);
- }).catch(e => loadingError(e));
- }
- } else {
- reject('Image url not set');
- }
+ reject('Not implemented');
});
}
+ public destruct() {
+ this.images.forEach(image => image.reset());
+ }
+
private releaseImageWithLowestPriority() {
this.context.setLoadingPriority();
const loadedImages = this.images.filter(a => a.image !== undefined && !a.loading);
@@ -155,8 +129,4 @@ export default class ImageSource {
}
}
}
-
- public destruct() {
- this.images.forEach(image => image.reset());
- }
}
\ No newline at end of file
diff --git a/src/lib/ImageSourceFetch.ts b/src/lib/ImageSourceFetch.ts
new file mode 100644
index 0000000..03cd925
--- /dev/null
+++ b/src/lib/ImageSourceFetch.ts
@@ -0,0 +1,45 @@
+import ImageElement from "./ImageElement.js";
+import {getImageFetchWorker, releaseImageFetchWorker} from "./ImageFetch.js";
+import {loadImage} from "./DownloadFile.js";
+import ImageSource from "./ImageSource.js";
+
+export default class ImageSourceFetch extends ImageSource {
+ public override getImageURL(index: number): string | undefined {
+ return this.options.imageURL ? new URL(this.options.imageURL(index), window.location.href).href : undefined;
+ }
+
+ public override async fetchImage(imageElement: ImageElement) {
+ return new Promise((resolve, reject) => {
+ if (imageElement.imageURL) {
+ imageElement.loading = true;
+
+ const loadingDone = (image: ImageBitmap | HTMLImageElement) => {
+ if (imageElement.loading) {
+ imageElement.image = image;
+ resolve(image);
+ }
+ };
+
+ const loadingError = (e: any) => {
+ imageElement.reset();
+ reject(e);
+ };
+
+ if (this.options.useWorker) {
+ const worker = getImageFetchWorker();
+ worker.load(this.index, imageElement.imageURL).then((imageBitmap) => {
+ loadingDone(imageBitmap);
+ releaseImageFetchWorker(worker);
+ }).catch(e => loadingError(e));
+ } else {
+ const imgElement = new Image();
+ loadImage(imgElement, imageElement.imageURL).then(() => {
+ loadingDone(imgElement);
+ }).catch(e => loadingError(e));
+ }
+ } else {
+ reject('Image url not set');
+ }
+ });
+ }
+}
\ No newline at end of file
diff --git a/src/lib/ImageSourceTar.ts b/src/lib/ImageSourceTar.ts
index c927846..3941050 100644
--- a/src/lib/ImageSourceTar.ts
+++ b/src/lib/ImageSourceTar.ts
@@ -17,7 +17,6 @@ export default class ImageSourceTar extends ImageSource {
this.context.log('Tarball', this.tarball);
this.images.forEach(image => image.available = image.imageURL !== undefined && this.tarball?.getInfo(image.imageURL) !== undefined);
- this.setMaxCachedImages(this.options.maxCachedImages);
}
return super.loadResources();