Overview
The useStyleTransfer hook manages a style transfer model instance for applying artistic styles to images. It transforms content images to match the artistic style of a reference style.
Import
import { useStyleTransfer } from 'react-native-executorch' ;
Hook Signature
const styleTransfer = useStyleTransfer ({ model , preventLoad }: StyleTransferProps ): StyleTransferType
Parameters
Object containing model source Source location of the style transfer model binary file (.pte)
If true, prevents automatic model loading and downloading when the hook mounts
Return Value
Returns an object with the following properties and methods:
State Properties
Indicates whether the style transfer model is loaded and ready to process images.
Indicates whether the model is currently processing an image.
Download progress as a value between 0 and 1.
Contains error details if the model fails to load or encounters an error during style transfer.
Methods
Executes the model’s forward pass to apply artistic style to the provided image. forward ( imageSource : string ): Promise < string >
Image source as a file path, URI, or base64 string
Returns a promise that resolves to a string containing the stylized image (typically as a base64 string or file URI).
Usage Examples
Basic Style Transfer
import { useStyleTransfer } from 'react-native-executorch' ;
import { useState } from 'react' ;
import { launchImageLibrary } from 'react-native-image-picker' ;
function StyleTransferApp () {
const [ originalUri , setOriginalUri ] = useState < string | null >( null );
const [ styledUri , setStyledUri ] = useState < string | null >( null );
const styleTransfer = useStyleTransfer ({
model: {
modelSource: 'https://huggingface.co/.../style-transfer.pte' ,
},
});
const applyStyle = async ( uri : string ) => {
if ( ! styleTransfer . isReady ) return ;
try {
const result = await styleTransfer . forward ( uri );
setStyledUri ( result );
console . log ( 'Style applied successfully!' );
} catch ( error ) {
console . error ( 'Style transfer failed:' , error );
}
};
const pickAndStyle = async () => {
const result = await launchImageLibrary ({ mediaType: 'photo' });
if ( result . assets ?.[ 0 ]?. uri ) {
const uri = result . assets [ 0 ]. uri ;
setOriginalUri ( uri );
await applyStyle ( uri );
}
};
return (
< View >
< Text > Status : { styleTransfer . isReady ? 'Ready' : 'Loading...' }</ Text >
< Text > Progress : {(styleTransfer.downloadProgress * 100). toFixed (0)}%</ Text >
< Button
title = "Pick Image & Apply Style"
onPress = { pickAndStyle }
disabled = {!styleTransfer. isReady }
/>
{ styleTransfer . isGenerating && < ActivityIndicator />}
< View style = {{ flexDirection : 'row' }} >
{ originalUri && (
< View style = {{ flex : 1 }} >
< Text > Original :</ Text >
< Image
source = {{ uri : originalUri }}
style = {{ width : 200 , height : 200 }}
/>
</ View >
)}
{ styledUri && (
< View style = {{ flex : 1 }} >
< Text > Styled :</ Text >
< Image
source = {{ uri : styledUri }}
style = {{ width : 200 , height : 200 }}
/>
</ View >
)}
</ View >
</ View >
);
}
Before/After Comparison
import { useStyleTransfer } from 'react-native-executorch' ;
import { useState } from 'react' ;
import Slider from '@react-native-community/slider' ;
function BeforeAfterComparison () {
const [ originalUri , setOriginalUri ] = useState < string | null >( null );
const [ styledUri , setStyledUri ] = useState < string | null >( null );
const [ sliderValue , setSliderValue ] = useState ( 0.5 );
const styleTransfer = useStyleTransfer ({
model: {
modelSource: require ( './models/mosaic-style.pte' ),
},
});
return (
< View >
< View style = {{ position : 'relative' , width : 400 , height : 400 }} >
{ styledUri && (
< Image
source = {{ uri : styledUri }}
style = {{
position : 'absolute' ,
width : 400 ,
height : 400 ,
}}
/>
)}
{ originalUri && (
< Image
source = {{ uri : originalUri }}
style = {{
position : 'absolute' ,
width : 400 ,
height : 400 ,
clipPath : `inset(0 ${ ( 1 - sliderValue ) * 100 } % 0 0)` ,
}}
/>
)}
</ View >
< Slider
value = { sliderValue }
onValueChange = { setSliderValue }
minimumValue = { 0 }
maximumValue = { 1 }
/>
< Text > Slide to compare </ Text >
</ View >
);
}
Camera with Live Style Preview
import { useStyleTransfer } from 'react-native-executorch' ;
import { Camera } from 'react-native-vision-camera' ;
import { useState , useRef } from 'react' ;
function LiveStyleCamera () {
const cameraRef = useRef < Camera >( null );
const [ styledImage , setStyledImage ] = useState < string | null >( null );
const [ isProcessing , setIsProcessing ] = useState ( false );
const styleTransfer = useStyleTransfer ({
model: {
modelSource: 'https://example.com/style.pte' ,
},
});
const captureAndStyle = async () => {
if ( ! cameraRef . current || ! styleTransfer . isReady || isProcessing ) return ;
setIsProcessing ( true );
try {
const photo = await cameraRef . current . takePhoto ();
const styled = await styleTransfer . forward ( photo . path );
setStyledImage ( styled );
} catch ( error ) {
console . error ( 'Style transfer failed:' , error );
} finally {
setIsProcessing ( false );
}
};
return (
< View style = {{ flex : 1 }} >
< Camera
ref = { cameraRef }
style = {{ flex : 1 }}
device = { /* camera device */ }
isActive = {! isProcessing }
/>
{ styledImage && (
< Image
source = {{ uri : styledImage }}
style = {{
position : 'absolute' ,
top : 20 ,
right : 20 ,
width : 100 ,
height : 100 ,
borderWidth : 2 ,
borderColor : 'white' ,
}}
/>
)}
< Button
title = {isProcessing ? 'Processing...' : 'Capture & Style' }
onPress = { captureAndStyle }
disabled = {!styleTransfer.isReady || isProcessing }
/>
</ View >
);
}
Batch Style Transfer
import { useStyleTransfer } from 'react-native-executorch' ;
import { useState } from 'react' ;
function BatchStyleTransfer () {
const [ images , setImages ] = useState < string []>([]);
const [ processedImages , setProcessedImages ] = useState < string []>([]);
const [ progress , setProgress ] = useState ( 0 );
const styleTransfer = useStyleTransfer ({
model: {
modelSource: require ( './models/style.pte' ),
},
});
const processBatch = async () => {
if ( ! styleTransfer . isReady ) return ;
const results : string [] = [];
for ( let i = 0 ; i < images . length ; i ++ ) {
try {
const styled = await styleTransfer . forward ( images [ i ]);
results . push ( styled );
setProgress (( i + 1 ) / images . length );
} catch ( error ) {
console . error ( `Failed to process image ${ i } :` , error );
}
}
setProcessedImages ( results );
setProgress ( 1 );
};
return (
< View >
< Text > Images : { images . length }</ Text >
< Text > Progress : {( progress * 100). toFixed (0)}%</ Text >
< Button
title = "Process All"
onPress = { processBatch }
disabled = {!styleTransfer.isReady || images. length === 0 }
/>
< ScrollView horizontal >
{ processedImages . map (( uri , idx ) => (
< Image
key = { idx }
source = {{ uri }}
style = {{ width : 150 , height : 150 , margin : 5 }}
/>
))}
</ ScrollView >
</ View >
);
}
Save Styled Image
import { useStyleTransfer } from 'react-native-executorch' ;
import { useState } from 'react' ;
import RNFS from 'react-native-fs' ;
import Share from 'react-native-share' ;
function StyleTransferWithSave () {
const [ styledUri , setStyledUri ] = useState < string | null >( null );
const styleTransfer = useStyleTransfer ({
model: {
modelSource: 'https://example.com/style.pte' ,
},
});
const applyStyleAndSave = async ( imageUri : string ) => {
if ( ! styleTransfer . isReady ) return ;
try {
const result = await styleTransfer . forward ( imageUri );
setStyledUri ( result );
// Save to device
const filename = `styled_ ${ Date . now () } .jpg` ;
const destPath = ` ${ RNFS . DocumentDirectoryPath } / ${ filename } ` ;
if ( result . startsWith ( 'data:' )) {
// Base64 image
const base64Data = result . split ( ',' )[ 1 ];
await RNFS . writeFile ( destPath , base64Data , 'base64' );
} else {
// File URI
await RNFS . copyFile ( result , destPath );
}
console . log ( 'Saved to:' , destPath );
return destPath ;
} catch ( error ) {
console . error ( 'Style transfer or save failed:' , error );
}
};
const shareStyled = async () => {
if ( ! styledUri ) return ;
try {
await Share . open ({
url: styledUri ,
type: 'image/jpeg' ,
});
} catch ( error ) {
console . error ( 'Share failed:' , error );
}
};
return (
< View >
{ styledUri && (
<>
< Image source = {{ uri : styledUri }} style = {{ width : 300 , height : 300 }} />
< Button title = "Share" onPress = { shareStyled } />
</>
)}
</ View >
);
}
import { useStyleTransfer } from 'react-native-executorch' ;
import { useState } from 'react' ;
function StyleTransferWithMetrics () {
const [ processingTime , setProcessingTime ] = useState < number | null >( null );
const [ styledUri , setStyledUri ] = useState < string | null >( null );
const styleTransfer = useStyleTransfer ({
model: {
modelSource: require ( './models/style.pte' ),
},
});
const measureStyleTransfer = async ( imageUri : string ) => {
if ( ! styleTransfer . isReady ) return ;
const startTime = Date . now ();
try {
const result = await styleTransfer . forward ( imageUri );
const endTime = Date . now ();
setStyledUri ( result );
setProcessingTime ( endTime - startTime );
console . log ( `Style transfer completed in ${ endTime - startTime } ms` );
} catch ( error ) {
console . error ( 'Style transfer failed:' , error );
}
};
return (
< View >
{ processingTime && (
< Text > Processing time : { processingTime } ms </ Text >
)}
{ styledUri && (
< Image source = {{ uri : styledUri }} style = {{ width : 300 , height : 300 }} />
)}
</ View >
);
}
Notes
The model automatically loads when the hook mounts unless preventLoad is set to true.
Style transfer can be computationally intensive and may take several seconds depending on image size and device capabilities.
For best results, consider resizing large images before applying style transfer to improve processing speed.
Common Use Cases
Photo Filters : Apply artistic filters to user photos
Creative Apps : Build photo editing apps with style effects
Art Generation : Create artistic variations of images
Social Media : Add unique visual effects to shared content
Content Creation : Generate stylized content for marketing
Image Size : Larger images take longer to process
Model Complexity : Different style models have varying performance
Device Capability : Performance varies by device hardware
Memory Usage : Monitor memory during batch processing
See Also