rev |
line source |
nuclear@14
|
1 /*
|
nuclear@14
|
2 libimago - a multi-format image file input/output library.
|
nuclear@14
|
3 Copyright (C) 2010 John Tsiombikas <nuclear@member.fsf.org>
|
nuclear@14
|
4
|
nuclear@14
|
5 This program is free software: you can redistribute it and/or modify
|
nuclear@14
|
6 it under the terms of the GNU Lesser General Public License as published
|
nuclear@14
|
7 by the Free Software Foundation, either version 3 of the License, or
|
nuclear@14
|
8 (at your option) any later version.
|
nuclear@14
|
9
|
nuclear@14
|
10 This program is distributed in the hope that it will be useful,
|
nuclear@14
|
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nuclear@14
|
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nuclear@14
|
13 GNU Lesser General Public License for more details.
|
nuclear@14
|
14
|
nuclear@14
|
15 You should have received a copy of the GNU Lesser General Public License
|
nuclear@14
|
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
nuclear@14
|
17 */
|
nuclear@14
|
18 #include <string.h>
|
nuclear@14
|
19 #include "imago2.h"
|
nuclear@14
|
20
|
nuclear@14
|
21 /* pixel-format conversions are sub-optimal at the moment to avoid
|
nuclear@14
|
22 * writing a lot of code. optimize at some point ?
|
nuclear@14
|
23 */
|
nuclear@14
|
24
|
nuclear@14
|
25 #define CLAMP(x, a, b) ((x) < (a) ? (a) : ((x) > (b) ? (b) : (x)))
|
nuclear@14
|
26
|
nuclear@14
|
27 struct pixel {
|
nuclear@14
|
28 float r, g, b, a;
|
nuclear@14
|
29 };
|
nuclear@14
|
30
|
nuclear@14
|
31 static void unpack_grey8(struct pixel *unp, void *pptr, int count);
|
nuclear@14
|
32 static void unpack_rgb24(struct pixel *unp, void *pptr, int count);
|
nuclear@14
|
33 static void unpack_rgba32(struct pixel *unp, void *pptr, int count);
|
nuclear@14
|
34 static void unpack_greyf(struct pixel *unp, void *pptr, int count);
|
nuclear@14
|
35 static void unpack_rgbf(struct pixel *unp, void *pptr, int count);
|
nuclear@14
|
36 static void unpack_rgbaf(struct pixel *unp, void *pptr, int count);
|
nuclear@14
|
37
|
nuclear@14
|
38 static void pack_grey8(void *pptr, struct pixel *unp, int count);
|
nuclear@14
|
39 static void pack_rgb24(void *pptr, struct pixel *unp, int count);
|
nuclear@14
|
40 static void pack_rgba32(void *pptr, struct pixel *unp, int count);
|
nuclear@14
|
41 static void pack_greyf(void *pptr, struct pixel *unp, int count);
|
nuclear@14
|
42 static void pack_rgbf(void *pptr, struct pixel *unp, int count);
|
nuclear@14
|
43 static void pack_rgbaf(void *pptr, struct pixel *unp, int count);
|
nuclear@14
|
44
|
nuclear@14
|
45 /* XXX keep in sync with enum img_fmt at imago2.h */
|
nuclear@14
|
46 static void (*unpack[])(struct pixel*, void*, int) = {
|
nuclear@14
|
47 unpack_grey8,
|
nuclear@14
|
48 unpack_rgb24,
|
nuclear@14
|
49 unpack_rgba32,
|
nuclear@14
|
50 unpack_greyf,
|
nuclear@14
|
51 unpack_rgbf,
|
nuclear@14
|
52 unpack_rgbaf
|
nuclear@14
|
53 };
|
nuclear@14
|
54
|
nuclear@14
|
55 /* XXX keep in sync with enum img_fmt at imago2.h */
|
nuclear@14
|
56 static void (*pack[])(void*, struct pixel*, int) = {
|
nuclear@14
|
57 pack_grey8,
|
nuclear@14
|
58 pack_rgb24,
|
nuclear@14
|
59 pack_rgba32,
|
nuclear@14
|
60 pack_greyf,
|
nuclear@14
|
61 pack_rgbf,
|
nuclear@14
|
62 pack_rgbaf
|
nuclear@14
|
63 };
|
nuclear@14
|
64
|
nuclear@14
|
65
|
nuclear@14
|
66 int img_convert(struct img_pixmap *img, enum img_fmt tofmt)
|
nuclear@14
|
67 {
|
nuclear@14
|
68 struct pixel pbuf[8];
|
nuclear@14
|
69 int bufsz = (img->width & 7) == 0 ? 8 : ((img->width & 3) == 0 ? 4 : 1);
|
nuclear@14
|
70 int i, num_pix = img->width * img->height;
|
nuclear@14
|
71 int num_iter = num_pix / bufsz;
|
nuclear@14
|
72 char *sptr, *dptr;
|
nuclear@14
|
73 struct img_pixmap nimg;
|
nuclear@14
|
74
|
nuclear@14
|
75 if(img->fmt == tofmt) {
|
nuclear@14
|
76 return 0; /* nothing to do */
|
nuclear@14
|
77 }
|
nuclear@14
|
78
|
nuclear@14
|
79 img_init(&nimg);
|
nuclear@14
|
80 if(img_set_pixels(&nimg, img->width, img->height, tofmt, 0) == -1) {
|
nuclear@14
|
81 img_destroy(&nimg);
|
nuclear@14
|
82 return -1;
|
nuclear@14
|
83 }
|
nuclear@14
|
84
|
nuclear@14
|
85 sptr = img->pixels;
|
nuclear@14
|
86 dptr = nimg.pixels;
|
nuclear@14
|
87
|
nuclear@14
|
88 for(i=0; i<num_iter; i++) {
|
nuclear@14
|
89 unpack[img->fmt](pbuf, sptr, bufsz);
|
nuclear@14
|
90 pack[tofmt](dptr, pbuf, bufsz);
|
nuclear@14
|
91
|
nuclear@14
|
92 sptr += bufsz * img->pixelsz;
|
nuclear@14
|
93 dptr += bufsz * nimg.pixelsz;
|
nuclear@14
|
94 }
|
nuclear@14
|
95
|
nuclear@14
|
96 img_copy(img, &nimg);
|
nuclear@14
|
97 img_destroy(&nimg);
|
nuclear@14
|
98 return 0;
|
nuclear@14
|
99 }
|
nuclear@14
|
100
|
nuclear@14
|
101 /* the following functions *could* benefit from SIMD */
|
nuclear@14
|
102
|
nuclear@14
|
103 static void unpack_grey8(struct pixel *unp, void *pptr, int count)
|
nuclear@14
|
104 {
|
nuclear@14
|
105 int i;
|
nuclear@14
|
106 unsigned char *pix = pptr;
|
nuclear@14
|
107
|
nuclear@14
|
108 for(i=0; i<count; i++) {
|
nuclear@14
|
109 unp->r = unp->g = unp->b = (float)*pix++ / 255.0;
|
nuclear@14
|
110 unp->a = 1.0;
|
nuclear@14
|
111 unp++;
|
nuclear@14
|
112 }
|
nuclear@14
|
113 }
|
nuclear@14
|
114
|
nuclear@14
|
115 static void unpack_rgb24(struct pixel *unp, void *pptr, int count)
|
nuclear@14
|
116 {
|
nuclear@14
|
117 int i;
|
nuclear@14
|
118 unsigned char *pix = pptr;
|
nuclear@14
|
119
|
nuclear@14
|
120 for(i=0; i<count; i++) {
|
nuclear@14
|
121 unp->r = (float)*pix++ / 255.0;
|
nuclear@14
|
122 unp->g = (float)*pix++ / 255.0;
|
nuclear@14
|
123 unp->b = (float)*pix++ / 255.0;
|
nuclear@14
|
124 unp->a = 1.0;
|
nuclear@14
|
125 unp++;
|
nuclear@14
|
126 }
|
nuclear@14
|
127 }
|
nuclear@14
|
128
|
nuclear@14
|
129 static void unpack_rgba32(struct pixel *unp, void *pptr, int count)
|
nuclear@14
|
130 {
|
nuclear@14
|
131 int i;
|
nuclear@14
|
132 unsigned char *pix = pptr;
|
nuclear@14
|
133
|
nuclear@14
|
134 for(i=0; i<count; i++) {
|
nuclear@14
|
135 unp->r = (float)*pix++ / 255.0;
|
nuclear@14
|
136 unp->g = (float)*pix++ / 255.0;
|
nuclear@14
|
137 unp->b = (float)*pix++ / 255.0;
|
nuclear@14
|
138 unp->a = (float)*pix++ / 255.0;
|
nuclear@14
|
139 unp++;
|
nuclear@14
|
140 }
|
nuclear@14
|
141 }
|
nuclear@14
|
142
|
nuclear@14
|
143 static void unpack_greyf(struct pixel *unp, void *pptr, int count)
|
nuclear@14
|
144 {
|
nuclear@14
|
145 int i;
|
nuclear@14
|
146 float *pix = pptr;
|
nuclear@14
|
147
|
nuclear@14
|
148 for(i=0; i<count; i++) {
|
nuclear@14
|
149 unp->r = unp->g = unp->b = *pix++;
|
nuclear@14
|
150 unp->a = 1.0;
|
nuclear@14
|
151 unp++;
|
nuclear@14
|
152 }
|
nuclear@14
|
153 }
|
nuclear@14
|
154
|
nuclear@14
|
155 static void unpack_rgbf(struct pixel *unp, void *pptr, int count)
|
nuclear@14
|
156 {
|
nuclear@14
|
157 int i;
|
nuclear@14
|
158 float *pix = pptr;
|
nuclear@14
|
159
|
nuclear@14
|
160 for(i=0; i<count; i++) {
|
nuclear@14
|
161 unp->r = *pix++;
|
nuclear@14
|
162 unp->g = *pix++;
|
nuclear@14
|
163 unp->b = *pix++;
|
nuclear@14
|
164 unp->a = 1.0;
|
nuclear@14
|
165 unp++;
|
nuclear@14
|
166 }
|
nuclear@14
|
167 }
|
nuclear@14
|
168
|
nuclear@14
|
169 static void unpack_rgbaf(struct pixel *unp, void *pptr, int count)
|
nuclear@14
|
170 {
|
nuclear@14
|
171 int i;
|
nuclear@14
|
172 float *pix = pptr;
|
nuclear@14
|
173
|
nuclear@14
|
174 for(i=0; i<count; i++) {
|
nuclear@14
|
175 unp->r = *pix++;
|
nuclear@14
|
176 unp->g = *pix++;
|
nuclear@14
|
177 unp->b = *pix++;
|
nuclear@14
|
178 unp->a = *pix++;
|
nuclear@14
|
179 unp++;
|
nuclear@14
|
180 }
|
nuclear@14
|
181 }
|
nuclear@14
|
182
|
nuclear@14
|
183
|
nuclear@14
|
184 static void pack_grey8(void *pptr, struct pixel *unp, int count)
|
nuclear@14
|
185 {
|
nuclear@14
|
186 int i;
|
nuclear@14
|
187 unsigned char *pix = pptr;
|
nuclear@14
|
188
|
nuclear@14
|
189 for(i=0; i<count; i++) {
|
nuclear@14
|
190 int lum = (int)(255.0 * (unp->r + unp->g + unp->b) / 3.0);
|
nuclear@14
|
191 *pix++ = CLAMP(lum, 0, 255);
|
nuclear@14
|
192 unp++;
|
nuclear@14
|
193 }
|
nuclear@14
|
194 }
|
nuclear@14
|
195
|
nuclear@14
|
196 static void pack_rgb24(void *pptr, struct pixel *unp, int count)
|
nuclear@14
|
197 {
|
nuclear@14
|
198 int i;
|
nuclear@14
|
199 unsigned char *pix = pptr;
|
nuclear@14
|
200
|
nuclear@14
|
201 for(i=0; i<count; i++) {
|
nuclear@14
|
202 int r = (int)(unp->r * 255.0);
|
nuclear@14
|
203 int g = (int)(unp->g * 255.0);
|
nuclear@14
|
204 int b = (int)(unp->b * 255.0);
|
nuclear@14
|
205
|
nuclear@14
|
206 *pix++ = CLAMP(r, 0, 255);
|
nuclear@14
|
207 *pix++ = CLAMP(g, 0, 255);
|
nuclear@14
|
208 *pix++ = CLAMP(b, 0, 255);
|
nuclear@14
|
209 unp++;
|
nuclear@14
|
210 }
|
nuclear@14
|
211 }
|
nuclear@14
|
212
|
nuclear@14
|
213 static void pack_rgba32(void *pptr, struct pixel *unp, int count)
|
nuclear@14
|
214 {
|
nuclear@14
|
215 int i;
|
nuclear@14
|
216 unsigned char *pix = pptr;
|
nuclear@14
|
217
|
nuclear@14
|
218 for(i=0; i<count; i++) {
|
nuclear@14
|
219 int r = (int)(unp->r * 255.0);
|
nuclear@14
|
220 int g = (int)(unp->g * 255.0);
|
nuclear@14
|
221 int b = (int)(unp->b * 255.0);
|
nuclear@14
|
222 int a = (int)(unp->a * 255.0);
|
nuclear@14
|
223
|
nuclear@14
|
224 *pix++ = CLAMP(r, 0, 255);
|
nuclear@14
|
225 *pix++ = CLAMP(g, 0, 255);
|
nuclear@14
|
226 *pix++ = CLAMP(b, 0, 255);
|
nuclear@14
|
227 *pix++ = CLAMP(a, 0, 255);
|
nuclear@14
|
228 unp++;
|
nuclear@14
|
229 }
|
nuclear@14
|
230 }
|
nuclear@14
|
231
|
nuclear@14
|
232 static void pack_greyf(void *pptr, struct pixel *unp, int count)
|
nuclear@14
|
233 {
|
nuclear@14
|
234 int i;
|
nuclear@14
|
235 float *pix = pptr;
|
nuclear@14
|
236
|
nuclear@14
|
237 for(i=0; i<count; i++) {
|
nuclear@14
|
238 *pix++ = (unp->r + unp->g + unp->b) / 3.0;
|
nuclear@14
|
239 unp++;
|
nuclear@14
|
240 }
|
nuclear@14
|
241 }
|
nuclear@14
|
242
|
nuclear@14
|
243 static void pack_rgbf(void *pptr, struct pixel *unp, int count)
|
nuclear@14
|
244 {
|
nuclear@14
|
245 int i;
|
nuclear@14
|
246 float *pix = pptr;
|
nuclear@14
|
247
|
nuclear@14
|
248 for(i=0; i<count; i++) {
|
nuclear@14
|
249 *pix++ = unp->r;
|
nuclear@14
|
250 *pix++ = unp->g;
|
nuclear@14
|
251 *pix++ = unp->b;
|
nuclear@14
|
252 unp++;
|
nuclear@14
|
253 }
|
nuclear@14
|
254 }
|
nuclear@14
|
255
|
nuclear@14
|
256 static void pack_rgbaf(void *pptr, struct pixel *unp, int count)
|
nuclear@14
|
257 {
|
nuclear@14
|
258 memcpy(pptr, unp, count * sizeof *unp);
|
nuclear@14
|
259 }
|
nuclear@14
|
260
|