@@ -386,26 +386,82 @@ export class RawImage {
386386 }
387387
388388 if ( IS_BROWSER_OR_WEBWORKER ) {
389- // TODO use `resample` in browser environment
390-
391389 // Store number of channels before resizing
392390 const numChannels = this . channels ;
393391
394- // Create canvas object for this image
395- const canvas = this . toCanvas ( ) ;
392+ // Create the output array for the resized image
393+ const resizedData = new Uint8ClampedArray ( width * height * numChannels ) ;
396394
397- // Actually perform resizing using the canvas API
398- const ctx = createCanvasFunction ( width , height ) . getContext ( '2d' ) ;
395+ // Scale factors for mapping new dimensions back to original dimensions
396+ const xScale = this . width / width ;
397+ const yScale = this . height / height ;
399398
400- // Draw image to context, resizing in the process
401- ctx . drawImage ( canvas , 0 , 0 , width , height ) ;
399+ switch ( resampleMethod ) {
400+ case 'bilinear' :
401+ // Iterate over each pixel in the new image.
402+ for ( let y = 0 ; y < height ; y ++ ) {
403+ for ( let x = 0 ; x < width ; x ++ ) {
404+ // Map new coordinates to original coordinates.
405+ const srcX = x * xScale ;
406+ const srcY = y * yScale ;
407+
408+ // Calculate the surrounding pixels.
409+ // Ensure that the pixels are within the bounds
410+ // of the image.
411+ const x0 = Math . floor ( srcX ) ;
412+ const x1 = Math . min ( x0 + 1 , this . width - 1 ) ;
413+ const y0 = Math . floor ( srcY ) ;
414+ const y1 = Math . min ( y0 + 1 , this . height - 1 ) ;
415+
416+ // Calculate fractional parts for interpolation.
417+ const dx = srcX - x0 ;
418+ const dy = srcY - y0 ;
419+
420+ for ( let c = 0 ; c < numChannels ; c ++ ) {
421+ // Get the values of the new pixel area.
422+ // Always multiply by the width because we
423+ // storing the data in a 1D array.
424+ // To get the second row, we must add a full
425+ // width, then adding the x offset.
426+ const topLeft = this . data [ ( ( ( y0 * this . width ) + x0 ) * numChannels ) + c ] ;
427+ const topRight = this . data [ ( ( ( y0 * this . width ) + x1 ) * numChannels ) + c ] ;
428+ const bottomLeft = this . data [ ( ( ( y1 * this . width ) + x0 ) * numChannels ) + c ] ;
429+ const bottomRight = this . data [ ( ( ( y1 * this . width ) + x1 ) * numChannels ) + c ] ;
430+
431+ // Perform bilinear interpolation.
432+ // Find the horizontal position along the
433+ // top and bottom rows.
434+ const top = ( topLeft * ( 1 - dx ) ) + ( topRight * dx ) ;
435+ const bottom = ( bottomLeft * ( 1 - dx ) ) + ( bottomRight * dx ) ;
436+ // Find the value between these two values.
437+ const interpolatedValue = ( top * ( 1 - dy ) ) + ( bottom * dy ) ;
438+
439+ // Set the value in the resized data.
440+ resizedData [ ( ( ( y * width ) + x ) * numChannels ) + c ] = Math . round ( interpolatedValue ) ;
441+ }
442+ }
443+ }
444+ break ;
402445
403- // Create image from the resized data
404- const resizedImage = new RawImage ( ctx . getImageData ( 0 , 0 , width , height ) . data , width , height , 4 ) ;
446+ // Fallback to the Canvas API.
447+ default :
448+ // Create canvas object for this image
449+ const canvas = this . toCanvas ( ) ;
405450
406- // Convert back so that image has the same number of channels as before
407- return resizedImage . convert ( numChannels ) ;
451+ // Actually perform resizing using the canvas API
452+ const ctx = createCanvasFunction ( width , height ) . getContext ( '2d' ) ;
453+
454+ // Draw image to context, resizing in the process
455+ ctx . drawImage ( canvas , 0 , 0 , width , height ) ;
456+
457+ // Create image from the resized data
458+ const resizedImage = new RawImage ( ctx . getImageData ( 0 , 0 , width , height ) . data , width , height , 4 ) ;
459+
460+ // Convert back so that image has the same number of channels as before
461+ return resizedImage . convert ( numChannels ) ;
462+ }
408463
464+ return new RawImage ( resizedData , width , height , numChannels ) ;
409465 } else {
410466 // Create sharp image from raw data, and resize
411467 let img = this . toSharp ( ) ;
0 commit comments