Skip to content
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

Improve image blob generation time by up to 5x! #35

Open
dgwyer opened this issue Oct 10, 2023 · 0 comments
Open

Improve image blob generation time by up to 5x! #35

dgwyer opened this issue Oct 10, 2023 · 0 comments

Comments

@dgwyer
Copy link

dgwyer commented Oct 10, 2023

@ryanwelcher I was just rewatching the OpenAI videos you streamed a while back and I played around with optimizing the blob generation time.

We can actually create the blob directly without having to create an itermediate Canvas element and call the canvas.toBlob() method. Using this method I saw up to 5x speed increase but in most cases it was around 4x increase!

Here's the updated code for helpers.js with performance timers included, which log the function run times to the console. The convertImageToBlobOld and loadImage functions can be removed now if using the new method.

Hope it's useful. 🙂

image

import apiFetch from '@wordpress/api-fetch';
import { uploadMedia } from '@wordpress/media-utils';
import { cleanForSlug } from '@wordpress/url';
import { API_KEY } from './constants';

export const convertImageToBlobOld = async ( base64Image ) => {
	// Start the timer
	const startTime = performance.now();

	const image = new Image();
	image.src = `data:image/png;base64,${ base64Image }`;
	image.crossOrigin = 'anonymous';
	await loadImage( image );

	const canvas = document.createElement( 'canvas' );
	canvas.width = image.width;
	canvas.height = image.height;

	const ctx = canvas.getContext( '2d' );
	if ( ! ctx ) return;
	ctx.drawImage( image, 0, 0 );

	const blob = await new Promise( ( resolve ) => {
		canvas.toBlob( ( blob ) => {
			blob && resolve( blob );
		}, 'image/jpeg' );
	} );

	// Stop the timer
	const endTime = performance.now();

	// Calculate the execution time in milliseconds
	const executionTime = endTime - startTime;

	// Log the execution time to the console
	console.log(
		`Execution time for convertImageToBlobOld(): ${ executionTime } milliseconds`
	);

	return blob;
};

const loadImage = ( img ) => {
	return new Promise( ( resolve ) => ( img.onload = resolve ) );
};

export const convertImageToBlob = ( base64Image ) => {
	// Start the timer
	const startTime = performance.now();

	// Your base64 encoded image string
	const base64ImageSrc = `data:image/png;base64,${ base64Image }`;

	// Convert the base64 string to binary data
	const binaryData = atob( base64ImageSrc.split( ',' )[ 1 ] );

	// Create a Uint8Array from the binary data
	const uint8Array = new Uint8Array( binaryData.length );
	for ( let i = 0; i < binaryData.length; i++ ) {
		uint8Array[ i ] = binaryData.charCodeAt( i );
	}

	// Create a Blob from the Uint8Array
	const blob = new Blob( [ uint8Array ], { type: 'image/png' } );

	// Stop the timer
	const endTime = performance.now();

	// Calculate the execution time in milliseconds
	const executionTime = endTime - startTime;

	// Log the execution time to the console
	console.log(
		`Execution time for convertImageToBlob(): ${ executionTime } milliseconds`
	);

	// Return the Blob
	return blob;
};

export async function makeRequest( {
	prompt = '',
	numberOfImages = 1,
	size = '256x256',
	format = 'b64_json',
} ) {
	const request = await fetch(
		'https://api.openai.com/v1/images/generations',
		{
			method: 'POST',
			headers: {
				'Content-Type': 'application/json',
				Authorization: `Bearer ${ API_KEY }`,
			},
			body: JSON.stringify( {
				prompt,
				n: numberOfImages,
				size,
				response_format: format,
			} ),
		}
	);
	const json = await request.json();
	return json.data;
}

export const uploadImageToMediaLibrary = async (
	imageSrc,
	prompt,
	uploadCallback
) => {
	const blob = await convertImageToBlob( imageSrc );
	const blobOld = await convertImageToBlobOld( imageSrc );
	const status = await uploadMedia( {
		filesList: [ new File( [ blob ], `${ cleanForSlug( prompt ) }.png` ) ],
		onFileChange: ( [ fileObj ] ) => {
			return uploadCallback( fileObj );
		},
		onError: console.error,
	} );
	return status;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant