-
-
Notifications
You must be signed in to change notification settings - Fork 63
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WIP|Implement for react-native-web #112
Open
jacob-israel-turner
wants to merge
24
commits into
mrousavy:master
Choose a base branch
from
FreeplayApp:jt/6
base: master
Could not load branches
Branch not found: {{ refName }}
Could not load tags
Nothing to show
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 17 commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
dde7d52
Move BlurhashModule to its own file
jacob-israel-turner dbb5e91
TEMP|Trying web with webpack
jacob-israel-turner 133aae7
Revert "TEMP|Trying web with webpack"
jacob-israel-turner 22bacde
Add prepare:dev script
jacob-israel-turner 5dbb7af
Add react-native-web/expo-web in examples
jacob-israel-turner d167339
Enhance prepare:dev
jacob-israel-turner 67c70b1
Get web example running
jacob-israel-turner 56d8196
Initial implementation of web working
jacob-israel-turner adf71c5
Tidy up
jacob-israel-turner 318d43c
Note
jacob-israel-turner e9d4d2c
Get iOS example to build
jacob-israel-turner c27164d
Fix native platforms
jacob-israel-turner f81736f
Apply styles to container
jacob-israel-turner bada2a4
Fix linting
jacob-israel-turner ce59868
Create .web files
jacob-israel-turner ea7c389
Cleanup
jacob-israel-turner 6617368
Build web BlurhashModule
jacob-israel-turner 9ac4819
Run prettier
jacob-israel-turner af2a8f9
Update package-lock.json
jacob-israel-turner 7140010
Run Prettier on /example
jacob-israel-turner 9d93f26
Cleanup
jacob-israel-turner cd22852
Move blurhash to peer dependencies
jacob-israel-turner 3720989
Add blurhash to dev dependencies
jacob-israel-turner 777befb
Remove expo-web
jacob-israel-turner File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -57,3 +57,6 @@ buck-out/ | |
|
||
# CocoaPods | ||
/ios/Pods/ | ||
|
||
# Expo | ||
.expo/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { NativeModules } from 'react-native'; | ||
const BlurhashModule: BlurhashModule = NativeModules.BlurhashView; | ||
|
||
type BlurhashModule = { | ||
createBlurhashFromImage: (imageUri: string, componentsX: number, componentsY: number) => Promise<string>, | ||
clearCosineCache: () => void | ||
}; | ||
|
||
export default BlurhashModule; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import { encode } from 'blurhash'; | ||
|
||
type BlurhashModule = { | ||
createBlurhashFromImage: (imageUri: string, componentsX: number, componentsY: number) => Promise<string>, | ||
clearCosineCache: () => void | ||
}; | ||
|
||
async function createBlurhashFromImage (imageUri: string, componentsX: number, componentsY: number): Promise<string> { | ||
const image = await loadImage(imageUri); | ||
const imageData = getImageData(image); | ||
if (!imageData) return ''; | ||
return encode(imageData.data, imageData.width, imageData.height, componentsX, componentsY); | ||
} | ||
|
||
const loadImage = (src: string): Promise<HTMLImageElement> => | ||
new Promise((resolve, reject) => { | ||
const img = document.createElement('img'); | ||
img.crossOrigin = 'Anonymous'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
img.onload = () => resolve(img); | ||
img.onerror = (...args) => reject(args); | ||
img.src = src; | ||
}); | ||
|
||
const getImageData = (image: HTMLImageElement) => { | ||
const canvas: HTMLCanvasElement = document.createElement('canvas'); | ||
canvas.width = image.width; | ||
canvas.height = image.height; | ||
const context = canvas.getContext('2d'); | ||
if (!context) return null; | ||
context.drawImage(image, 0, 0); | ||
return context.getImageData(0, 0, image.width, image.height); | ||
}; | ||
|
||
const BlurhashModule: BlurhashModule = { | ||
createBlurhashFromImage, | ||
clearCosineCache: () => null, | ||
}; | ||
|
||
export default BlurhashModule; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import type { ViewProps } from 'react-native'; | ||
|
||
export default interface BlurhashProps extends Omit<ViewProps, 'children'> { | ||
/** | ||
* 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 `<Blurhash>` view. | ||
*/ | ||
onLoadEnd?: () => void; | ||
|
||
/** | ||
* Emitted when the Blurhash failed to decode/load. | ||
*/ | ||
onLoadError?: (message?: string) => void; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import * as React from 'react'; | ||
import { requireNativeComponent, Platform, NativeSyntheticEvent } from 'react-native'; | ||
import { decode83, decodeDC, isBlurhashValid, RGB } from './utils'; | ||
import type BlurhashProps from './blurhashProps'; | ||
// NativeModules automatically resolves 'BlurhashView' to 'BlurhashViewModule' | ||
import BlurhashModule from './blurhashModule'; | ||
|
||
export class Blurhash extends React.PureComponent<BlurhashProps> { | ||
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<string> { | ||
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 BlurhashModule.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') BlurhashModule.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<typeof isBlurhashValid> { | ||
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) { | ||
const message = event?.nativeEvent?.message; // TODO: Not sure how to get proper value here on web | ||
this.props.onLoadError(message); | ||
} | ||
} | ||
|
||
render() { | ||
return ( | ||
<NativeBlurhashView | ||
{...this.props} | ||
onLoadStart={this._onLoadStart} | ||
onLoadEnd={this._onLoadEnd} | ||
// @ts-expect-error | ||
onLoadError={this._onLoadError} | ||
/> | ||
); | ||
} | ||
} | ||
|
||
const NativeBlurhashView = requireNativeComponent<BlurhashProps>( | ||
'BlurhashView', | ||
// @ts-expect-error this second argument is still not public, but probably required for TurboModules. | ||
Blurhash, | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import React, { useEffect, useRef } from 'react'; | ||
|
||
export type Props = React.CanvasHTMLAttributes<HTMLCanvasElement> & { | ||
getContext?: Function; | ||
decodedBlurhash: Uint8ClampedArray; | ||
height?: number; | ||
onLoadEnd: Function; | ||
punch?: number; | ||
width?: number; | ||
}; | ||
|
||
export default function BlurhashCanvas ({ | ||
// TODO: See how canvas handles unset width/height | ||
decodedBlurhash, | ||
height = 128, | ||
onLoadEnd, | ||
width = 128, | ||
...rest | ||
}: Props) { | ||
const canvasRef = useRef<HTMLCanvasElement>(null); | ||
useEffect(() => { | ||
if (!canvasRef.current) return; | ||
const ctx = canvasRef?.current?.getContext('2d'); | ||
if (!ctx) return; | ||
const imageData = ctx.createImageData(width, height); | ||
imageData.data.set(decodedBlurhash); | ||
ctx.putImageData(imageData, 0, 0); | ||
onLoadEnd(); | ||
}, [canvasRef, decodedBlurhash, height, width, onLoadEnd]); | ||
|
||
return <canvas {...rest} height={height} width={width} ref={canvasRef} /> | ||
}; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could not get the current iOS example to run without these changes.