haroldo-ok / RgbQuant-SMS.js

RgbQuant.js adapted for quantizing images for the Sega Master System hardware
https://haroldo-ok.github.io/RgbQuant-SMS.js/RgbQuant-SMS.js/demo/index.html
15 stars 1 forks source link

implement predefined palette as option #1

Closed leeoniya closed 9 years ago

leeoniya commented 9 years ago

Hey, noticed your fork. thought you might be interested in this update which implements fixed palettes.

It's a huge speed boost because RgbQuant spends a lot of time doing color analysis/selection for optimal palette reduction. If you already have a predefined palette (as it seems in your SMS case), you can skip the expensive .sample() and .palette() building steps completely and just use reduce(). See included sample.

cheers! Leon

leeoniya commented 9 years ago

after a bit more wiki reading [1], looks like "The Sega Master System had a 6-bit RGB palette (64 colors), with 32 colors on-screen at once".

this complicates things, since it's essentially a combination of a predefined palette and a target sub-palette reduced from the main one using the same methodology that RgbQuant usually uses via histogram sampling. I'm gonna look into allowing the colors option (target palette size) to be used in tandem with the predefined palette.

[1] https://en.wikipedia.org/wiki/List_of_video_game_console_palettes

haroldo-ok commented 9 years ago

Thanks! I created this fork exactly because most color reduction routines don't take into account for those kinds of palette specificities and, as a result, may give poor results when reducing the colors for Master System/Game Gear/Sega Genesis; fortunately, as long as the user only intends to use up to 16 colors, all I had to do was add a preprocessing step to the quantization; using the full 32 colors would be more difficult due to the way the Master System uses them, but I don't intend to go there, yet.

Anyway, the fixed palette option may be useful if the user needs to use an specific palette, but being able to combine both the colors option and the palette option would certainly be even better. ;)

leeoniya commented 9 years ago

@haroldo-ok, well it took some effort, but it's been implemented with 0 hacks. example has been updated.

a few things to keep in mind:

  1. if each frame needs its own palette computed, you'll need to make a new instance of RgbQuant for each frame. this isn't new, it has always been the case and is by design for perf.
  2. predefined palettes will not and cannot be sorted. this is to preserve the original colors' indices.
  3. if the target number of colors is smaller than the palette, the palette will be reduced. for this to be possible, it needs to sample/histogram at least one image. you can skip the sampling step and use the full palette with much higher performance. you can also skip calling .palette() explicitly if you don't need the palette itself - it will be built implicitly on the first .reduce() call.
  4. the palette reduction of a predefined palette will result in a sparse palette (again, to retain original indices); you can see this in the example.

i think that's it. please test it and let me know how it works (or doesn't) for you, leon

leeoniya commented 9 years ago

oh, and use Firefox for running the example, otherwise the shown palettes will look blurry since they're scaled up via CSS and Chrome isnt gonna have image-rendering: pixelated; support till v41 hits stable [1]

[1] https://googlechrome.github.io/samples/image-rendering-pixelated/index.html

haroldo-ok commented 9 years ago

Thank you. it seems to ve working okay. I'll refactor the tile reduction code to use the new feature.

haroldo-ok commented 9 years ago

Okay, code refactored successfully! ;)

leeoniya commented 9 years ago

updated lib to support pre-def palette re-indexing (and compacting/sorting) via reIndex: true. also added a dithering threshold: e.g. dithDelta: 0.05 will not dither pixels that differ by < 5% from palette.

haroldo-ok commented 9 years ago

Okay, thanks, changes merged.