* sort a given list of rgba entries so that all the opaque pixels are at the end */
| 192 | * sort a given list of rgba entries so that all the opaque pixels are at the end |
| 193 | */ |
| 194 | int remapPaletteForPNG(rasterBufferObj *rb, rgbPixel *rgb, unsigned char *a, int *num_a) { |
| 195 | int bot_idx, top_idx, x; |
| 196 | int remap[256]; |
| 197 | unsigned int maxval = rb->data.palette.scaling_maxval; |
| 198 | |
| 199 | assert(rb->type == MS_BUFFER_BYTE_PALETTE); |
| 200 | |
| 201 | /* |
| 202 | ** remap the palette colors so that all entries with |
| 203 | ** the maximal alpha value (i.e., fully opaque) are at the end and can |
| 204 | ** therefore be omitted from the tRNS chunk. Note that the ordering of |
| 205 | ** opaque entries is reversed from how they were previously arranged |
| 206 | ** --not that this should matter to anyone. |
| 207 | */ |
| 208 | |
| 209 | for (top_idx = rb->data.palette.num_entries-1, bot_idx = x = 0; x < rb->data.palette.num_entries; ++x) { |
| 210 | if (rb->data.palette.palette[x].a == maxval) |
| 211 | remap[x] = top_idx--; |
| 212 | else |
| 213 | remap[x] = bot_idx++; |
| 214 | } |
| 215 | /* sanity check: top and bottom indices should have just crossed paths */ |
| 216 | if (bot_idx != top_idx + 1) { |
| 217 | msSetError(MS_MISCERR,"quantization sanity check failed","createPNGPalette()"); |
| 218 | return MS_FAILURE; |
| 219 | } |
| 220 | |
| 221 | *num_a = bot_idx; |
| 222 | |
| 223 | for(x=0;x<rb->width*rb->height;x++) |
| 224 | rb->data.palette.pixels[x] = remap[rb->data.palette.pixels[x]]; |
| 225 | |
| 226 | |
| 227 | for (x = 0; x < rb->data.palette.num_entries; ++x) { |
| 228 | if(maxval == 255) { |
| 229 | a[remap[x]] = rb->data.palette.palette[x].a; |
| 230 | rgb[remap[x]].r = rb->data.palette.palette[x].r; |
| 231 | rgb[remap[x]].g = rb->data.palette.palette[x].g; |
| 232 | rgb[remap[x]].b = rb->data.palette.palette[x].b; |
| 233 | } else { |
| 234 | /* rescale palette */ |
| 235 | rgb[remap[x]].r = (rb->data.palette.palette[x].r * 255 + (maxval >> 1)) / maxval; |
| 236 | rgb[remap[x]].g = (rb->data.palette.palette[x].g * 255 + (maxval >> 1)) / maxval; |
| 237 | rgb[remap[x]].b = (rb->data.palette.palette[x].b * 255 + (maxval >> 1)) / maxval; |
| 238 | a[remap[x]] = (rb->data.palette.palette[x].a * 255 + (maxval >> 1)) / maxval; |
| 239 | } |
| 240 | if(a[remap[x]] != 255) { |
| 241 | /* un-premultiply pixels */ |
| 242 | double da = 255.0/a[remap[x]]; |
| 243 | rgb[remap[x]].r *= da; |
| 244 | rgb[remap[x]].g *= da; |
| 245 | rgb[remap[x]].b *= da; |
| 246 | } |
| 247 | } |
| 248 | |
| 249 | return MS_SUCCESS; |
| 250 | } |
| 251 |
no test coverage detected