@@ -687,11 +687,13 @@ export class RawImage {
687
687
* Performs a Gaussian blur on the image.
688
688
* @param {number } kernelSize - Kernel size (must be odd).
689
689
* @param {number } sigma - Standard deviation of the Gaussian.
690
+ * @param {number } numChunks - Number of chunks to divide the image into for parallel processing.
690
691
* @returns {Promise<RawImage> } - The blurred image.
691
692
*/
692
- async gaussianBlur ( kernelSize = 3 , sigma = 1 ) {
693
+ async gaussianBlur ( kernelSize = 3 , sigma = 1 , numChunks = 4 ) {
693
694
const kernel = this . generateGaussianKernel ( kernelSize , sigma ) ;
694
695
const halfSize = Math . floor ( kernelSize / 2 ) ;
696
+
695
697
const width = this . width ;
696
698
const height = this . height ;
697
699
const channels = this . channels ;
@@ -703,43 +705,67 @@ export class RawImage {
703
705
const horizontalPass = new Float32Array ( this . data . length ) ;
704
706
const verticalPass = new Uint8ClampedArray ( this . data . length ) ;
705
707
706
- // Horizontal pass.
707
- for ( let y = 0 ; y < height ; y ++ ) {
708
- for ( let x = 0 ; x < width ; x ++ ) {
709
- for ( let c = 0 ; c < channels ; c ++ ) {
710
- let sum = 0 ;
711
-
712
- for ( let kx = - halfSize ; kx <= halfSize ; kx ++ ) {
713
- const pixelX = Math . min ( Math . max ( x + kx , 0 ) , width - 1 ) ;
714
- const dataIndex = ( ( y * width ) + pixelX ) * channels + c ;
715
- const kernelValue = kernel [ kx + halfSize ] ;
716
- sum += this . data [ dataIndex ] * kernelValue ;
708
+ const chunkHeight = Math . ceil ( height / numChunks ) ;
709
+
710
+ // Process horizontal pass in chunks.
711
+ const horizontalPassPromises = Array . from ( { length : numChunks } , ( _ , chunkIndex ) => {
712
+ return new Promise ( resolve => {
713
+ const startY = chunkIndex * chunkHeight ;
714
+ const endY = Math . min ( startY + chunkHeight , height ) ;
715
+
716
+ for ( let y = startY ; y < endY ; y ++ ) {
717
+ for ( let x = 0 ; x < width ; x ++ ) {
718
+ for ( let c = 0 ; c < channels ; c ++ ) {
719
+ let sum = 0 ;
720
+
721
+ for ( let kx = - halfSize ; kx <= halfSize ; kx ++ ) {
722
+ const pixelX = Math . min ( Math . max ( x + kx , 0 ) , width - 1 ) ;
723
+ const dataIndex = ( ( ( y * width ) + pixelX ) * channels ) + c ;
724
+ const kernelValue = kernel [ kx + halfSize ] ;
725
+ sum += this . data [ dataIndex ] * kernelValue ;
726
+ }
727
+
728
+ const outputIndex = ( ( ( y * width ) + x ) * channels ) + c ;
729
+ horizontalPass [ outputIndex ] = sum ;
730
+ }
717
731
}
718
-
719
- const outputIndex = ( ( y * width ) + x ) * channels + c ;
720
- horizontalPass [ outputIndex ] = sum ;
721
732
}
722
- }
723
- }
724
-
725
- // Vertical pass.
726
- for ( let y = 0 ; y < height ; y ++ ) {
727
- for ( let x = 0 ; x < width ; x ++ ) {
728
- for ( let c = 0 ; c < channels ; c ++ ) {
729
- let sum = 0 ;
733
+ resolve ( ) ;
734
+ } ) ;
735
+ } ) ;
730
736
731
- for ( let ky = - halfSize ; ky <= halfSize ; ky ++ ) {
732
- const pixelY = Math . min ( Math . max ( y + ky , 0 ) , height - 1 ) ;
733
- const dataIndex = ( ( pixelY * width ) + x ) * channels + c ;
734
- const kernelValue = kernel [ ky + halfSize ] ;
735
- sum += horizontalPass [ dataIndex ] * kernelValue ;
737
+ // Wait for all horizontal chunks to complete.
738
+ await Promise . all ( horizontalPassPromises ) ;
739
+
740
+ // Process vertical pass in chunks.
741
+ const verticalPassPromises = Array . from ( { length : numChunks } , ( _ , chunkIndex ) => {
742
+ return new Promise ( resolve => {
743
+ const startY = chunkIndex * chunkHeight ;
744
+ const endY = Math . min ( startY + chunkHeight , height ) ;
745
+
746
+ for ( let y = startY ; y < endY ; y ++ ) {
747
+ for ( let x = 0 ; x < width ; x ++ ) {
748
+ for ( let c = 0 ; c < channels ; c ++ ) {
749
+ let sum = 0 ;
750
+
751
+ for ( let ky = - halfSize ; ky <= halfSize ; ky ++ ) {
752
+ const pixelY = Math . min ( Math . max ( y + ky , 0 ) , height - 1 ) ;
753
+ const dataIndex = ( ( ( pixelY * width ) + x ) * channels ) + c ;
754
+ const kernelValue = kernel [ ky + halfSize ] ;
755
+ sum += horizontalPass [ dataIndex ] * kernelValue ;
756
+ }
757
+
758
+ const outputIndex = ( ( ( y * width ) + x ) * channels ) + c ;
759
+ verticalPass [ outputIndex ] = sum ;
760
+ }
736
761
}
737
-
738
- const outputIndex = ( ( y * width ) + x ) * channels + c ;
739
- verticalPass [ outputIndex ] = sum ;
740
762
}
741
- }
742
- }
763
+ resolve ( ) ;
764
+ } ) ;
765
+ } ) ;
766
+
767
+ // Wait for all vertical chunks to complete.
768
+ await Promise . all ( verticalPassPromises ) ;
743
769
744
770
this . data = verticalPass ;
745
771
return this ;
0 commit comments