UNPKG

4.7 kBJavaScriptView Raw
1/**
2 * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
3 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4 */
5import { global } from 'ckeditor5/src/utils.js';
6/**
7 * Creates a regular expression used to test for image files.
8 *
9 * ```ts
10 * const imageType = createImageTypeRegExp( [ 'png', 'jpeg', 'svg+xml', 'vnd.microsoft.icon' ] );
11 *
12 * console.log( 'is supported image', imageType.test( file.type ) );
13 * ```
14 */
15export function createImageTypeRegExp(types) {
16 // Sanitize the MIME type name which may include: "+", "-" or ".".
17 const regExpSafeNames = types.map(type => type.replace('+', '\\+'));
18 return new RegExp(`^image\\/(${regExpSafeNames.join('|')})$`);
19}
20/**
21 * Creates a promise that fetches the image local source (Base64 or blob) and resolves with a `File` object.
22 *
23 * @param image Image whose source to fetch.
24 * @returns A promise which resolves when an image source is fetched and converted to a `File` instance.
25 * It resolves with a `File` object. If there were any errors during file processing, the promise will be rejected.
26 */
27export function fetchLocalImage(image) {
28 return new Promise((resolve, reject) => {
29 const imageSrc = image.getAttribute('src');
30 // Fetch works asynchronously and so does not block browser UI when processing data.
31 fetch(imageSrc)
32 .then(resource => resource.blob())
33 .then(blob => {
34 const mimeType = getImageMimeType(blob, imageSrc);
35 const ext = mimeType.replace('image/', '');
36 const filename = `image.${ext}`;
37 const file = new File([blob], filename, { type: mimeType });
38 resolve(file);
39 })
40 .catch(err => {
41 // Fetch fails only, if it can't make a request due to a network failure or if anything prevented the request
42 // from completing, i.e. the Content Security Policy rules. It is not possible to detect the exact cause of failure,
43 // so we are just trying the fallback solution, if general TypeError is thrown.
44 return err && err.name === 'TypeError' ?
45 convertLocalImageOnCanvas(imageSrc).then(resolve).catch(reject) :
46 reject(err);
47 });
48 });
49}
50/**
51 * Checks whether a given node is an image element with a local source (Base64 or blob).
52 *
53 * @param node The node to check.
54 */
55export function isLocalImage(imageUtils, node) {
56 if (!imageUtils.isInlineImageView(node) || !node.getAttribute('src')) {
57 return false;
58 }
59 return !!node.getAttribute('src').match(/^data:image\/\w+;base64,/g) ||
60 !!node.getAttribute('src').match(/^blob:/g);
61}
62/**
63 * Extracts an image type based on its blob representation or its source.
64 * @param blob Image blob representation.
65 * @param src Image `src` attribute value.
66 */
67function getImageMimeType(blob, src) {
68 if (blob.type) {
69 return blob.type;
70 }
71 else if (src.match(/data:(image\/\w+);base64/)) {
72 return src.match(/data:(image\/\w+);base64/)[1].toLowerCase();
73 }
74 else {
75 // Fallback to 'jpeg' as common extension.
76 return 'image/jpeg';
77 }
78}
79/**
80 * Creates a promise that converts the image local source (Base64 or blob) to a blob using canvas and resolves
81 * with a `File` object.
82 * @param imageSrc Image `src` attribute value.
83 * @returns A promise which resolves when an image source is converted to a `File` instance.
84 * It resolves with a `File` object. If there were any errors during file processing, the promise will be rejected.
85 */
86function convertLocalImageOnCanvas(imageSrc) {
87 return getBlobFromCanvas(imageSrc).then(blob => {
88 const mimeType = getImageMimeType(blob, imageSrc);
89 const ext = mimeType.replace('image/', '');
90 const filename = `image.${ext}`;
91 return new File([blob], filename, { type: mimeType });
92 });
93}
94/**
95 * Creates a promise that resolves with a `Blob` object converted from the image source (Base64 or blob).
96 * @param imageSrc Image `src` attribute value.
97 */
98function getBlobFromCanvas(imageSrc) {
99 return new Promise((resolve, reject) => {
100 const image = global.document.createElement('img');
101 image.addEventListener('load', () => {
102 const canvas = global.document.createElement('canvas');
103 canvas.width = image.width;
104 canvas.height = image.height;
105 const ctx = canvas.getContext('2d');
106 ctx.drawImage(image, 0, 0);
107 canvas.toBlob(blob => blob ? resolve(blob) : reject());
108 });
109 image.addEventListener('error', () => reject());
110 image.src = imageSrc;
111 });
112}