Skip to content

Commit

Permalink
Dithering fixes:�- Only apply dithering to pixels that meet the trans…
Browse files Browse the repository at this point in the history
…parency threshold. This prevents said pixels from "bleeding" their quantization error on to other pixels, creating a solid first line of pixels on some images with a transparent background.�- Remove the alpha component in the quantization error, so that it is only RGB values. This prevents the appearance of jagged borders on images with a transparent background.
  • Loading branch information
Frumple committed Nov 20, 2023
1 parent 39a592a commit 40c2469
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 5 deletions.
6 changes: 3 additions & 3 deletions src/ts/helpers/dithering-helpers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ColorObject } from 'colorjs.io/types/src/color';

export type QuantizationError = [number, number, number, number];
// Quantization error consists of RGB but no alpha
export type QuantizationError = [number, number, number];

// TODO: Support other dithering algorithms
export function applyDitheringToImageData(imageData: ImageData, pixelStartIndex: number, originalColor: ColorObject, newColor: ColorObject): void {
Expand Down Expand Up @@ -40,12 +41,11 @@ function getQuantizationError(originalColor: ColorObject, newColor: ColorObject)
originalColor.coords[0] - newColor.coords[0],
originalColor.coords[1] - newColor.coords[1],
originalColor.coords[2] - newColor.coords[2],
(originalColor.alpha !== undefined && newColor.alpha !== undefined) ? originalColor.alpha - newColor.alpha : 0,
]
}

function applyQuantizationErrorToPixel(imageDataArray: Uint8ClampedArray, quantizationError: QuantizationError, pixelStartIndex: number, weight: number): void {
for (let offset = 0; offset <= 3; offset++) {
for (let offset = 0; offset <= 2; offset++) {
imageDataArray[pixelStartIndex + offset] += quantizationError[offset] * weight * 255;
}
}
11 changes: 9 additions & 2 deletions src/ts/workers/upload-worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,10 @@ class UploadWorker {
setPixelToImageData(outputImageData, pixelStartIndex, nearestMapColor);

if (this.settings.dithering === 'floyd-steinberg') {
applyDitheringToImageData(inputImageData, pixelStartIndex, originalPixel.color, nearestMapColor);
// Only apply dithering if the original pixel color meets the transparency threshold
if (this.doesColorMeetTransparencyThreshold(originalPixel.color)) {
applyDitheringToImageData(inputImageData, pixelStartIndex, originalPixel.color, nearestMapColor);
}
}

return nearestMapColorId;
Expand All @@ -218,7 +221,7 @@ class UploadWorker {
const originalColor = originalPixel.color;

// Return the transparent map color if the original color doesn't meet the transparency threshold
if (originalColor.alpha !== undefined && originalColor.alpha * 255 < this.settings.transparency) {
if (! this.doesColorMeetTransparencyThreshold(originalColor)) {
return 0;
}

Expand All @@ -236,6 +239,10 @@ class UploadWorker {
return nearestMapColorId;
}

doesColorMeetTransparencyThreshold(originalColor: ColorObject): boolean {
return originalColor.alpha !== undefined && originalColor.alpha * 255 >= this.settings.transparency;
}

searchForNearestMapColorId(originalColor: ColorObject, mapColors: readonly ColorObject[]): number {
let nearestDistance = Number.MAX_VALUE;
let nearestMapColorId = 0;
Expand Down

0 comments on commit 40c2469

Please sign in to comment.