From 966c807a5ebc404ee9729286d2864c968a612120 Mon Sep 17 00:00:00 2001 From: David Catalan Date: Tue, 23 May 2023 11:55:16 +0200 Subject: [PATCH] feat: add support for base64 images --- src/importer/PageImporter.js | 9 +++++++-- src/utils/DOMUtils.js | 20 ++++++++++++++++++++ test/utils/DOMUtils.spec.js | 19 +++++++++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/importer/PageImporter.js b/src/importer/PageImporter.js index 70c8185c..2fd2b73b 100644 --- a/src/importer/PageImporter.js +++ b/src/importer/PageImporter.js @@ -233,9 +233,14 @@ export default class PageImporter { } src = img.getAttribute('src'); + // try to handle b64 img if (!src || src.indexOf('data:') === 0) { - // we cannot handle b64 asset for now, remove - img.remove(); + const dataUrl = DOMUtils.getDataUrlFromB64Img(img.src); + if (dataUrl) { + img.setAttribute('src', dataUrl); + } else { + img.remove(); + } } const alt = img.getAttribute('alt'); diff --git a/src/utils/DOMUtils.js b/src/utils/DOMUtils.js index 851e656f..7e6b67ec 100644 --- a/src/utils/DOMUtils.js +++ b/src/utils/DOMUtils.js @@ -11,6 +11,7 @@ */ import { JSDOM } from 'jsdom'; +import { Blob } from 'buffer'; export default class DOMUtils { static EMPTY_TAGS_TO_PRESERVE = ['img', 'video', 'iframe', 'div', 'picture']; @@ -280,4 +281,23 @@ export default class DOMUtils { }, interval); }); } + + static getDataUrlFromB64Img(src) { + try { + const arr = src.split(','); + const bstr = atob(arr[1]); + let n = bstr.length - 1; + const u8arr = new Uint8Array(n); + while (n >= 0) { + u8arr[n] = bstr.charCodeAt(n); + n -= 1; + } + const blob = new Blob([u8arr]); + return URL.createObjectURL(blob); + } catch (e) { + // eslint-disable-next-line no-console + console.error(`get data url from a base64 image (${src}):`, e); + return null; + } + } } diff --git a/test/utils/DOMUtils.spec.js b/test/utils/DOMUtils.spec.js index d5b27b69..27299590 100644 --- a/test/utils/DOMUtils.spec.js +++ b/test/utils/DOMUtils.spec.js @@ -411,3 +411,22 @@ describe('DOMUtils#getImgFromBackground', () => { test(createElement('div', { class: 'someclass' }, { 'background-image': 'url("https://www.server.com/image.jpg")', background: 'rgb(0, 0, 0) none repeat scroll 0% 0% / auto padding-box border-box' }, '
Some divs
More divs
'), ''); }); }); + +describe('DOMUtils#getDataUrlFromB64Img', () => { + const test = (img, expected) => { + const dataUrl = DOMUtils.getDataUrlFromB64Img(img.src); + return expected(dataUrl) === true; + }; + + it('no data url in original image', () => { + test(createElement('img', { src: 'https://www.server.com/image.jpg' }, {}, ''), (res) => res === null); + }); + + it('malformed base64 data url in original image', () => { + test(createElement('img', { src: 'data:image/png;base64,--dummy--' }, {}, ''), (res) => res === null); + }); + + it('base64 data url in original image', () => { + test(createElement('img', { src: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==' }, {}, ''), (res) => res.indexOf('blob:nodedata:') === 0); + }); +});