1+ // Define a Bayer matrix (e.g., 4x4)
2+ const bayerMatrix4x4 = [
3+ [ 0 , 8 , 2 , 10 ] ,
4+ [ 12 , 4 , 14 , 6 ] ,
5+ [ 3 , 11 , 1 , 9 ] ,
6+ [ 15 , 7 , 13 , 5 ]
7+ ] ;
8+
9+ // Normalize the Bayer matrix values to a 0-1 range
10+ const normalizeBayerMatrix = ( matrix ) => {
11+ const maxVal = matrix . flat ( ) . reduce ( ( max , val ) => Math . max ( max , val ) , 0 ) ;
12+ return matrix . map ( row => row . map ( val => val / ( maxVal + 1 ) ) ) ; // +1 to ensure values are strictly less than 1
13+ } ;
14+
15+ const normalizedBayerMatrix = normalizeBayerMatrix ( bayerMatrix4x4 ) ;
16+
17+ /**
18+ * Applies Bayer dithering to an image data array between two specified colors.
19+ * @param imageData The ImageData object containing pixel data.
20+ * @param color1 The first color (e.g., [r, g, b]).
21+ * @param color2 The second color (e.g., [r, g, b]).
22+ * @returns The dithered ImageData object.
23+ */
24+ function applyBayerDithering (
25+ imageData ,
26+ color1 ,
27+ color2
28+ ) {
29+ const { data, width, height } = imageData ;
30+ const matrixSize = normalizedBayerMatrix . length ;
31+
32+ for ( let y = 0 ; y < height ; y ++ ) {
33+ for ( let x = 0 ; x < width ; x ++ ) {
34+ const i = ( y * width + x ) * 4 ; // Index for R component
35+
36+ // Calculate grayscale intensity (luminance) of the original pixel
37+ const r = data [ i ] ;
38+ const g = data [ i + 1 ] ;
39+ const b = data [ i + 2 ] ;
40+ const intensity = ( 0.299 * r + 0.587 * g + 0.114 * b ) / 255 ; // Normalize to 0-1
41+
42+ // Get the threshold from the normalized Bayer matrix
43+ const threshold = normalizedBayerMatrix [ y % matrixSize ] [ x % matrixSize ] ;
44+
45+ // Assign color based on intensity and threshold
46+ if ( intensity > threshold ) {
47+ data [ i ] = color2 [ 0 ] ;
48+ data [ i + 1 ] = color2 [ 1 ] ;
49+ data [ i + 2 ] = color2 [ 2 ] ;
50+ } else {
51+ data [ i ] = color1 [ 0 ] ;
52+ data [ i + 1 ] = color1 [ 1 ] ;
53+ data [ i + 2 ] = color1 [ 2 ] ;
54+ }
55+ }
56+ }
57+ return imageData ;
58+ }
59+ /*
60+ // Example usage (assuming you have an ImageData object from a canvas)
61+ const canvas = document.querySelector('canvas');
62+ const ctx = canvas.getContext('2d');
63+
64+ const linearGradient = ctx.createLinearGradient(0, 0, canvas.width, 0); // x0, y0, x1, y1
65+
66+ // Add color stops
67+ linearGradient.addColorStop(0, 'white'); // Start color at 0%
68+ linearGradient.addColorStop(1, 'black'); // End color at 100%
69+
70+ // Apply the gradient to fillStyle and draw a rectangle
71+ ctx.fillStyle = linearGradient;
72+ ctx.fillRect(0, 0, canvas.width, canvas.height);
73+
74+ const originalImageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
75+ const ditheredImageData = applyBayerDithering(originalImageData, [0, 0, 0], [255, 255, 255]);
76+ ctx.putImageData(ditheredImageData, 0, 0);
77+ */
0 commit comments