Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Black/White dithering #48

Open
mpp opened this issue Feb 13, 2019 · 3 comments
Open

Black/White dithering #48

mpp opened this issue Feb 13, 2019 · 3 comments

Comments

@mpp
Copy link

mpp commented Feb 13, 2019

Hi, I'm not sure if this is an issue. Probably only my ignorance.

I want to apply a dithering algorithm to an image that come from an input (code as an angular component):

@Component({
  selector: "graphics-form",
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
      <div>
        <button mat-stroked-button color="primary" (click)="fileInput.click()">
          Upload
        </button>
        <input hidden type="file" #fileInput (change)="onFileChange($event)" />
      </div>
  `
})
export class GraphicsFormComponent {

  onFileChange(event) {
    if (event.target.files && event.target.files.length) {
      var img = new Image();
      img.onload = function() {
        const canvas: HTMLCanvasElement = document.createElement("canvas");
        canvas.height = img.height;
        canvas.width = img.width;
        const ctx = canvas.getContext("2d");
        ctx.drawImage(img, 0, 0);
        URL.revokeObjectURL(img.src);
        console.log(
          "the image is drawn",
          img.width,
          img.height,
          canvas.width,
          canvas.height
        );

        const pointContainer = iq.utils.PointContainer.fromHTMLCanvasElement(
          canvas
        );
        const distanceCalculator = new iq.distance.EuclideanBT709();
        const paletteQuantizer = new iq.palette.WuQuant(distanceCalculator, 2);
        paletteQuantizer.sample(pointContainer);
        const palette = paletteQuantizer.quantizeSync();
        console.log(palette);

        const imageQuantizer = new iq.image.ErrorDiffusionArray(
          distanceCalculator,
          iq.image.ErrorDiffusionArrayKernel.Jarvis
        );
        const outPointContainer = imageQuantizer.quantizeSync(
          pointContainer,
          palette
        );
        var uint8array = outPointContainer.toUint8Array();

        console.log(uint8array);
      };
      img.src = URL.createObjectURL(event.target.files[0]);
    }
  }
}

The palette contains 2 points (colors?):
_pointArray: Array(2)
0: Point {uint32: 85133568, a: 5, b: 19, g: 9, r: 0, …}
1: Point {uint32: 4104476424, a: 244, b: 165, g: 87, r: 8, …}
length: 2

Is the method correct?
How should I proceed? I would like to have only black/white pixels. Should I iterate the canvas pixels and substitute with black each time I find (a: 5, b: 19, g: 9, r: 0) and with white each time I find (a: 244, b: 165, g: 87, r: 8)?

Thanks!

@mpp
Copy link
Author

mpp commented Feb 13, 2019

I saw that setting the palette manually I get what I was looking for:

palette.add(iq.utils.Point.createByRGBA(0, 0, 0, 255)); // black
palette.add(iq.utils.Point.createByRGBA(255, 255, 255, 0)); // white

but why the Alpha channel of white has to be zero? If I set to 255 the result is wrong (or at least not what I expect).

@gretchen-blackwood
Copy link

I'm having an issue that I think is related. When I generate a palette from an image it correctly limits the number of colors to what I specify when creating the palette quantizer. However, if I then add dithering, it completely ignores the target number of colors. Is there a way to limit the total number of colors used including after dithering?

@ibezkrovnyi
Copy link
Owner

Quantizer: WuQuant
Color distance: EuclideanBT709
Dithering: Jarvis

Palette with alpha = 255 for white color:

  palette = new iq.utils.Palette();
  palette.add(iq.utils.Point.createByRGBA(0, 0, 0, 255))
  palette.add(iq.utils.Point.createByRGBA(255, 255, 255, 255))

image

Palette with alpha = 0 for white color:

  palette = new iq.utils.Palette();
  palette.add(iq.utils.Point.createByRGBA(0, 0, 0, 255))
  palette.add(iq.utils.Point.createByRGBA(255, 255, 255, 0))

image

Demo app where to put these changes:

palette = paletteQuantizer.quantizeSync();

How to run:

"start": "pnpm build && http-server ./ -c-1"

Summary:

Looks like alpha=255 (as expected) for white color gives best results.

Note: for images without alpha channel with alpha=0 for white color in palette the above settings give empty black box. Changing to Manhatten gives better results, however because one of the colors in palette now has alpha 0 - final result now depends on background color.

Please test first in demo app and then please let me know if it is still an issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants