From df3cea1c78caa8b0e991029c55fafea2c7d77e08 Mon Sep 17 00:00:00 2001 From: Spence Pope Date: Tue, 18 Aug 2026 09:26:26 -0400 Subject: [PATCH] APP-2884: Avoid base64 reads for web videos (#11493) --- src/lib/media/picker.shared.ts | 7 +++++-- src/view/com/composer/SelectMediaButton.tsx | 15 +++++++++------ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/lib/media/picker.shared.ts b/src/lib/media/picker.shared.ts index 63e2a1e06c..cabc9fa62f 100644 --- a/src/lib/media/picker.shared.ts +++ b/src/lib/media/picker.shared.ts @@ -8,7 +8,7 @@ import {t} from '@lingui/core/macro' import {type ImageMeta} from '#/state/gallery' import * as Toast from '#/components/Toast' -import {IS_IOS, IS_WEB} from '#/env' +import {IS_IOS} from '#/env' import {VIDEO_MAX_DURATION_MS} from '../constants' import {getDataUriSize} from './util' @@ -58,7 +58,10 @@ export async function openUnifiedPicker({ quality: 1, allowsMultipleSelection: true, legacy: true, - base64: IS_WEB, + // Reading videos as base64 can fail in the browser before callers have a + // chance to validate the file size. Web callers can read image files from + // the `file` returned on each asset after validation instead. + base64: false, selectionLimit: IS_IOS ? selectionCountRemaining : undefined, preferredAssetRepresentationMode: UIImagePickerPreferredAssetRepresentationMode.Automatic, diff --git a/src/view/com/composer/SelectMediaButton.tsx b/src/view/com/composer/SelectMediaButton.tsx index 24ddeaa2aa..15872a4733 100644 --- a/src/view/com/composer/SelectMediaButton.tsx +++ b/src/view/com/composer/SelectMediaButton.tsx @@ -16,7 +16,7 @@ import { useVideoLibraryPermission, } from '#/lib/hooks/usePermissions' import {openUnifiedPicker} from '#/lib/media/picker' -import {extractDataUriMime} from '#/lib/media/util' +import {blobToDataUri, extractDataUriMime} from '#/lib/media/util' import {MAX_GALLERY_IMAGES} from '#/view/com/composer/state/composer' import {atoms as a, useTheme} from '#/alf' import {Button} from '#/components/Button' @@ -331,18 +331,21 @@ async function processImagePickerAssets( /* * All validations passed, we have an asset! */ + let uri = asset.uri + if (IS_WEB && type === 'image' && asset.file) { + uri = await blobToDataUri(asset.file) + } + supportedAssets.push({ mimeType, ...asset, /* * In `expo-image-picker` >= v17, `uri` is now a `blob:` URL, not a * data-uri. Our handling elsewhere in the app (for web) relies on the - * base64 data-uri, so we construct it here for web only. + * data-uri, so read images only after their type has been validated. + * Videos retain their File/blob URL and avoid an expensive base64 read. */ - uri: - IS_WEB && asset.base64 - ? `data:${mimeType};base64,${asset.base64}` - : asset.uri, + uri, }) }