7
7
#include "Tiles.h"
8
8
/**************************************/
9
9
10
- //! Dither modes available
11
- #define DITHER_NONE ( 0) //! No dither
12
- #define DITHER_ORDERED (n ) ( n) //! Ordered dithering (Kernel size: (2^n) x (2^n))
13
- #define DITHER_FLOYDSTEINBERG (-1) //! Floyd-Steinberg (diffusion)
14
-
15
- //! Dither settings
16
- //! NOTE: Ordered dithering gives consistent tiled results, but Floyd-Steinberg can look nicer.
17
- //! Recommend dither level of 0.5 for ordered, and 1.0 for Floyd-Steinberg.
18
- //! NOTE: DITHER_NO_ALPHA disables dithering on the alpha channel.
19
- #define DITHER_TYPE DITHER_ORDERED(3)
20
- #define DITHER_LEVEL 0.5f
21
- #define DITHER_NO_ALPHA
22
-
23
10
//! When not zero, the PSNR for each channel will be displayed
24
11
#define MEASURE_PSNR 1
25
12
@@ -49,14 +36,32 @@ struct BGRAf_t Qualetize(
49
36
int MaxTilePals ,
50
37
int MaxPalSize ,
51
38
int PalUnused ,
39
+ const struct BGRA8_t * BitRange ,
40
+ int DitherType ,
52
41
int ReplaceImage
53
42
) {
54
43
int i ;
55
44
56
45
//! Do processing
57
46
TilesData_QuantizePalettes (TilesData , Palette , MaxTilePals , MaxPalSize , PalUnused );
58
47
59
- //! Convert pixels to palettized
48
+ //! Reduce palette range
49
+ {
50
+ struct BGRAf_t DitherVal = BGRAf_FromBGRA (& (const struct BGRA8_t ){1 ,1 ,1 ,0 }, BitRange );
51
+ DitherVal = BGRAf_Muli (& DitherVal , 0.25f );
52
+ for (i = 0 ;i < MaxTilePals * MaxPalSize ;i ++ ) {
53
+ struct BGRAf_t p = BGRAf_FromYCoCg (& Palette [i ]);
54
+
55
+ //! Apply dithering bias to every second colour
56
+ if (i & 1 ) p = BGRAf_Add (& p , & DitherVal );
57
+
58
+ struct BGRA8_t p2 = BGRA_FromBGRAf (& p , BitRange );
59
+ p = BGRAf_FromBGRA (& p2 , BitRange );
60
+ Palette [i ] = BGRAf_AsYCoCg (& p );
61
+ }
62
+ }
63
+
64
+ //! Get parameters, pointers, etc.
60
65
int x , y ;
61
66
int ImgW = Image -> Width ;
62
67
int ImgH = Image -> Height ;
@@ -68,39 +73,41 @@ struct BGRAf_t Qualetize(
68
73
#endif
69
74
const uint8_t * PxSrcIdx = Image -> ColPal ? Image -> PxIdx : NULL ;
70
75
const struct BGRA8_t * PxSrcBGR = Image -> ColPal ? Image -> ColPal : Image -> PxBGR ;
71
- #if DITHER_TYPE != DITHER_NONE
72
- # if DITHER_TYPE == DITHER_FLOYDSTEINBERG
73
- struct BGRAf_t * PxDiffuse = TilesData -> PxData ;
74
- for (y = 0 ;y < ImgH ;y ++ ) for (x = 0 ;x < ImgW ;x ++ ) PxDiffuse [y * ImgW + x ] = (struct BGRAf_t ){0 ,0 ,0 ,0 };
75
- # else
76
- struct BGRAf_t * PaletteSpread = TilesData -> PxData ;
77
- for (i = 0 ;i < MaxTilePals ;i ++ ) {
78
- //! Find the mean values of this palette
79
- int n ;
80
- struct BGRAf_t Mean = (struct BGRAf_t ){0 ,0 ,0 ,0 };
81
- for (n = PalUnused ;n < MaxPalSize ;n ++ ) Mean = BGRAf_Add (& Mean , & Palette [i * MaxPalSize + n ]);
82
- Mean = BGRAf_Divi (& Mean , MaxPalSize - PalUnused );
83
-
84
- //! Compute slopes and store to the palette spread
85
- //! NOTE: For some reason, it works better to use the square root as a weight.
86
- //! This probably gives a value somewhere between the arithmetic mean and
87
- //! the smooth-max, which should result in better quality.
88
- struct BGRAf_t Spread = {0 ,0 ,0 ,0 }, SpreadW = {0 ,0 ,0 ,0 };
89
- for (n = PalUnused ;n < MaxPalSize ;n ++ ) {
90
- struct BGRAf_t d = BGRAf_Sub (& Palette [i * MaxPalSize + n ], & Mean );
91
- d = BGRAf_Abs (& d );
92
- struct BGRAf_t w = BGRAf_Sqrt (& d );
93
- d = BGRAf_Mul (& d , & w );
94
- Spread = BGRAf_Add (& Spread , & d );
95
- SpreadW = BGRAf_Add (& SpreadW , & w );
96
- }
97
- PaletteSpread [i ] = BGRAf_DivSafe (& Spread , & SpreadW , NULL );
76
+
77
+ //! Initialize dither patterns
78
+ struct BGRAf_t * PxDiffuse = TilesData -> PxData ; //! DITHER_FLOYDSTEINBERG only
79
+ struct BGRAf_t * PaletteSpread = TilesData -> PxData ; //! DITHER_ORDERED only
80
+ if (DitherType != DITHER_NONE ) {
81
+ if (DitherType == DITHER_FLOYDSTEINBERG ) {
82
+ for (y = 0 ;y < ImgH ;y ++ ) for (x = 0 ;x < ImgW ;x ++ ) PxDiffuse [y * ImgW + x ] = (struct BGRAf_t ){0 ,0 ,0 ,0 };
83
+ } else for (i = 0 ;i < MaxTilePals ;i ++ ) {
84
+ //! Find the mean values of this palette
85
+ int n ;
86
+ struct BGRAf_t Mean = (struct BGRAf_t ){0 ,0 ,0 ,0 };
87
+ for (n = PalUnused ;n < MaxPalSize ;n ++ ) Mean = BGRAf_Add (& Mean , & Palette [i * MaxPalSize + n ]);
88
+ Mean = BGRAf_Divi (& Mean , MaxPalSize - PalUnused );
89
+
90
+ //! Compute slopes and store to the palette spread
91
+ //! NOTE: For some reason, it works better to use the square root as a weight.
92
+ //! This probably gives a value somewhere between the arithmetic mean and
93
+ //! the smooth-max, which should result in better quality.
94
+ struct BGRAf_t Spread = {0 ,0 ,0 ,0 }, SpreadW = {0 ,0 ,0 ,0 };
95
+ for (n = PalUnused ;n < MaxPalSize ;n ++ ) {
96
+ struct BGRAf_t d = BGRAf_Sub (& Palette [i * MaxPalSize + n ], & Mean );
97
+ d = BGRAf_Abs (& d );
98
+ struct BGRAf_t w = BGRAf_Sqrt (& d );
99
+ d = BGRAf_Mul (& d , & w );
100
+ Spread = BGRAf_Add (& Spread , & d );
101
+ SpreadW = BGRAf_Add (& SpreadW , & w );
102
+ }
103
+ PaletteSpread [i ] = BGRAf_DivSafe (& Spread , & SpreadW , NULL );
98
104
#ifdef DITHER_NO_ALPHA
99
- PaletteSpread [i ].a = 0.0f ;
105
+ PaletteSpread [i ].a = 0.0f ;
100
106
#endif
107
+ }
101
108
}
102
- # endif
103
- #endif
109
+
110
+ //! Convert pixels to palettized
104
111
for (y = 0 ;y < ImgH ;y ++ ) for (x = 0 ;x < ImgW ;x ++ ) {
105
112
int PalIdx = TilePalIdx [(y /TileH )* (ImgW /TileW ) + (x /TileW )];
106
113
@@ -113,58 +120,56 @@ struct BGRAf_t Qualetize(
113
120
Px_Original = BGRAf_AsYCoCg (& Px_Original );
114
121
Px = Px_Original ;
115
122
}
116
- #if DITHER_TYPE != DITHER_NONE
117
- # if DITHER_TYPE == DITHER_FLOYDSTEINBERG
118
- //! Adjust for diffusion error
119
- {
120
- struct BGRAf_t Dif = PxDiffuse [y * ImgW + x ];
123
+
124
+ //! Apply dithering?
125
+ if (DitherType != DITHER_NONE ) {
126
+ if (DitherType == DITHER_FLOYDSTEINBERG ) {
127
+ //! Adjust for diffusion error
128
+ struct BGRAf_t Dif = PxDiffuse [y * ImgW + x ];
121
129
#ifdef DITHER_NO_ALPHA
122
- Dif .a = 0.0f ;
130
+ Dif .a = 0.0f ;
123
131
#endif
124
- Dif = BGRAf_Muli (& Dif , DITHER_LEVEL );
125
- Px = BGRAf_Add (& Px , & Dif );
126
- }
127
- # else
128
- //! Adjust for dither matrix
129
- {
130
- int Threshold = 0 , xKey = x , yKey = x ^y ;
131
- int Bit = DITHER_TYPE - 1 ; do {
132
- Threshold = Threshold * 2 + (yKey & 1 ), yKey >>= 1 ; //! <- Hopefully turned into "SHR, ADC"
133
- Threshold = Threshold * 2 + (xKey & 1 ), xKey >>= 1 ;
134
- } while (-- Bit >= 0 );
135
- float fThres = Threshold * (1.0f / (1 << (2 * DITHER_TYPE ))) - 0.5f ;
136
- struct BGRAf_t DitherVal = BGRAf_Muli (& PaletteSpread [PalIdx ], fThres * DITHER_LEVEL );
137
- Px = BGRAf_Add (& Px , & DitherVal );
132
+ Dif = BGRAf_Muli (& Dif , DITHER_LEVEL );
133
+ Px = BGRAf_Add (& Px , & Dif );
134
+ } else {
135
+ //! Adjust for dither matrix
136
+ int Threshold = 0 , xKey = x , yKey = x ^y ;
137
+ int Bit = DitherType - 1 ; do {
138
+ Threshold = Threshold * 2 + (yKey & 1 ), yKey >>= 1 ; //! <- Hopefully turned into "SHR, ADC"
139
+ Threshold = Threshold * 2 + (xKey & 1 ), xKey >>= 1 ;
140
+ } while (-- Bit >= 0 );
141
+ float fThres = Threshold * (1.0f / (1 << (2 * DitherType ))) - 0.5f ;
142
+ struct BGRAf_t DitherVal = BGRAf_Muli (& PaletteSpread [PalIdx ], fThres * DITHER_LEVEL );
143
+ Px = BGRAf_Add (& Px , & DitherVal );
144
+ }
138
145
}
139
- # endif
140
- #endif
141
- //! Find matching palette entry and store
146
+
147
+ //! Find matching palette entry. Store and get the error
142
148
int PalCol = FindPaletteEntry (& Px , Palette + PalIdx * MaxPalSize , MaxPalSize , PalUnused );
143
149
PxData [y * ImgW + x ] = PalIdx * MaxPalSize + PalCol ;
144
- #if MEASURE_PSNR || DITHER_TYPE == DITHER_FLOYDSTEINBERG
145
150
struct BGRAf_t Error = BGRAf_Sub (& Px_Original , & Palette [PxData [y * ImgW + x ]]);
146
- #endif
147
- #if DITHER_TYPE == DITHER_FLOYDSTEINBERG
151
+
148
152
//! Store error diffusion
149
- if (y + 1 < ImgH ) {
150
- if (x > 0 ) {
151
- struct BGRAf_t t = BGRAf_Muli (& Error , 3.0f /16 );
152
- PxDiffuse [(y + 1 )* ImgW + (x - 1 )] = BGRAf_Add (& PxDiffuse [(y + 1 )* ImgW + (x - 1 )], & t );
153
- }
154
- if (1 ) {
155
- struct BGRAf_t t = BGRAf_Muli (& Error , 5.0f /16 );
156
- PxDiffuse [(y + 1 )* ImgW + (x )] = BGRAf_Add (& PxDiffuse [(y + 1 )* ImgW + (x )], & t );
153
+ if (DitherType == DITHER_FLOYDSTEINBERG ) {
154
+ if (y + 1 < ImgH ) {
155
+ if (x > 0 ) {
156
+ struct BGRAf_t t = BGRAf_Muli (& Error , 3.0f /16 );
157
+ PxDiffuse [(y + 1 )* ImgW + (x - 1 )] = BGRAf_Add (& PxDiffuse [(y + 1 )* ImgW + (x - 1 )], & t );
158
+ }
159
+ if (1 ) {
160
+ struct BGRAf_t t = BGRAf_Muli (& Error , 5.0f /16 );
161
+ PxDiffuse [(y + 1 )* ImgW + (x )] = BGRAf_Add (& PxDiffuse [(y + 1 )* ImgW + (x )], & t );
162
+ }
163
+ if (x + 1 < ImgW ) {
164
+ struct BGRAf_t t = BGRAf_Muli (& Error , 1.0f /16 );
165
+ PxDiffuse [(y + 1 )* ImgW + (x + 1 )] = BGRAf_Add (& PxDiffuse [(y + 1 )* ImgW + (x + 1 )], & t );
166
+ }
157
167
}
158
168
if (x + 1 < ImgW ) {
159
- struct BGRAf_t t = BGRAf_Muli (& Error , 1 .0f /16 );
160
- PxDiffuse [(y + 1 )* ImgW + (x + 1 )] = BGRAf_Add (& PxDiffuse [(y + 1 )* ImgW + (x + 1 )], & t );
169
+ struct BGRAf_t t = BGRAf_Muli (& Error , 7 .0f /16 );
170
+ PxDiffuse [(y )* ImgW + (x + 1 )] = BGRAf_Add (& PxDiffuse [(y )* ImgW + (x + 1 )], & t );
161
171
}
162
172
}
163
- if (x + 1 < ImgW ) {
164
- struct BGRAf_t t = BGRAf_Muli (& Error , 7.0f /16 );
165
- PxDiffuse [(y )* ImgW + (x + 1 )] = BGRAf_Add (& PxDiffuse [(y )* ImgW + (x + 1 )], & t );
166
- }
167
- #endif
168
173
#if MEASURE_PSNR
169
174
//! Accumulate squared error
170
175
Error = BGRAf_Mul (& Error , & Error );
0 commit comments