mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2026-07-31 07:44:24 +02:00
nQuant: backport Gadgetbridge fixups
This commit is contained in:
committed by
José Rebelo
parent
c8da8b4717
commit
07b1e593b3
@@ -37,7 +37,7 @@ public class BitmapUtilities {
|
|||||||
return ditherPixel;
|
return ditherPixel;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int[] quantize_image(final int width, final int height, final int[] pixels, final Integer[] palette, final Ditherable ditherable, final boolean hasSemiTransparency, final boolean dither)
|
static int[] quantize_image(final int width, final int height, final int[] pixels, final int[] palette, final Ditherable ditherable, final boolean hasSemiTransparency, final boolean dither)
|
||||||
{
|
{
|
||||||
int[] qPixels = new int[pixels.length];
|
int[] qPixels = new int[pixels.length];
|
||||||
int nMaxColors = palette.length;
|
int nMaxColors = palette.length;
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ public class BlueNoise {
|
|||||||
return Color.argb(a_pix, r_pix, g_pix, b_pix);
|
return Color.argb(a_pix, r_pix, g_pix, b_pix);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int[] processImagePixels(final Integer[] palette, final int[] qPixels) {
|
static int[] processImagePixels(final int[] palette, final int[] qPixels) {
|
||||||
int[] qPixel32s = new int[qPixels.length];
|
int[] qPixel32s = new int[qPixels.length];
|
||||||
for (var i = 0; i < qPixels.length; ++i)
|
for (var i = 0; i < qPixels.length; ++i)
|
||||||
qPixel32s[i] = palette[qPixels[i]];
|
qPixel32s[i] = palette[qPixels[i]];
|
||||||
@@ -204,7 +204,7 @@ public class BlueNoise {
|
|||||||
return qPixel32s;
|
return qPixel32s;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int[] dither(final int width, final int height, final int[] pixels, final Integer[] palette, final Ditherable ditherable, final int[] qPixels, final float weight)
|
public static int[] dither(final int width, final int height, final int[] pixels, final int[] palette, final Ditherable ditherable, final int[] qPixels, final float weight)
|
||||||
{
|
{
|
||||||
final float strength = 1 / 3f;
|
final float strength = 1 / 3f;
|
||||||
for (int y = 0; y < height; ++y) {
|
for (int y = 0; y < height; ++y) {
|
||||||
|
|||||||
@@ -3,5 +3,5 @@ package com.android.nQuant;
|
|||||||
public interface Ditherable {
|
public interface Ditherable {
|
||||||
public int getColorIndex(final int c);
|
public int getColorIndex(final int c);
|
||||||
|
|
||||||
public short nearestColorIndex(final Integer[] palette, final int c, final int pos);
|
public short nearestColorIndex(final int[] palette, final int c, final int pos);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public class GilbertCurve {
|
|||||||
private final int width, height;
|
private final int width, height;
|
||||||
private final double weight;
|
private final double weight;
|
||||||
private final int[] pixels;
|
private final int[] pixels;
|
||||||
private final Integer[] palette;
|
private final int[] palette;
|
||||||
private final int[] qPixels;
|
private final int[] qPixels;
|
||||||
private final Ditherable ditherable;
|
private final Ditherable ditherable;
|
||||||
private final float[] saliencies;
|
private final float[] saliencies;
|
||||||
@@ -47,7 +47,7 @@ public class GilbertCurve {
|
|||||||
private final int margin, thresold;
|
private final int margin, thresold;
|
||||||
private static final float BLOCK_SIZE = 343f;
|
private static final float BLOCK_SIZE = 343f;
|
||||||
|
|
||||||
private GilbertCurve(final int width, final int height, final int[] image, final Integer[] palette, final int[] qPixels, final Ditherable ditherable, final float[] saliencies, double weight, boolean dither)
|
private GilbertCurve(final int width, final int height, final int[] image, final int[] palette, final int[] qPixels, final Ditherable ditherable, final float[] saliencies, double weight, boolean dither)
|
||||||
{
|
{
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
@@ -279,7 +279,7 @@ public class GilbertCurve {
|
|||||||
qPixels[bidx] = palette[qPixels[bidx]];
|
qPixels[bidx] = palette[qPixels[bidx]];
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generate2d(int x, int y, int ax, int ay, int bx, int by) throws Exception {
|
private void generate2d(int x, int y, int ax, int ay, int bx, int by) {
|
||||||
int w = Math.abs(ax + ay);
|
int w = Math.abs(ax + ay);
|
||||||
int h = Math.abs(bx + by);
|
int h = Math.abs(bx + by);
|
||||||
int dax = Integer.signum(ax);
|
int dax = Integer.signum(ax);
|
||||||
@@ -353,7 +353,7 @@ public class GilbertCurve {
|
|||||||
weights[0] += 1f - weight;
|
weights[0] += 1f - weight;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void run() throws Exception
|
private void run()
|
||||||
{
|
{
|
||||||
if(!sortedByYDiff)
|
if(!sortedByYDiff)
|
||||||
initWeights(DITHER_MAX);
|
initWeights(DITHER_MAX);
|
||||||
@@ -364,7 +364,7 @@ public class GilbertCurve {
|
|||||||
generate2d(0, 0, 0, height, width, 0);
|
generate2d(0, 0, 0, height, width, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int[] dither(final int width, final int height, final int[] pixels, final Integer[] palette, final Ditherable ditherable, final float[] saliencies, final double weight, final boolean dither) throws Exception
|
public static int[] dither(final int width, final int height, final int[] pixels, final int[] palette, final Ditherable ditherable, final float[] saliencies, final double weight, final boolean dither)
|
||||||
{
|
{
|
||||||
int[] qPixels = new int[pixels.length];
|
int[] qPixels = new int[pixels.length];
|
||||||
new GilbertCurve(width, height, pixels, palette, qPixels, ditherable, saliencies, weight, dither).run();
|
new GilbertCurve(width, height, pixels, palette, qPixels, ditherable, saliencies, weight, dither).run();
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ package com.android.nQuant;
|
|||||||
Copyright (c) 2018-2026 Miller Cy Chan
|
Copyright (c) 2018-2026 Miller Cy Chan
|
||||||
* error measure; time used is proportional to number of bins squared - WJ */
|
* error measure; time used is proportional to number of bins squared - WJ */
|
||||||
|
|
||||||
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
|
|
||||||
import com.android.nQuant.CIELABConvertor.Lab;
|
import com.android.nQuant.CIELABConvertor.Lab;
|
||||||
@@ -25,6 +26,10 @@ public class PnnLABQuantizer extends PnnQuantizer {
|
|||||||
super(fname);
|
super(fname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PnnLABQuantizer(Bitmap bitmap) {
|
||||||
|
super(bitmap);
|
||||||
|
}
|
||||||
|
|
||||||
private static final class Pnnbin {
|
private static final class Pnnbin {
|
||||||
float ac = 0, Lc = 0, Ac = 0, Bc = 0, err = 0;
|
float ac = 0, Lc = 0, Ac = 0, Bc = 0, err = 0;
|
||||||
float cnt = 0;
|
float cnt = 0;
|
||||||
@@ -128,7 +133,7 @@ public class PnnLABQuantizer extends PnnQuantizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Integer[] pnnquan(final int[] pixels, int nMaxColors)
|
protected int[] pnnquan(final int[] pixels, int nMaxColors)
|
||||||
{
|
{
|
||||||
short quan_rt = (short) 1;
|
short quan_rt = (short) 1;
|
||||||
Pnnbin[] bins = new Pnnbin[65536];
|
Pnnbin[] bins = new Pnnbin[65536];
|
||||||
@@ -192,7 +197,7 @@ public class PnnLABQuantizer extends PnnQuantizer {
|
|||||||
|
|
||||||
if(pixelMap.size() <= nMaxColors) {
|
if(pixelMap.size() <= nMaxColors) {
|
||||||
/* Fill palette */
|
/* Fill palette */
|
||||||
Integer[] palette = new Integer[pixelMap.size()];
|
int[] palette = new int[pixelMap.size()];
|
||||||
int k = 0;
|
int k = 0;
|
||||||
for (Integer pixel : pixelMap.keySet()) {
|
for (Integer pixel : pixelMap.keySet()) {
|
||||||
palette[k++] = pixel;
|
palette[k++] = pixel;
|
||||||
@@ -312,7 +317,7 @@ public class PnnLABQuantizer extends PnnQuantizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Fill palette */
|
/* Fill palette */
|
||||||
Integer[] palette = new Integer[extbins > 0 ? nMaxColors : maxbins];
|
int[] palette = new int[extbins > 0 ? nMaxColors : maxbins];
|
||||||
short k = 0;
|
short k = 0;
|
||||||
for (int i = 0; k < palette.length; ++k) {
|
for (int i = 0; k < palette.length; ++k) {
|
||||||
Lab lab1 = new Lab();
|
Lab lab1 = new Lab();
|
||||||
@@ -327,7 +332,7 @@ public class PnnLABQuantizer extends PnnQuantizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected short nearestColorIndex(final Integer[] palette, int c, final int pos)
|
protected short nearestColorIndex(final int[] palette, int c, final int pos)
|
||||||
{
|
{
|
||||||
final int offset = !isNano ? c : BitmapUtilities.getColorIndex(c, hasSemiTransparency, m_transparentPixelIndex >= 0);
|
final int offset = !isNano ? c : BitmapUtilities.getColorIndex(c, hasSemiTransparency, m_transparentPixelIndex >= 0);
|
||||||
Short got = nearestMap.get(offset);
|
Short got = nearestMap.get(offset);
|
||||||
@@ -404,7 +409,7 @@ public class PnnLABQuantizer extends PnnQuantizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected short closestColorIndex(final Integer[] palette, int c, final int pos)
|
protected short closestColorIndex(final int[] palette, int c, final int pos)
|
||||||
{
|
{
|
||||||
if (Color.alpha(c) <= alphaThreshold)
|
if (Color.alpha(c) <= alphaThreshold)
|
||||||
return nearestColorIndex(palette, c, pos);
|
return nearestColorIndex(palette, c, pos);
|
||||||
@@ -481,7 +486,7 @@ public class PnnLABQuantizer extends PnnQuantizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public short nearestColorIndex(Integer[] palette, int c, final int pos) {
|
public short nearestColorIndex(int[] palette, int c, final int pos) {
|
||||||
if (palette.length <= 4)
|
if (palette.length <= 4)
|
||||||
return PnnLABQuantizer.this.nearestColorIndex(palette, c, pos);
|
return PnnLABQuantizer.this.nearestColorIndex(palette, c, pos);
|
||||||
return PnnLABQuantizer.this.closestColorIndex(palette, c, pos);
|
return PnnLABQuantizer.this.closestColorIndex(palette, c, pos);
|
||||||
@@ -490,7 +495,7 @@ public class PnnLABQuantizer extends PnnQuantizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int[] dither(final int[] cPixels, Integer[] palette, int width, int height, boolean dither) throws Exception
|
public int[] dither(final int[] cPixels, int[] palette, int width, int height, boolean dither)
|
||||||
{
|
{
|
||||||
Ditherable ditherable = getDitherFn();
|
Ditherable ditherable = getDitherFn();
|
||||||
if(hasSemiTransparency)
|
if(hasSemiTransparency)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ Copyright (c) 2018-2026 Miller Cy Chan
|
|||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -36,6 +37,10 @@ public class PnnQuantizer {
|
|||||||
fromBitmap(fname);
|
fromBitmap(fname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PnnQuantizer(Bitmap bitmap) {
|
||||||
|
fromBitmap(bitmap);
|
||||||
|
}
|
||||||
|
|
||||||
private void fromBitmap(Bitmap bitmap) {
|
private void fromBitmap(Bitmap bitmap) {
|
||||||
width = bitmap.getWidth();
|
width = bitmap.getWidth();
|
||||||
height = bitmap.getHeight();
|
height = bitmap.getHeight();
|
||||||
@@ -131,7 +136,7 @@ public class PnnQuantizer {
|
|||||||
return cnt -> cnt;
|
return cnt -> cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Integer[] pnnquan(final int[] pixels, int nMaxColors)
|
protected int[] pnnquan(final int[] pixels, int nMaxColors)
|
||||||
{
|
{
|
||||||
short quan_rt = (short) 1;
|
short quan_rt = (short) 1;
|
||||||
Pnnbin[] bins = new Pnnbin[65536];
|
Pnnbin[] bins = new Pnnbin[65536];
|
||||||
@@ -255,7 +260,7 @@ public class PnnQuantizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Fill palette */
|
/* Fill palette */
|
||||||
Integer[] palette = new Integer[extbins > 0 ? nMaxColors : maxbins];
|
int[] palette = new int[extbins > 0 ? nMaxColors : maxbins];
|
||||||
short k = 0;
|
short k = 0;
|
||||||
for (int i = 0; k < palette.length; ++k) {
|
for (int i = 0; k < palette.length; ++k) {
|
||||||
palette[k] = Color.argb((int) bins[i].ac, (int) bins[i].rc, (int) bins[i].gc, (int) bins[i].bc);
|
palette[k] = Color.argb((int) bins[i].ac, (int) bins[i].rc, (int) bins[i].gc, (int) bins[i].bc);
|
||||||
@@ -266,7 +271,7 @@ public class PnnQuantizer {
|
|||||||
return palette;
|
return palette;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected short nearestColorIndex(final Integer[] palette, int c, final int pos)
|
protected short nearestColorIndex(final int[] palette, int c, final int pos)
|
||||||
{
|
{
|
||||||
final int offset = weight > .015 ? c : BitmapUtilities.getColorIndex(c, hasSemiTransparency, m_transparentPixelIndex >= 0);
|
final int offset = weight > .015 ? c : BitmapUtilities.getColorIndex(c, hasSemiTransparency, m_transparentPixelIndex >= 0);
|
||||||
Short got = nearestMap.get(offset);
|
Short got = nearestMap.get(offset);
|
||||||
@@ -310,7 +315,7 @@ public class PnnQuantizer {
|
|||||||
return k;
|
return k;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected short closestColorIndex(final Integer[] palette, int c, final int pos)
|
protected short closestColorIndex(final int[] palette, int c, final int pos)
|
||||||
{
|
{
|
||||||
short k = 0;
|
short k = 0;
|
||||||
if (Color.alpha(c) <= alphaThreshold)
|
if (Color.alpha(c) <= alphaThreshold)
|
||||||
@@ -382,7 +387,7 @@ public class PnnQuantizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public short nearestColorIndex(Integer[] palette, int c, final int pos) {
|
public short nearestColorIndex(int[] palette, int c, final int pos) {
|
||||||
if(dither)
|
if(dither)
|
||||||
return PnnQuantizer.this.nearestColorIndex(palette, c, pos);
|
return PnnQuantizer.this.nearestColorIndex(palette, c, pos);
|
||||||
return PnnQuantizer.this.closestColorIndex(palette, c, pos);
|
return PnnQuantizer.this.closestColorIndex(palette, c, pos);
|
||||||
@@ -390,7 +395,7 @@ public class PnnQuantizer {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int[] dither(final int[] cPixels, Integer[] palette, int width, int height, boolean dither) throws Exception
|
protected int[] dither(final int[] cPixels, int[] palette, int width, int height, boolean dither)
|
||||||
{
|
{
|
||||||
Ditherable ditherable = getDitherFn(dither);
|
Ditherable ditherable = getDitherFn(dither);
|
||||||
if(hasSemiTransparency)
|
if(hasSemiTransparency)
|
||||||
@@ -406,7 +411,7 @@ public class PnnQuantizer {
|
|||||||
return qPixels;
|
return qPixels;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Bitmap convert(int nMaxColors, boolean dither) throws Exception {
|
public Pair<Bitmap, int[]> convert(int nMaxColors, boolean dither) {
|
||||||
int semiTransCount = 0;
|
int semiTransCount = 0;
|
||||||
for (int i = 0; i < pixels.length; ++i) {
|
for (int i = 0; i < pixels.length; ++i) {
|
||||||
int pixel = pixels[i];
|
int pixel = pixels[i];
|
||||||
@@ -435,11 +440,11 @@ public class PnnQuantizer {
|
|||||||
PR = coeffs[0][0]; PG = coeffs[0][1]; PB = coeffs[0][2];
|
PR = coeffs[0][0]; PG = coeffs[0][1]; PB = coeffs[0][2];
|
||||||
}
|
}
|
||||||
|
|
||||||
Integer[] palette;
|
int[] palette;
|
||||||
if (nMaxColors > 2)
|
if (nMaxColors > 2)
|
||||||
palette = pnnquan(pixels, nMaxColors);
|
palette = pnnquan(pixels, nMaxColors);
|
||||||
else {
|
else {
|
||||||
palette = new Integer[nMaxColors];
|
palette = new int[nMaxColors];
|
||||||
weight = 1;
|
weight = 1;
|
||||||
if (m_transparentPixelIndex >= 0) {
|
if (m_transparentPixelIndex >= 0) {
|
||||||
palette[0] = m_transparentColor;
|
palette[0] = m_transparentColor;
|
||||||
@@ -452,7 +457,9 @@ public class PnnQuantizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int[] qPixels = dither(pixels, palette, width, height, dither);
|
int[] qPixels = dither(pixels, palette, width, height, dither);
|
||||||
return Bitmap.createBitmap(qPixels, width, height, Bitmap.Config.ARGB_8888);
|
return new Pair<>(
|
||||||
|
Bitmap.createBitmap(qPixels, width, height, Bitmap.Config.ARGB_8888),
|
||||||
|
palette);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasAlpha() {
|
public boolean hasAlpha() {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* All files under this package were adapted from https://github.com/mcychan/nQuant.android
|
* All files under this package were adapted from https://github.com/mcychan/nQuant.android
|
||||||
* at 8f18e9d7536e71a90d0d1333968e07688b7ebf09
|
* at 12822f15c92695136f1761b6b72c9bd18dc70c46
|
||||||
* <p>
|
* <p>
|
||||||
* Changes done:
|
* Changes done:
|
||||||
* - Update PnnQuantizer to allow for access to the palette after convertion
|
* - Update PnnQuantizer to allow for access to the palette after convertion
|
||||||
|
|||||||
Reference in New Issue
Block a user