2 libimago - a multi-format image file input/output library.
3 Copyright (C) 2010-2021 John Tsiombikas <nuclear@member.fsf.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published
7 by the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 /* pixel-format conversions are sub-optimal at the moment to avoid
23 * writing a lot of code. optimize at some point ?
26 #define CLAMP(x, a, b) ((x) < (a) ? (a) : ((x) > (b) ? (b) : (x)))
32 static void unpack_grey8(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap);
33 static void unpack_rgb24(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap);
34 static void unpack_rgba32(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap);
35 static void unpack_bgra32(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap);
36 static void unpack_greyf(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap);
37 static void unpack_rgbf(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap);
38 static void unpack_rgbaf(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap);
39 static void unpack_rgb565(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap);
40 static void unpack_idx8(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap);
42 static void pack_grey8(void *pptr, struct pixel *unp, int count);
43 static void pack_rgb24(void *pptr, struct pixel *unp, int count);
44 static void pack_rgba32(void *pptr, struct pixel *unp, int count);
45 static void pack_bgra32(void *pptr, struct pixel *unp, int count);
46 static void pack_greyf(void *pptr, struct pixel *unp, int count);
47 static void pack_rgbf(void *pptr, struct pixel *unp, int count);
48 static void pack_rgbaf(void *pptr, struct pixel *unp, int count);
49 static void pack_rgb565(void *pptr, struct pixel *unp, int count);
51 /* XXX keep in sync with enum img_fmt at imago2.h */
52 static void (*unpack[])(struct pixel*, void*, int, struct img_colormap*) = {
64 /* XXX keep in sync with enum img_fmt at imago2.h */
65 static void (*pack[])(void*, struct pixel*, int) = {
78 int img_convert(struct img_pixmap *img, enum img_fmt tofmt)
81 int bufsz = (img->width & 7) == 0 ? 8 : ((img->width & 3) == 0 ? 4 : 1);
82 int i, num_pix = img->width * img->height;
83 int num_iter = num_pix / bufsz;
85 struct img_pixmap nimg;
86 struct img_colormap *cmap = img_colormap(img);
88 if(img->fmt == tofmt) {
89 return 0; /* nothing to do */
92 if(tofmt == IMG_FMT_IDX8) {
94 fprintf(stderr, "imago: conversions to indexed not implemented yet\n");
99 if(img_set_pixels(&nimg, img->width, img->height, tofmt, 0) == -1) {
107 for(i=0; i<num_iter; i++) {
108 unpack[img->fmt](pbuf, sptr, bufsz, cmap);
109 pack[tofmt](dptr, pbuf, bufsz);
111 sptr += bufsz * img->pixelsz;
112 dptr += bufsz * nimg.pixelsz;
115 img_copy(img, &nimg);
120 /* the following functions *could* benefit from SIMD */
122 static void unpack_grey8(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap)
125 unsigned char *pix = pptr;
127 for(i=0; i<count; i++) {
128 unp->r = unp->g = unp->b = (float)*pix++ / 255.0;
134 static void unpack_rgb24(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap)
137 unsigned char *pix = pptr;
139 for(i=0; i<count; i++) {
140 unp->r = (float)*pix++ / 255.0;
141 unp->g = (float)*pix++ / 255.0;
142 unp->b = (float)*pix++ / 255.0;
148 static void unpack_rgba32(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap)
151 unsigned char *pix = pptr;
153 for(i=0; i<count; i++) {
154 unp->r = (float)*pix++ / 255.0;
155 unp->g = (float)*pix++ / 255.0;
156 unp->b = (float)*pix++ / 255.0;
157 unp->a = (float)*pix++ / 255.0;
162 static void unpack_bgra32(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap)
165 unsigned char *pix = pptr;
167 for(i=0; i<count; i++) {
168 unp->a = (float)*pix++ / 255.0;
169 unp->r = (float)*pix++ / 255.0;
170 unp->g = (float)*pix++ / 255.0;
171 unp->b = (float)*pix++ / 255.0;
176 static void unpack_greyf(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap)
181 for(i=0; i<count; i++) {
182 unp->r = unp->g = unp->b = *pix++;
188 static void unpack_rgbf(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap)
193 for(i=0; i<count; i++) {
202 static void unpack_rgbaf(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap)
207 for(i=0; i<count; i++) {
216 static void unpack_rgb565(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap)
219 uint16_t *pix = pptr;
221 for(i=0; i<count; i++) {
222 uint16_t r, g, b, p = *pix++;
224 if(b & 8) b |= 7; /* fill LSbits with whatever bit 0 was */
226 if(g & 4) g |= 3; /* ditto */
228 if(r & 8) r |= 7; /* same */
230 unp->r = (float)r / 255.0f;
231 unp->g = (float)g / 255.0f;
232 unp->b = (float)b / 255.0f;
238 static void unpack_idx8(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap)
241 unsigned char *pix = pptr;
243 for(i=0; i<count; i++) {
245 if(idx >= cmap->ncolors) {
246 unp->r = unp->g = unp->b = 0;
248 unp->r = (float)cmap->color[idx].r / 255.0f;
249 unp->g = (float)cmap->color[idx].g / 255.0f;
250 unp->b = (float)cmap->color[idx].b / 255.0f;
258 static void pack_grey8(void *pptr, struct pixel *unp, int count)
261 unsigned char *pix = pptr;
263 for(i=0; i<count; i++) {
264 int lum = (int)(255.0 * (unp->r + unp->g + unp->b) / 3.0);
265 *pix++ = CLAMP(lum, 0, 255);
270 static void pack_rgb24(void *pptr, struct pixel *unp, int count)
273 unsigned char *pix = pptr;
275 for(i=0; i<count; i++) {
276 int r = (int)(unp->r * 255.0);
277 int g = (int)(unp->g * 255.0);
278 int b = (int)(unp->b * 255.0);
280 *pix++ = CLAMP(r, 0, 255);
281 *pix++ = CLAMP(g, 0, 255);
282 *pix++ = CLAMP(b, 0, 255);
287 static void pack_rgba32(void *pptr, struct pixel *unp, int count)
290 unsigned char *pix = pptr;
292 for(i=0; i<count; i++) {
293 int r = (int)(unp->r * 255.0);
294 int g = (int)(unp->g * 255.0);
295 int b = (int)(unp->b * 255.0);
296 int a = (int)(unp->a * 255.0);
298 *pix++ = CLAMP(r, 0, 255);
299 *pix++ = CLAMP(g, 0, 255);
300 *pix++ = CLAMP(b, 0, 255);
301 *pix++ = CLAMP(a, 0, 255);
306 static void pack_bgra32(void *pptr, struct pixel *unp, int count)
309 unsigned char *pix = pptr;
311 for(i=0; i<count; i++) {
312 int r = (int)(unp->r * 255.0);
313 int g = (int)(unp->g * 255.0);
314 int b = (int)(unp->b * 255.0);
315 int a = (int)(unp->a * 255.0);
317 *pix++ = CLAMP(b, 0, 255);
318 *pix++ = CLAMP(g, 0, 255);
319 *pix++ = CLAMP(r, 0, 255);
320 *pix++ = CLAMP(a, 0, 255);
325 static void pack_greyf(void *pptr, struct pixel *unp, int count)
330 for(i=0; i<count; i++) {
331 *pix++ = (unp->r + unp->g + unp->b) / 3.0;
336 static void pack_rgbf(void *pptr, struct pixel *unp, int count)
341 for(i=0; i<count; i++) {
349 static void pack_rgbaf(void *pptr, struct pixel *unp, int count)
351 memcpy(pptr, unp, count * sizeof *unp);
355 static void pack_rgb565(void *pptr, struct pixel *unp, int count)
358 uint16_t *pix = pptr;
360 for(i=0; i<count; i++) {
361 uint16_t r = (uint16_t)(unp->r * 31.0f);
362 uint16_t g = (uint16_t)(unp->g * 63.0f);
363 uint16_t b = (uint16_t)(unp->b * 31.0f);
367 *pix++ = (r << 11) | (g << 5) | b;