diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/media/manip.ts | 74 | ||||
-rw-r--r-- | src/view/com/composer/useExternalLinkFetch.ts | 26 |
2 files changed, 71 insertions, 29 deletions
diff --git a/src/lib/media/manip.ts b/src/lib/media/manip.ts index 3f01e98c5..e75f13755 100644 --- a/src/lib/media/manip.ts +++ b/src/lib/media/manip.ts @@ -6,18 +6,20 @@ import { copyAsync, deleteAsync, EncodingType, + getInfoAsync, makeDirectoryAsync, StorageAccessFramework, writeAsStringAsync, } from 'expo-file-system' +import {manipulateAsync, SaveFormat} from 'expo-image-manipulator' import * as MediaLibrary from 'expo-media-library' import * as Sharing from 'expo-sharing' -import ImageResizer from '@bam.tech/react-native-image-resizer' import {Buffer} from 'buffer' import RNFetchBlob from 'rn-fetch-blob' +import {POST_IMG_MAX} from '#/lib/constants' import {logger} from '#/logger' -import {isAndroid, isIOS} from 'platform/detection' +import {isAndroid, isIOS} from '#/platform/detection' import {Dimensions} from './types' export async function compressIfNeeded( @@ -165,29 +167,47 @@ interface DoResizeOpts { } async function doResize(localUri: string, opts: DoResizeOpts): Promise<Image> { + // We need to get the dimensions of the image before we resize it. Previously, the library we used allowed us to enter + // a "max size", and it would do the "best possible size" calculation for us. + // Now instead, we have to supply the final dimensions to the manipulation function instead. + // Performing an "empty" manipulation lets us get the dimensions of the original image. React Native's Image.getSize() + // does not work for local files... + const imageRes = await manipulateAsync(localUri, [], {}) + const newDimensions = getResizedDimensions({ + width: imageRes.width, + height: imageRes.height, + }) + for (let i = 0; i < 9; i++) { - const quality = 100 - i * 10 - const resizeRes = await ImageResizer.createResizedImage( + // nearest 10th + const quality = Math.round((1 - 0.1 * i) * 10) / 10 + const resizeRes = await manipulateAsync( localUri, - opts.width, - opts.height, - 'JPEG', - quality, - undefined, - undefined, - undefined, - {mode: opts.mode}, + [{resize: newDimensions}], + { + format: SaveFormat.JPEG, + compress: quality, + }, ) - if (resizeRes.size < opts.maxSize) { + + const fileInfo = await getInfoAsync(resizeRes.uri) + if (!fileInfo.exists) { + throw new Error( + 'The image manipulation library failed to create a new image.', + ) + } + + if (fileInfo.size < opts.maxSize) { + safeDeleteAsync(imageRes.uri) return { - path: normalizePath(resizeRes.path), + path: normalizePath(resizeRes.uri), mime: 'image/jpeg', - size: resizeRes.size, + size: fileInfo.size, width: resizeRes.width, height: resizeRes.height, } } else { - safeDeleteAsync(resizeRes.path) + safeDeleteAsync(resizeRes.uri) } } throw new Error( @@ -311,3 +331,25 @@ async function withTempFile<T>( safeDeleteAsync(tmpDirUri) } } + +export function getResizedDimensions(originalDims: { + width: number + height: number +}) { + if ( + originalDims.width <= POST_IMG_MAX.width && + originalDims.height <= POST_IMG_MAX.height + ) { + return originalDims + } + + const ratio = Math.min( + POST_IMG_MAX.width / originalDims.width, + POST_IMG_MAX.height / originalDims.height, + ) + + return { + width: Math.round(originalDims.width * ratio), + height: Math.round(originalDims.height * ratio), + } +} diff --git a/src/view/com/composer/useExternalLinkFetch.ts b/src/view/com/composer/useExternalLinkFetch.ts index 1a36b5034..60afadefe 100644 --- a/src/view/com/composer/useExternalLinkFetch.ts +++ b/src/view/com/composer/useExternalLinkFetch.ts @@ -2,23 +2,18 @@ import {useEffect, useState} from 'react' import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' -import {logger} from '#/logger' -import {createComposerImage} from '#/state/gallery' -import {useFetchDid} from '#/state/queries/handle' -import {useGetPost} from '#/state/queries/post' -import {useAgent} from '#/state/session' -import * as apilib from 'lib/api/index' -import {POST_IMG_MAX} from 'lib/constants' +import * as apilib from '#/lib/api/index' +import {POST_IMG_MAX} from '#/lib/constants' import { EmbeddingDisabledError, getFeedAsEmbed, getListAsEmbed, getPostAsQuote, getStarterPackAsEmbed, -} from 'lib/link-meta/bsky' -import {getLinkMeta} from 'lib/link-meta/link-meta' -import {resolveShortLink} from 'lib/link-meta/resolve-short-link' -import {downloadAndResize} from 'lib/media/manip' +} from '#/lib/link-meta/bsky' +import {getLinkMeta} from '#/lib/link-meta/link-meta' +import {resolveShortLink} from '#/lib/link-meta/resolve-short-link' +import {downloadAndResize} from '#/lib/media/manip' import { isBskyCustomFeedUrl, isBskyListUrl, @@ -26,8 +21,13 @@ import { isBskyStarterPackUrl, isBskyStartUrl, isShortLink, -} from 'lib/strings/url-helpers' -import {ComposerOpts} from 'state/shell/composer' +} from '#/lib/strings/url-helpers' +import {logger} from '#/logger' +import {createComposerImage} from '#/state/gallery' +import {useFetchDid} from '#/state/queries/handle' +import {useGetPost} from '#/state/queries/post' +import {useAgent} from '#/state/session' +import {ComposerOpts} from '#/state/shell/composer' export function useExternalLinkFetch({ setQuote, |