import * as React from 'react'; import { Platform, type NativeSyntheticEvent, type ViewProps } from 'react-native'; import NativeBlurhashModule from './specs/NativeBlurhashModule'; import NativeBlurhashView from './specs/NativeBlurhashView'; import { decode83, decodeDC, isBlurhashValid, type RGB } from './utils'; export interface BlurhashProps extends Omit { /** * The blurhash string to use. Example: `LGFFaXYk^6#M@-5c,1J5@[or[Q6`. */ blurhash: string; /** * The width (resolution) to decode to. Higher values decrease performance, use `16` for large lists, otherwise you can increase it to `32`. * @default 32 */ decodeWidth?: number; /** * The height (resolution) to decode to. Higher values decrease performance, use `16` for large lists, otherwise you can increase it to `32`. * @default 32 */ decodeHeight?: number; /** * Adjusts the contrast of the output image. Tweak it if you want a different look for your placeholders. * @default 1.0 */ decodePunch?: number; /** * Asynchronously decode the Blurhash on a background Thread instead of the UI-Thread. * Read the [performance documentation](https://github.com/mrousavy/react-native-blurhash#performance) * before enabling this. * @default false */ decodeAsync?: boolean; /** * Adjusts the resize mode of the image. * @default 'cover' */ resizeMode?: 'cover' | 'contain' | 'stretch' | 'center'; /** * Emitted when the Blurhash received new parameters and started to decode the given `blurhash` string. */ onLoadStart?: () => void; /** * Emitted when the Blurhash successfully decoded the given `blurhash` string and rendered the image to the `` view. */ onLoadEnd?: () => void; /** * Emitted when the Blurhash failed to decode/load. */ onLoadError?: (message?: string) => void; } export class Blurhash extends React.PureComponent { static displayName = 'Blurhash'; constructor(props: BlurhashProps) { super(props); this._onLoadStart = this._onLoadStart.bind(this); this._onLoadEnd = this._onLoadEnd.bind(this); this._onLoadError = this._onLoadError.bind(this); } /** * Encodes the given image URI to a blurhash string * @param imageUri An URI to an Image parseable by the react native image loader * @param componentsX The number of X components * @param componentsY The number of Y components * @example * const blurhash = await Blurhash.encode('https://blurha.sh/assets/images/img2.jpg') */ static encode(imageUri: string, componentsX: number, componentsY: number): Promise { if (typeof imageUri !== 'string') throw new Error('imageUri must be a non-empty string!'); if (typeof componentsX !== 'number') throw new Error('componentsX must be a valid positive number!'); if (typeof componentsY !== 'number') throw new Error('componentsY must be a valid positive number!'); return NativeBlurhashModule.createBlurhashFromImage(imageUri, componentsX, componentsY); } /** * Gets the average color in a given blurhash string. * * This uses the JS blurhash decoder, so it might be slow. * @param blurhash The blurhash string * @example * const averageColor = Blurhash.getAverageColor(`LGFFaXYk^6#M@-5c,1J5@[or[Q6.`) */ static getAverageColor(blurhash: string): RGB | undefined { if (blurhash == null || blurhash.length < 7) return undefined; const value = decode83(blurhash.substring(2, 6)); return decodeDC(value); } /** * Clears the cosine cache and frees up memory. * * @platform Android * @see https://github.com/mrousavy/react-native-blurhash#cosine-operations */ static clearCosineCache(): void { if (Platform.OS === 'android') NativeBlurhashModule.clearCosineCache(); else console.warn('Blurhash.clearCosineCache is only available on Android.'); } /** * Verifies if the given blurhash is valid by checking it's type, length and size flag. * * This uses the JS blurhash decoder, so it might be slow. * @param blurhash The given blurhash string */ static isBlurhashValid(blurhash: string): ReturnType { return isBlurhashValid(blurhash); } _onLoadStart() { if (this.props.onLoadStart != null) this.props.onLoadStart(); } _onLoadEnd() { if (this.props.onLoadEnd != null) this.props.onLoadEnd(); } _onLoadError(event?: NativeSyntheticEvent<{ message?: string }>) { if (this.props.onLoadError != null) this.props.onLoadError(event?.nativeEvent?.message); } render() { return ; } }