(imageData)
| 25 | |
| 26 | const _cache = new WeakMap(); |
| 27 | |
| 28 | /** |
| 29 | * @param {ImageData} imageData RGBA pixel buffer (only the R channel is read) |
| 30 | * @returns {{ meanGrad: number, sharpFrac: number, pixelsPerEdge: number }} |
| 31 | */ |
| 32 | export function analyzeTexture(imageData) { |
| 33 | if (!imageData) { |
| 34 | return { meanGrad: 0, sharpFrac: 0, pixelsPerEdge: 4.0 }; |
| 35 | } |
| 36 | const cached = _cache.get(imageData); |
| 37 | if (cached) return cached; |
| 38 | |
| 39 | const { width, height, data } = imageData; |
| 40 | if (width < 3 || height < 3) { |
| 41 | const fallback = { meanGrad: 0, sharpFrac: 0, pixelsPerEdge: 4.0 }; |
| 42 | _cache.set(imageData, fallback); |
| 43 | return fallback; |
| 44 | } |
| 45 | |
| 46 | const stride = width * 4; |
| 47 | let sumGrad = 0; |
| 48 | let sharpCount = 0; |
| 49 | let pixelCount = 0; |
| 50 | |
| 51 | // Central differences on the red channel; skip the 1-pixel border. |
| 52 | for (let y = 1; y < height - 1; y++) { |
| 53 | const rowOff = y * stride; |
| 54 | for (let x = 1; x < width - 1; x++) { |
| 55 | const i = rowOff + x * 4; |
| 56 | const left = data[i - 4]; |
| 57 | const right = data[i + 4]; |
| 58 | const up = data[i - stride]; |
| 59 | const down = data[i + stride]; |
| 60 | const dx = (right - left) * 0.5; |
| 61 | const dy = (down - up) * 0.5; |
| 62 | const mag = Math.sqrt(dx * dx + dy * dy); |
| 63 | sumGrad += mag; |
| 64 | if (mag > SHARP_THRESHOLD) sharpCount++; |
| 65 | pixelCount++; |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | const meanGrad = sumGrad / pixelCount; |
| 70 | const sharpFrac = sharpCount / pixelCount; |
| 71 | |
| 72 | let pixelsPerEdge; |
| 73 | if (sharpFrac > 0.15 || meanGrad > 50) pixelsPerEdge = 1.0; |
| 74 | else if (sharpFrac > 0.05 || meanGrad > 20) pixelsPerEdge = 1.5; |
| 75 | else if (meanGrad > 8) pixelsPerEdge = 2.5; |
| 76 | else pixelsPerEdge = 4.0; |
| 77 | |
| 78 | const result = { meanGrad, sharpFrac, pixelsPerEdge }; |
| 79 | _cache.set(imageData, result); |
no test coverage detected