Page MenuHomePhorge

D7223.1768405336.diff
No OneTemporary

Size
4 KB
Referenced Files
None
Subscribers
None

D7223.1768405336.diff

diff --git a/lib/media/data-utils.js b/lib/media/data-utils.js
new file mode 100644
--- /dev/null
+++ b/lib/media/data-utils.js
@@ -0,0 +1,92 @@
+// @flow
+
+import { fileInfoFromData } from './file-utils.js';
+
+/**
+ * Returns a hex string representation of the given Uint8Array.
+ */
+function uintArrayToHexString(data: Uint8Array): string {
+ return Array.from(data)
+ .map(byte => byte.toString(16).padStart(2, '0'))
+ .join('');
+}
+
+/**
+ * Returns a Uint8Array representation of the given hex string.
+ */
+function hexToUintArray(hex: string): Uint8Array {
+ const result = new Uint8Array(hex.length / 2);
+ for (let i = 0; i < hex.length; i += 2) {
+ result[i / 2] = parseInt(hex.substr(i, 2), 16);
+ }
+ return result;
+}
+
+/**
+ * Returns a data URL representation of the given Uint8Array.
+ * Returns `null` if MIME type cannot be determined by reading the data header.
+ */
+function uintArrayToDataURL(bytes: Uint8Array): ?string {
+ const base64 = base64FromIntArray(bytes);
+ const { mime } = fileInfoFromData(bytes);
+ if (!mime) {
+ return null;
+ }
+ return `data:${mime};base64,${base64}`;
+}
+
+/**
+ * Converts a Uint8Array to a base64 string. This is a temporary workaround
+ * until we can use implement native method to directly save Uint8Array to file.
+ *
+ * It is ~4-6x faster than using
+ * ```js
+ * let base64 = await blobToDataURI(new Blob([bytes]));
+ * base64 = base64.substring(base64.indexOf(',') + 1);
+ * ```
+ *
+ * This function based on
+ * - https://developer.mozilla.org/en-US/docs/Glossary/Base64
+ * - https://gist.github.com/jonleighton/958841
+ * - https://stackoverflow.com/a/12713326
+ */
+function base64FromIntArray(bytes: Uint8Array): string {
+ let base64 = '';
+ const alphabet =
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+
+ const remainder = bytes.length % 3;
+ const mainLength = bytes.length - remainder;
+
+ let a, b, c, d;
+ let chunk;
+ for (let i = 0; i < mainLength; i += 3) {
+ chunk = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2];
+ a = (chunk & 16515072) >> 18;
+ b = (chunk & 258048) >> 12;
+ c = (chunk & 4032) >> 6;
+ d = chunk & 63;
+ base64 += alphabet[a] + alphabet[b] + alphabet[c] + alphabet[d];
+ }
+
+ if (remainder === 1) {
+ chunk = bytes[mainLength];
+ a = (chunk & 252) >> 2;
+ b = (chunk & 3) << 4;
+ base64 += alphabet[a] + alphabet[b] + '==';
+ } else if (remainder === 2) {
+ chunk = (bytes[mainLength] << 8) | bytes[mainLength + 1];
+ a = (chunk & 64512) >> 10;
+ b = (chunk & 1008) >> 4;
+ c = (chunk & 15) << 2;
+ base64 += alphabet[a] + alphabet[b] + alphabet[c] + '=';
+ }
+ return base64;
+}
+
+export {
+ uintArrayToHexString,
+ hexToUintArray,
+ base64FromIntArray,
+ uintArrayToDataURL,
+};
diff --git a/lib/media/data-utils.test.js b/lib/media/data-utils.test.js
new file mode 100644
--- /dev/null
+++ b/lib/media/data-utils.test.js
@@ -0,0 +1,42 @@
+// @flow
+import {
+ uintArrayToHexString,
+ hexToUintArray,
+ uintArrayToDataURL,
+} from './data-utils.js';
+
+describe('uintArrayToHexString', () => {
+ it('converts Uint8Array to hex string', () => {
+ const data = new Uint8Array([0x00, 0x01, 0x02, 0x1a, 0x2b, 0xff]);
+ expect(uintArrayToHexString(data)).toStrictEqual('0001021a2bff');
+ });
+});
+
+describe('hexToUintArray', () => {
+ it('converts hex string to Uint8Array', () => {
+ const hex = '0001021a2bff';
+ expect(hexToUintArray(hex)).toStrictEqual(
+ new Uint8Array([0x00, 0x01, 0x02, 0x1a, 0x2b, 0xff]),
+ );
+ });
+});
+
+describe('uintArrayToDataURL', () => {
+ it('converts JPEG Uint8Array to data URL', () => {
+ const jpegMagicBytes = new Uint8Array([0xff, 0xd8, 0xff, 0xe0]);
+ const jpegData = new Uint8Array(jpegMagicBytes.length + 10);
+ jpegData.set(jpegMagicBytes);
+ jpegData.set(
+ new Uint8Array([0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01]),
+ jpegMagicBytes.length,
+ );
+
+ const jpegBase64 = 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAAA=';
+ expect(uintArrayToDataURL(jpegData)).toStrictEqual(jpegBase64);
+ });
+
+ it('returns null if MIME type cannot be determined', () => {
+ const data = new Uint8Array([0x00, 0x01, 0x02, 0x1a, 0x2b, 0xff]);
+ expect(uintArrayToDataURL(data)).toBeNull();
+ });
+});

File Metadata

Mime Type
text/plain
Expires
Wed, Jan 14, 3:42 PM (7 h, 55 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5932702
Default Alt Text
D7223.1768405336.diff (4 KB)

Event Timeline