From 8106f4744b07833526d16acf656eda11d29b99ad Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sun, 1 Mar 2020 22:36:42 -0500 Subject: Add support for importing and storing media files --- ext/bg/js/media-utility.js | 75 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 ext/bg/js/media-utility.js (limited to 'ext/bg/js/media-utility.js') diff --git a/ext/bg/js/media-utility.js b/ext/bg/js/media-utility.js new file mode 100644 index 00000000..24686838 --- /dev/null +++ b/ext/bg/js/media-utility.js @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2020 Yomichan Authors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +const mediaUtility = (() => { + function getFileNameExtension(fileName) { + const match = /\.[^.]*$/.exec(fileName); + return match !== null ? match[0] : ''; + } + + function getImageMediaTypeFromFileName(fileName) { + switch (getFileNameExtension(fileName).toLowerCase()) { + case '.apng': + return 'image/apng'; + case '.bmp': + return 'image/bmp'; + case '.gif': + return 'image/gif'; + case '.ico': + case '.cur': + return 'image/x-icon'; + case '.jpg': + case '.jpeg': + case '.jfif': + case '.pjpeg': + case '.pjp': + return 'image/jpeg'; + case '.png': + return 'image/png'; + case '.svg': + return 'image/svg+xml'; + case '.tif': + case '.tiff': + return 'image/tiff'; + case '.webp': + return 'image/webp'; + default: + return null; + } + } + + function loadImage(mediaType, base64Source) { + return new Promise((resolve, reject) => { + const image = new Image(); + const eventListeners = new EventListenerCollection(); + eventListeners.addEventListener(image, 'load', () => { + eventListeners.removeAllEventListeners(); + resolve(image); + }, false); + eventListeners.addEventListener(image, 'error', () => { + eventListeners.removeAllEventListeners(); + reject(new Error('Image failed to load')); + }, false); + image.src = `data:${mediaType};base64,${base64Source}`; + }); + } + + return { + getImageMediaTypeFromFileName, + loadImage + }; +})(); -- cgit v1.2.3 From 7faaf4e45737dd06ab3fdf189bd9c1d26ad1349d Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sun, 19 Apr 2020 10:16:59 -0400 Subject: Use 'content' instead of 'source' to contain media file data --- ext/bg/js/dictionary-importer.js | 6 +++--- ext/bg/js/media-utility.js | 4 ++-- ext/mixed/js/media-loader.js | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'ext/bg/js/media-utility.js') diff --git a/ext/bg/js/dictionary-importer.js b/ext/bg/js/dictionary-importer.js index 8a4497a3..b5c535bb 100644 --- a/ext/bg/js/dictionary-importer.js +++ b/ext/bg/js/dictionary-importer.js @@ -323,7 +323,7 @@ class DictionaryImporter { throw new Error(`Could not find image at path ${JSON.stringify(path)} for ${errorSource}`); } - const source = await file.async('base64'); + const content = await file.async('base64'); const mediaType = mediaUtility.getImageMediaTypeFromFileName(path); if (mediaType === null) { throw new Error(`Could not determine media type for image at path ${JSON.stringify(path)} for ${errorSource}`); @@ -331,7 +331,7 @@ class DictionaryImporter { let image; try { - image = await mediaUtility.loadImage(mediaType, source); + image = await mediaUtility.loadImage(mediaType, content); } catch (e) { throw new Error(`Could not load image at path ${JSON.stringify(path)} for ${errorSource}`); } @@ -346,7 +346,7 @@ class DictionaryImporter { mediaType, width, height, - source + content }; context.media.set(path, mediaData); diff --git a/ext/bg/js/media-utility.js b/ext/bg/js/media-utility.js index 24686838..febc509a 100644 --- a/ext/bg/js/media-utility.js +++ b/ext/bg/js/media-utility.js @@ -52,7 +52,7 @@ const mediaUtility = (() => { } } - function loadImage(mediaType, base64Source) { + function loadImage(mediaType, content) { return new Promise((resolve, reject) => { const image = new Image(); const eventListeners = new EventListenerCollection(); @@ -64,7 +64,7 @@ const mediaUtility = (() => { eventListeners.removeAllEventListeners(); reject(new Error('Image failed to load')); }, false); - image.src = `data:${mediaType};base64,${base64Source}`; + image.src = `data:${mediaType};base64,${content}`; }); } diff --git a/ext/mixed/js/media-loader.js b/ext/mixed/js/media-loader.js index c89c4f12..5e3177fc 100644 --- a/ext/mixed/js/media-loader.js +++ b/ext/mixed/js/media-loader.js @@ -86,7 +86,7 @@ class MediaLoader { const token = this._token; const data = (await apiGetMedia([{path, dictionaryName}]))[0]; if (token === this._token && data !== null) { - const sourceArrayBuffer = this._base64ToArrayBuffer(data.source); + const sourceArrayBuffer = this._base64ToArrayBuffer(data.content); const blob = new Blob([sourceArrayBuffer], {type: data.mediaType}); const url = URL.createObjectURL(blob); cachedData.data = data; @@ -95,8 +95,8 @@ class MediaLoader { return cachedData; } - _base64ToArrayBuffer(source) { - const binarySource = window.atob(source); + _base64ToArrayBuffer(content) { + const binarySource = window.atob(content); const length = binarySource.length; const array = new Uint8Array(length); for (let i = 0; i < length; ++i) { -- cgit v1.2.3 From 16893b52b141938a32027049b71cc6c6f46dfb93 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sun, 19 Apr 2020 10:18:31 -0400 Subject: Make getFileNameExtension properly handle directory separators --- ext/bg/js/media-utility.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'ext/bg/js/media-utility.js') diff --git a/ext/bg/js/media-utility.js b/ext/bg/js/media-utility.js index febc509a..8a46cb49 100644 --- a/ext/bg/js/media-utility.js +++ b/ext/bg/js/media-utility.js @@ -16,13 +16,13 @@ */ const mediaUtility = (() => { - function getFileNameExtension(fileName) { - const match = /\.[^.]*$/.exec(fileName); + function getFileNameExtension(path) { + const match = /\.[^./\\]*$/.exec(path); return match !== null ? match[0] : ''; } - function getImageMediaTypeFromFileName(fileName) { - switch (getFileNameExtension(fileName).toLowerCase()) { + function getImageMediaTypeFromFileName(path) { + switch (getFileNameExtension(path).toLowerCase()) { case '.apng': return 'image/apng'; case '.bmp': -- cgit v1.2.3 From 0e80c0d5d03b51c56e72657a46c868c9a2c1137d Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sun, 19 Apr 2020 10:24:36 -0400 Subject: Rename loadImage to loadImageBase64 for clarity --- ext/bg/js/dictionary-importer.js | 2 +- ext/bg/js/media-utility.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'ext/bg/js/media-utility.js') diff --git a/ext/bg/js/dictionary-importer.js b/ext/bg/js/dictionary-importer.js index b5c535bb..3727f7ee 100644 --- a/ext/bg/js/dictionary-importer.js +++ b/ext/bg/js/dictionary-importer.js @@ -331,7 +331,7 @@ class DictionaryImporter { let image; try { - image = await mediaUtility.loadImage(mediaType, content); + image = await mediaUtility.loadImageBase64(mediaType, content); } catch (e) { throw new Error(`Could not load image at path ${JSON.stringify(path)} for ${errorSource}`); } diff --git a/ext/bg/js/media-utility.js b/ext/bg/js/media-utility.js index 8a46cb49..fcbf9d37 100644 --- a/ext/bg/js/media-utility.js +++ b/ext/bg/js/media-utility.js @@ -52,7 +52,7 @@ const mediaUtility = (() => { } } - function loadImage(mediaType, content) { + function loadImageBase64(mediaType, content) { return new Promise((resolve, reject) => { const image = new Image(); const eventListeners = new EventListenerCollection(); @@ -70,6 +70,6 @@ const mediaUtility = (() => { return { getImageMediaTypeFromFileName, - loadImage + loadImageBase64 }; })(); -- cgit v1.2.3 From a7e7d546c70c604e986d5c772d842c47fb701eda Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sun, 19 Apr 2020 10:24:59 -0400 Subject: Add documentation --- ext/bg/js/media-utility.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'ext/bg/js/media-utility.js') diff --git a/ext/bg/js/media-utility.js b/ext/bg/js/media-utility.js index fcbf9d37..1f93b2b4 100644 --- a/ext/bg/js/media-utility.js +++ b/ext/bg/js/media-utility.js @@ -15,12 +15,28 @@ * along with this program. If not, see . */ +/** + * mediaUtility is an object containing helper methods related to media processing. + */ const mediaUtility = (() => { + /** + * Gets the file extension of a file path. URL search queries and hash + * fragments are not handled. + * @param path The path to the file. + * @returns The file extension, including the '.', or an empty string + * if there is no file extension. + */ function getFileNameExtension(path) { const match = /\.[^./\\]*$/.exec(path); return match !== null ? match[0] : ''; } + /** + * Gets an image file's media type using a file path. + * @param path The path to the file. + * @returns The media type string if it can be determined from the file path, + * otherwise null. + */ function getImageMediaTypeFromFileName(path) { switch (getFileNameExtension(path).toLowerCase()) { case '.apng': @@ -52,6 +68,13 @@ const mediaUtility = (() => { } } + /** + * Attempts to load an image using a base64 encoded content and a media type. + * @param mediaType The media type for the image content. + * @param content The binary content for the image, encoded in base64. + * @returns A Promise which resolves with an HTMLImageElement instance on + * successful load, otherwise an error is thrown. + */ function loadImageBase64(mediaType, content) { return new Promise((resolve, reject) => { const image = new Image(); -- cgit v1.2.3