@@ -651,6 +651,88 @@ export class RawImage {
651
651
}
652
652
}
653
653
654
+ /**
655
+ * Generates a 1D Gaussian kernel.
656
+ * @param {number } kernelSize - Kernel size (must be odd).
657
+ * @param {number } sigma - Standard deviation of the Gaussian.
658
+ * @returns {Array<number> } - The 1D Gaussian kernel.
659
+ */
660
+ generateGaussianKernel ( kernelSize , sigma ) {
661
+ // Kernel must be odd because each pixel must sit evenly in the middle.
662
+ if ( kernelSize % 2 === 0 ) {
663
+ throw new Error ( 'Kernel size must be odd.' ) ;
664
+ }
665
+
666
+ const kernel = [ ] ;
667
+ const center = Math . floor ( kernelSize / 2 ) ;
668
+ let sum = 0 ;
669
+
670
+ for ( let i = 0 ; i < kernelSize ; i ++ ) {
671
+ kernel [ i ] = [ ] ;
672
+ for ( let j = 0 ; j < kernelSize ; j ++ ) {
673
+ const x = i - center ;
674
+ const y = j - center ;
675
+
676
+ // Square the numbers.
677
+ const x2 = x * x ;
678
+ const y2 = y * y ;
679
+ const sigma2 = sigma * sigma ;
680
+
681
+ const value = Math . exp ( - ( x2 + y2 ) / ( 2 * sigma2 ) ) ;
682
+ kernel [ i ] [ j ] = value ;
683
+ sum += value ;
684
+ }
685
+ }
686
+
687
+ // Normalise the kernel.
688
+ for ( let i = 0 ; i < kernelSize ; i ++ ) {
689
+ for ( let j = 0 ; j < kernelSize ; j ++ ) {
690
+ kernel [ i ] [ j ] /= sum ;
691
+ }
692
+ }
693
+
694
+ return kernel ;
695
+ }
696
+
697
+ /**
698
+ * Performs a Gaussian blur on the image.
699
+ * @param {number } kernelSize - Kernel size (must be odd).
700
+ * @param {number } sigma - Standard deviation of the Gaussian.
701
+ * @returns {Promise<RawImage> } - The blurred image.
702
+ */
703
+ async gaussianBlur ( kernelSize = 3 , sigma = 1 ) {
704
+ const kernel = this . generateGaussianKernel ( kernelSize , sigma ) ;
705
+ const output = new Uint8ClampedArray ( this . data . length ) ;
706
+ const halfSize = Math . floor ( kernelSize / 2 ) ;
707
+
708
+ for ( let c = 0 ; c < this . channels ; c ++ ) {
709
+ for ( let y = 0 ; y < this . height ; y ++ ) {
710
+ for ( let x = 0 ; x < this . width ; x ++ ) {
711
+ let sum = 0 ;
712
+
713
+ for ( let ky = - halfSize ; ky < halfSize ; ky ++ ) {
714
+ for ( let kx = - halfSize ; kx < halfSize ; kx ++ ) {
715
+ const pixelX = Math . min ( Math . max ( x + kx , 0 ) , this . width - 1 ) ;
716
+ const pixelY = Math . min ( Math . max ( y + ky , 0 ) , this . height - 1 ) ;
717
+
718
+ const kernelValue = kernel [ ky + halfSize ] [ kx + halfSize ] ;
719
+ const dataIndex = ( pixelY * this . width + pixelX ) * this . channels + c ;
720
+
721
+ sum += this . data [ dataIndex ] * kernelValue ;
722
+ }
723
+ }
724
+
725
+ const outputIndex = ( y * this . width + x ) * this . channels + c ;
726
+ output [ outputIndex ] = sum ;
727
+ }
728
+ }
729
+ }
730
+
731
+ // Update the image data with the blurred result.
732
+ this . data = output ;
733
+ return this ;
734
+ }
735
+
654
736
async toBlob ( type = 'image/png' , quality = 1 ) {
655
737
if ( ! IS_BROWSER_OR_WEBWORKER ) {
656
738
throw new Error ( 'toBlob() is only supported in browser environments.' )
0 commit comments