rev |
line source |
nuclear@12
|
1 #include <stdio.h>
|
nuclear@12
|
2 #include <stdlib.h>
|
nuclear@12
|
3 #include <string.h>
|
nuclear@12
|
4 #include <limits.h>
|
nuclear@12
|
5 #include <errno.h>
|
nuclear@12
|
6 #include <imago2.h>
|
nuclear@12
|
7 #include <arpa/inet.h>
|
nuclear@12
|
8 #include "image.h"
|
nuclear@12
|
9
|
nuclear@12
|
10 static int convert(struct ham_image *img, unsigned char *pixels, int xsz, int ysz);
|
nuclear@12
|
11 static int save_ham(struct ham_image *img, const char *fname);
|
nuclear@12
|
12 static void destroy_image(struct ham_image *img);
|
nuclear@12
|
13
|
nuclear@12
|
14 int main(int argc, char **argv)
|
nuclear@12
|
15 {
|
nuclear@12
|
16 int i, width, height, len;
|
nuclear@12
|
17 unsigned char *pixels;
|
nuclear@12
|
18 char *out_fname, *suffix;
|
nuclear@12
|
19 struct ham_image img;
|
nuclear@12
|
20
|
nuclear@12
|
21 for(i=1; i<argc; i++) {
|
nuclear@12
|
22 if(!(pixels = img_load_pixels(argv[i], &width, &height, IMG_FMT_RGB24))) {
|
nuclear@12
|
23 fprintf(stderr, "failed to load image: %s\n", argv[i]);
|
nuclear@12
|
24 continue;
|
nuclear@12
|
25 }
|
nuclear@12
|
26 convert(&img, pixels, width, height);
|
nuclear@12
|
27
|
nuclear@12
|
28 len = strlen(argv[i]) + 4;
|
nuclear@12
|
29 if(!(out_fname = malloc(len + 1))) {
|
nuclear@12
|
30 perror("failed to allocate memory");
|
nuclear@12
|
31 abort();
|
nuclear@12
|
32 }
|
nuclear@12
|
33 memcpy(out_fname, argv[i], len + 1);
|
nuclear@12
|
34 if(!(suffix = strrchr(out_fname, '.'))) {
|
nuclear@12
|
35 suffix = out_fname + len;
|
nuclear@12
|
36 }
|
nuclear@12
|
37 memcpy(suffix, ".ham", 5);
|
nuclear@12
|
38
|
nuclear@12
|
39 save_ham(&img, out_fname);
|
nuclear@12
|
40 destroy_image(&img);
|
nuclear@12
|
41
|
nuclear@12
|
42 free(out_fname);
|
nuclear@12
|
43 }
|
nuclear@12
|
44
|
nuclear@12
|
45 return 0;
|
nuclear@12
|
46 }
|
nuclear@12
|
47
|
nuclear@12
|
48 struct fringe {
|
nuclear@12
|
49 int pixel, score;
|
nuclear@12
|
50 };
|
nuclear@12
|
51
|
nuclear@12
|
52 static int detect_fringes(int *flist, int num, unsigned char *scanline, int width, int pr, int pg, int pb)
|
nuclear@12
|
53 {
|
nuclear@12
|
54 int i, j, fcount = 0;
|
nuclear@12
|
55 struct fringe fringes[16] = {{0, 0}};
|
nuclear@12
|
56
|
nuclear@12
|
57 if(num > 16) num = 16;
|
nuclear@12
|
58
|
nuclear@12
|
59 for(i=0; i<width; i++) {
|
nuclear@12
|
60 int r = *scanline++;
|
nuclear@12
|
61 int g = *scanline++;
|
nuclear@12
|
62 int b = *scanline++;
|
nuclear@12
|
63 int dr = r - pr;
|
nuclear@12
|
64 int dg = g - pg;
|
nuclear@12
|
65 int db = b - pb;
|
nuclear@12
|
66 int max = dr > dg ? (dr > db ? dr : db) : (dg > db ? dg : db);
|
nuclear@12
|
67 int score = dr + dg + db - max;
|
nuclear@12
|
68
|
nuclear@12
|
69 if(score > 0) {
|
nuclear@12
|
70 int min = fringes[0].score, min_idx = 0;
|
nuclear@12
|
71 for(j=1; j<fcount; j++) {
|
nuclear@12
|
72 if(fringes[j].score < min) {
|
nuclear@12
|
73 min = fringes[j].score;
|
nuclear@12
|
74 min_idx = j;
|
nuclear@12
|
75 }
|
nuclear@12
|
76 }
|
nuclear@12
|
77 if(score > min) {
|
nuclear@12
|
78 fringes[min_idx].score = score;
|
nuclear@12
|
79 fringes[min_idx].pixel = i;
|
nuclear@12
|
80 }
|
nuclear@12
|
81 }
|
nuclear@12
|
82 }
|
nuclear@12
|
83 }
|
nuclear@12
|
84
|
nuclear@12
|
85 static int convert(struct ham_image *img, unsigned char *pixels, int xsz, int ysz)
|
nuclear@12
|
86 {
|
nuclear@12
|
87 int i, j, x, y, pstart, numpix = xsz * ysz;
|
nuclear@12
|
88 FILE *fp = 0;
|
nuclear@12
|
89 uint32_t cps, npalent;
|
nuclear@12
|
90 struct palchange *tail = 0;
|
nuclear@12
|
91 unsigned char *inpixels = 0;
|
nuclear@12
|
92 unsigned char *srcptr, *destptr;
|
nuclear@12
|
93
|
nuclear@12
|
94 /* convert RGB to HAM in-place */
|
nuclear@12
|
95 for(i=0; i<ysz; i++) {
|
nuclear@12
|
96 for(j=0; j<xsz; j++) {
|
nuclear@12
|
97 }
|
nuclear@12
|
98 }
|
nuclear@12
|
99
|
nuclear@12
|
100 img->width = xsz;
|
nuclear@12
|
101 img->height = ysz;
|
nuclear@12
|
102 img->nbitplanes = 6;
|
nuclear@12
|
103 img->ham = 1;
|
nuclear@12
|
104 img->chglist = 0;
|
nuclear@12
|
105
|
nuclear@12
|
106 if(!(img->pixels = malloc(img->width * img->height / 8 * img->nbitplanes))) {
|
nuclear@12
|
107 perror("failed to allocate pixels");
|
nuclear@12
|
108 goto err;
|
nuclear@12
|
109 }
|
nuclear@12
|
110
|
nuclear@12
|
111 for(i=0; i<img->nbitplanes; i++) {
|
nuclear@12
|
112 srcptr = inpixels;
|
nuclear@12
|
113 destptr = img->pixels + i * img->width / 8;
|
nuclear@12
|
114 for(y=0; y<img->height; y++) {
|
nuclear@12
|
115 unsigned char pixval = 0;
|
nuclear@12
|
116 for(x=0; x<img->width; x++) {
|
nuclear@12
|
117 pixval = (pixval << 1) | ((*srcptr++ >> i) & 1);
|
nuclear@12
|
118 if((x & 7) == 7) {
|
nuclear@12
|
119 *destptr++ = pixval;
|
nuclear@12
|
120 pixval = 0;
|
nuclear@12
|
121 }
|
nuclear@12
|
122 }
|
nuclear@12
|
123 destptr += img->width / 8 * (img->nbitplanes - 1);
|
nuclear@12
|
124 }
|
nuclear@12
|
125 }
|
nuclear@12
|
126
|
nuclear@12
|
127 free(inpixels);
|
nuclear@12
|
128 fclose(fp);
|
nuclear@12
|
129 return img;
|
nuclear@12
|
130
|
nuclear@12
|
131 err:
|
nuclear@12
|
132 free(inpixels);
|
nuclear@12
|
133 if(img) {
|
nuclear@12
|
134 while(img->chglist) {
|
nuclear@12
|
135 void *tmp = img->chglist;
|
nuclear@12
|
136 img->chglist = img->chglist->next;
|
nuclear@12
|
137 free(tmp);
|
nuclear@12
|
138 }
|
nuclear@12
|
139 free(img->pixels);
|
nuclear@12
|
140 free(img);
|
nuclear@12
|
141 }
|
nuclear@12
|
142 if(fp) fclose(fp);
|
nuclear@12
|
143 return 0;
|
nuclear@12
|
144 }
|
nuclear@12
|
145
|
nuclear@12
|
146
|
nuclear@12
|
147 /* interleaved ham format (output)
|
nuclear@12
|
148 * byte order: big endian
|
nuclear@12
|
149 *
|
nuclear@12
|
150 * 4 bytes: magic: "HAAM"
|
nuclear@12
|
151 * 2 bytes: width
|
nuclear@12
|
152 * 2 bytes: height
|
nuclear@12
|
153 * 1 byte: number of bitplanes
|
nuclear@12
|
154 * 1 byte: padding
|
nuclear@12
|
155 * 2 bytes: number of palette change descriptors (nchg)
|
nuclear@12
|
156 * 16 * 2 bytes: initial palette [ x | r | g | b ]
|
nuclear@12
|
157 * nchg * 4 bytes: [ scanline ] [ idx | r | g | b ]
|
nuclear@12
|
158 * width * height / 8 * bitplanes bytes: pixels interleaved scanlines
|
nuclear@12
|
159 * [ row0 bpl0 ] ... [ row0 bplN ] [ row1 bpl0 ] ... [ row1 bplN ] ...
|
nuclear@12
|
160 */
|
nuclear@12
|
161 static int save_ham(struct ham_image *img, const char *fname)
|
nuclear@12
|
162 {
|
nuclear@12
|
163 int i, num;
|
nuclear@12
|
164 unsigned char c, *pptr;
|
nuclear@12
|
165 uint16_t val;
|
nuclear@12
|
166 FILE *fp;
|
nuclear@12
|
167 struct palchange *chg;
|
nuclear@12
|
168
|
nuclear@12
|
169 if(!(fp = fopen(fname, "wb"))) {
|
nuclear@12
|
170 fprintf(stderr, "failed to open %s for writing: %s\n", fname, strerror(errno));
|
nuclear@12
|
171 return -1;
|
nuclear@12
|
172 }
|
nuclear@12
|
173 fprintf(fp, "HAAM");
|
nuclear@12
|
174
|
nuclear@12
|
175 val = htons(img->width);
|
nuclear@12
|
176 fwrite(&val, 2, 1, fp);
|
nuclear@12
|
177 val = htons(img->height);
|
nuclear@12
|
178 fwrite(&val, 2, 1, fp);
|
nuclear@12
|
179 c = img->nbitplanes;
|
nuclear@12
|
180 fwrite(&c, 1, 1, fp);
|
nuclear@12
|
181 fwrite(&c, 1, 1, fp); /* padding */
|
nuclear@12
|
182
|
nuclear@12
|
183 num = 0;
|
nuclear@12
|
184 chg = img->chglist;
|
nuclear@12
|
185 while(chg) {
|
nuclear@12
|
186 ++num;
|
nuclear@12
|
187 chg = chg->next;
|
nuclear@12
|
188 }
|
nuclear@12
|
189 num = htons(num);
|
nuclear@12
|
190 fwrite(&num, 2, 1, fp);
|
nuclear@12
|
191
|
nuclear@12
|
192 for(i=0; i<16; i++) {
|
nuclear@12
|
193 val = htons(img->palette[i]);
|
nuclear@12
|
194 fwrite(&val, 2, 1, fp);
|
nuclear@12
|
195 }
|
nuclear@12
|
196
|
nuclear@12
|
197 chg = img->chglist;
|
nuclear@12
|
198 while(chg) {
|
nuclear@12
|
199 val = htons(chg->line);
|
nuclear@12
|
200 fwrite(&val, 2, 1, fp);
|
nuclear@12
|
201 val = htons(chg->entry);
|
nuclear@12
|
202 fwrite(&val, 2, 1, fp);
|
nuclear@12
|
203 chg = chg->next;
|
nuclear@12
|
204 }
|
nuclear@12
|
205
|
nuclear@12
|
206 pptr = img->pixels;
|
nuclear@12
|
207 num = img->width * img->height / 8 * img->nbitplanes;
|
nuclear@12
|
208 for(i=0; i<num; i++) {
|
nuclear@12
|
209 fwrite(pptr, 1, 1, fp);
|
nuclear@12
|
210 ++pptr;
|
nuclear@12
|
211 }
|
nuclear@12
|
212 fclose(fp);
|
nuclear@12
|
213 return 0;
|
nuclear@12
|
214 }
|
nuclear@12
|
215
|
nuclear@12
|
216 void destroy_image(struct ham_image *img)
|
nuclear@12
|
217 {
|
nuclear@12
|
218 if(img) {
|
nuclear@12
|
219 free(img->pixels);
|
nuclear@12
|
220 while(img->chglist) {
|
nuclear@12
|
221 void *tmp = img->chglist;
|
nuclear@12
|
222 img->chglist = img->chglist->next;
|
nuclear@12
|
223 free(tmp);
|
nuclear@12
|
224 }
|
nuclear@12
|
225 }
|
nuclear@12
|
226 }
|