* Makes a particular rgb color and colors that are nearly the same in an ImageData completely * transparent. * @returns True if the result is "empty", meaning all pixels are fully transparent.
(imageData: ImageData, bg: IColor, fg: IColor, enableThresholdCheck: boolean)
| 1081 | * @returns True if the result is "empty", meaning all pixels are fully transparent. |
| 1082 | */ |
| 1083 | function clearColor(imageData: ImageData, bg: IColor, fg: IColor, enableThresholdCheck: boolean): boolean { |
| 1084 | // Get color channels |
| 1085 | const r = bg.rgba >>> 24; |
| 1086 | const g = bg.rgba >>> 16 & 0xFF; |
| 1087 | const b = bg.rgba >>> 8 & 0xFF; |
| 1088 | const fgR = fg.rgba >>> 24; |
| 1089 | const fgG = fg.rgba >>> 16 & 0xFF; |
| 1090 | const fgB = fg.rgba >>> 8 & 0xFF; |
| 1091 | |
| 1092 | // Calculate a threshold that when below a color will be treated as transpart when the sum of |
| 1093 | // channel value differs. This helps improve rendering when glyphs overlap with others. This |
| 1094 | // threshold is calculated relative to the difference between the background and foreground to |
| 1095 | // ensure important details of the glyph are always shown, even when the contrast ratio is low. |
| 1096 | // The number 12 is largely arbitrary to ensure the pixels that escape the cell in the test case |
| 1097 | // were covered (fg=#8ae234, bg=#c4a000). |
| 1098 | const threshold = Math.floor((Math.abs(r - fgR) + Math.abs(g - fgG) + Math.abs(b - fgB)) / 12); |
| 1099 | |
| 1100 | // Set alpha channel of relevent pixels to 0 |
| 1101 | let isEmpty = true; |
| 1102 | for (let offset = 0; offset < imageData.data.length; offset += 4) { |
| 1103 | // Check exact match |
| 1104 | if (imageData.data[offset] === r && |
| 1105 | imageData.data[offset + 1] === g && |
| 1106 | imageData.data[offset + 2] === b) { |
| 1107 | imageData.data[offset + 3] = 0; |
| 1108 | } else { |
| 1109 | // Check the threshold based difference |
| 1110 | if (enableThresholdCheck && |
| 1111 | (Math.abs(imageData.data[offset] - r) + |
| 1112 | Math.abs(imageData.data[offset + 1] - g) + |
| 1113 | Math.abs(imageData.data[offset + 2] - b)) < threshold) { |
| 1114 | imageData.data[offset + 3] = 0; |
| 1115 | } else { |
| 1116 | isEmpty = false; |
| 1117 | } |
| 1118 | } |
| 1119 | } |
| 1120 | |
| 1121 | return isEmpty; |
| 1122 | } |
| 1123 | |
| 1124 | function checkCompletelyTransparent(imageData: ImageData): boolean { |
| 1125 | for (let offset = 0; offset < imageData.data.length; offset += 4) { |