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

Partial opacity color sampling #20

Open
adworetzky opened this issue Mar 7, 2022 · 5 comments
Open

Partial opacity color sampling #20

adworetzky opened this issue Mar 7, 2022 · 5 comments
Labels
enhancement New feature or request

Comments

@adworetzky
Copy link

It could be a feature or could be a bug but when you load a png with transparency, the resulting pixelated image retains semi transparent colors from the border between opaque pixels and the background. It might be helpful to have a method to strip the underlying partially transparent pixels of their opacity so that the resulting image keeps the selected color palette. Well, I guess it wouldn't be striping it but rather rounding up or down. Like If a pixel is mostly transparent, just round it down to nothing but if its mostly opaque, round it up. It would feel more like pixel art since that rarely has partial transparency.
Example image where the transparency is retained from the original img:
download (15)

@giventofly
Copy link
Owner

I'm not sure I quite understand. Can you give me 2 examples (one with the transparency other without) + the original image?

@adworetzky
Copy link
Author

adworetzky commented Mar 8, 2022

The difference is highlighted below. For example in the first image, the pixels on the border of the original image are semi transparent and it seems that this transparency makes it to the final pixelated drawing. This transparency causes some of the pixels in the final drawing to be colors that don't adhere to the original palette.
download (20)

But in this image where there is a background, every pixel is opaque so every pixel in the final pixelated drawing adheres to the user defined palette.
download (19)

The difference in treatment in highlighted below
image

@giventofly
Copy link
Owner

Sorry for taking so long to give some feedback, this issue is not forgotten I haven't had the time to pick on this project.

but I will check and give some feedback as soon as possible

@giventofly giventofly added the enhancement New feature or request label Apr 13, 2022
@jetrotal
Copy link

jetrotal commented Apr 13, 2022

Since opacity is usually a float number between 0 to 1.
This could be solved by adding an opacity threshold checker,
where (here comes some pseudo code, sorry):

config.opacityThreshold = .5 //or any value the user can customize. 
if (pixel.opacity >= config.opacityThreshold) pixel.opacity = 1
else pixel.opacity = 0

@jetrotal
Copy link

jetrotal commented Apr 13, 2022

I guess I kinda solved it... the pixel opacity comes from 0 to 255 as any other color
I wish I could force it to consider areas of the image that are transparent by choice, but idk.

image
Live Demo: https://codepen.io/jetrotau/pen/popOqrV?editors=1111


Opacity/Alpha is stored on image data as the 4th color input (R,G,B,A), so I created a function that reworks the alpha property before using putImageData:

{
      key: "crushAlpha",
      value: function(threshold = 127.5, opacity = 255) {
    const w = this.drawto.width;
    const h = this.drawto.height;
    var imgPixels = this.ctx.getImageData(0, 0, w, h);
    for (var y = 0; y < imgPixels.height; y++) {
        for (var x = 0; x < imgPixels.width; x++) {
            var i = y * 4 * imgPixels.width + x * 4;

            0 < imgPixels.data[i + 3] && imgPixels.data[i + 3] <= opacity ? //0 < pixelAlpha < 255 
                imgPixels.data[i + 3] = (imgPixels.data[i + 3] < threshold ?
                    0 : (Math.round(opacity) >= threshold ? (opacity - imgPixels.data[i + 3] / 2) + imgPixels.data[i + 3] : (opacity * imgPixels.data[i + 3]) / 127)) :
                ""
        }
    }
    this.ctx.putImageData(imgPixels, 0, 0, 0, 0, imgPixels.width, imgPixels.height);
    return this;
}
    }

to use it, call it like:

var threshold  = 50 // Any number between 0 and 255. Default is 127.5
var opacity = 255  // Any number between 0 and 255. Default is 255
px.draw().pixelate().crushAlpha( threshold, opacity )

Edits were made on pixelit.min.js


on pixelit.js, it would look like this:

/**
   * color similarity between colors, lower is better
   * @param {number} threshold number between 0 and 255
   * @param {number} opacity number between 0 and 255
   */

 crushAlpha(threshold = 127.5, opacity = 255) {
  const w = this.drawto.width;
  const h = this.drawto.height;
  var imgPixels = this.ctx.getImageData(0, 0, w, h);
  for (var y = 0; y < imgPixels.height; y++) {
      for (var x = 0; x < imgPixels.width; x++) {
          var i = y * 4 * imgPixels.width + x * 4;

          0 < imgPixels.data[i + 3] && imgPixels.data[i + 3] <= opacity ? //0 < pixelAlpha < 255 
              imgPixels.data[i + 3] = (imgPixels.data[i + 3] < threshold ?
                  0 : (Math.round(opacity) >= threshold ? (opacity - imgPixels.data[i + 3] / 2) + imgPixels.data[i + 3] : (opacity * imgPixels.data[i + 3]) / 127)) :
              ""
      }
  }
  this.ctx.putImageData(imgPixels, 0, 0, 0, 0, imgPixels.width, imgPixels.height);
  return this;
}

I'm not sure, needs testing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants