source: trunk/JPGPROC/source/gbmsrc/gbmgem.c@ 2

Last change on this file since 2 was 2, checked in by stevenhl, 8 years ago

Import sources from cwmm-full.zip dated 2005-03-21

File size: 26.8 KB
Line 
1/*
2
3gbmgem.c - GEM Raster support
4
5Reads 1 bpp files and returns 1 bpp data.
6Reads 2,3 and 4 bpp files and returns 4 bpp data.
7Reads 5,6,7 and 8 bpp files and returns 8 bpp data.
8Reads 24 bpp XIMG files and returns 24 bpp data.
9Writes 1 bpp data as B/W 1 bpp file.
10Writes 4 bpp data mapped to 'standard' 16 colour palette.
11Or writes 4 bpp data greyscale 4 bpp file, if output option "grey" given.
12Or writes 4 bpp data to XIMG file with palette if "pal" option given.
13Writes 8 bpp data as greyscale 8 bpp file.
14Or writes 8 bpp to XIMG file with palette if "pal" option given.
15Writes 24 bpp data as an XIMG file.
16The pixel dimensions in microns can be specified via "pixw=#,pixh=#".
17
18Reference material used :-
19 p300 of EoGFF book.
20 Documents 1 bpp, 4 bpp and 8 bpp formats.
21 No mention of XIMG extension.
22 Suspected inaccurate - 8 word 4 bpp files are *colour*.
23 Its supplied sample FLAG_B24.IMG on CD-ROM proves the point.
24 Revision 17 of Image Alchemy.
25 Suspected wrong also - reorders palette writing 4 bpp IMG.
26 EoGFF sample and other samples all agree, Alchemy odd-one-out.
27 Public Domain source and other sample files.
28 Introduces notion of XIMG header extension block.
29 XIMGs can include palette entries (exact layout guessed).
30 XIMGs introduces notion of 24 bpp files.
31
32*/
33
34/*...sincludes:0:*/
35#include <stdio.h>
36#include <ctype.h>
37#include <stddef.h>
38#include <stdlib.h>
39#include <string.h>
40#include "gbm.h"
41#include "gbmhelp.h"
42
43/*...vgbm\46\h:0:*/
44/*...vgbmhelp\46\h:0:*/
45
46#ifndef min
47#define min(a,b) (((a)<(b))?(a):(b))
48#endif
49/*...e*/
50
51/*...suseful:0:*/
52static word getword(byte *p) { return (p[0]<<8)|p[1]; }
53static void putword(byte *p, word w) { p[0] = (byte) (w>>8); p[1] = (byte) w; }
54/*...e*/
55
56static GBMFT gem_gbmft =
57 {
58 "GemRas",
59 "GEM Raster",
60 "IMG",
61 GBM_FT_R1|GBM_FT_R4|GBM_FT_R8|GBM_FT_R24|
62 GBM_FT_W1|GBM_FT_W4|GBM_FT_W8|GBM_FT_W24,
63 };
64
65/*...serror codes:0:*/
66#define GBM_ERR_GEM_IS_DVI ((GBM_ERR) 1700)
67#define GBM_ERR_GEM_IS_IMDS ((GBM_ERR) 1701)
68#define GBM_ERR_GEM_BAD_VERSION ((GBM_ERR) 1702)
69#define GBM_ERR_GEM_BAD_HDRLEN ((GBM_ERR) 1703)
70#define GBM_ERR_GEM_BAD_PLANES ((GBM_ERR) 1704)
71#define GBM_ERR_GEM_BAD_FLAG ((GBM_ERR) 1705)
72#define GBM_ERR_GEM_FIXEDCPAL ((GBM_ERR) 1706)
73#define GBM_ERR_GEM_XIMG_TYPE ((GBM_ERR) 1707)
74/*...e*/
75
76typedef struct
77 {
78 word lenhdr, planes, patlen, flag;
79 BOOLEAN ximg;
80 } GEM_PRIV;
81
82/*...srgb_bgr:0:*/
83static void rgb_bgr(const byte *p, byte *q, int n)
84 {
85 while ( n-- )
86 {
87 byte r = *p++;
88 byte g = *p++;
89 byte b = *p++;
90
91 *q++ = b;
92 *q++ = g;
93 *q++ = r;
94 }
95 }
96/*...e*/
97
98/*...sgem_qft:0:*/
99GBM_ERR gem_qft(GBMFT *gbmft)
100 {
101 *gbmft = gem_gbmft;
102 return GBM_ERR_OK;
103 }
104/*...e*/
105/*...sgem_rhdr:0:*/
106/* GEM-Raster files, The green plane of an ActionMedia DVI still, and IMDS
107 image files all share the common .IMG file extension. GBM only supports
108 GEM-Raster files, but to be nice, I'll give a nice diagnostic if I detect
109 one of the others.
110
111 GEM-Rasters can be :-
112 8 word header, data
113 planes==1 => b/w image
114 planes==3 => fixed 8 colour palette (guesswork)
115 planes==4 => fixed 16 colour palette
116 9 word header including flag, data
117 flag==0 => treat as 8 word header
118 flag==1 => treat as greyscale
119 other size header, with XIMG signiture and 3<<planes words palette, data
120 other size header, with XIMG signiture and planes==24, data
121*/
122
123static byte imds_begin_image_segment[] = { 0x70, 0x04, 0x00, 0x00, 0x00, 0x00 };
124static byte imds_modca_wrapping [] = { 0x08, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00 };
125
126GBM_ERR gem_rhdr(const char *fn, int fd, GBM *gbm, const char *opt)
127 {
128 GEM_PRIV *priv = (GEM_PRIV *) gbm->priv;
129 byte hdr[22];
130
131 fn=fn; opt=opt; /* Suppress 'unref arg' compiler warnings */
132
133 if ( gbm_file_read(fd, hdr, 22) != 22 )
134 return GBM_ERR_READ;
135
136 if ( !memcmp(hdr, "VDVI", 4) )
137 return GBM_ERR_GEM_IS_DVI;
138
139 if ( !memcmp(hdr, imds_begin_image_segment, sizeof(imds_begin_image_segment)) ||
140 !memcmp(hdr, imds_modca_wrapping, sizeof(imds_modca_wrapping)) )
141 return GBM_ERR_GEM_IS_IMDS;
142
143 if ( getword(hdr) != 1 )
144 return GBM_ERR_GEM_BAD_VERSION;
145
146 priv->lenhdr = getword(hdr+1*2);
147 if ( priv->lenhdr < 8 )
148 return GBM_ERR_GEM_BAD_HDRLEN;
149
150 gbm_file_lseek(fd, priv->lenhdr*2, SEEK_SET);
151
152 if ( !memcmp(hdr+8*2, "XIMG", 4) )
153 /* XIMG signiture has been found */
154 {
155 priv->ximg = TRUE;
156 if ( getword(hdr+10*2) != 0 )
157 return GBM_ERR_GEM_XIMG_TYPE;
158 }
159 else
160 priv->ximg = FALSE;
161
162 priv->planes = getword(hdr+2*2);
163 if ( priv->planes >= 1 && priv->planes <= 8 )
164 ; /* All ok */
165 else if ( priv->ximg && priv->planes == 24 )
166 ; /* Still all ok */
167 else
168 /* Don't know how to handle this */
169 return GBM_ERR_GEM_BAD_PLANES;
170
171 priv->patlen = getword(hdr+3*2);
172
173 gbm->w = getword(hdr+6*2);
174 gbm->h = getword(hdr+7*2);
175
176 if ( priv->lenhdr == 9 )
177 {
178 priv->flag = getword(hdr+8*2);
179 if ( priv->flag != 0 && priv->flag != 1 )
180 return GBM_ERR_GEM_BAD_FLAG;
181 }
182
183 switch ( priv->planes )
184 {
185 case 1:
186 gbm->bpp = 1; break;
187 case 2: case 3: case 4:
188 gbm->bpp = 4; break;
189 case 5: case 6: case 7: case 8:
190 gbm->bpp = 8; break;
191 case 24:
192 gbm->bpp = 24; break;
193 }
194
195 /* Enforce assumed rules */
196 if ( priv->lenhdr == 8 ||
197 (priv->lenhdr == 9 && priv->flag == 0) )
198 /* Is a fixed colour palette */
199 if ( priv->planes != 1 &&
200 priv->planes != 3 &&
201 priv->planes != 4 )
202 return GBM_ERR_GEM_FIXEDCPAL;
203
204 return GBM_ERR_OK;
205 }
206/*...e*/
207/*...sgem_rpal:0:*/
208/* This palettes were determined by looking at .IMG files and their equivelent
209 .BMP files (that had been converted elsewhere). */
210
211/*...sgbmrgb_3 \45\ 3 plane palette:0:*/
212static GBMRGB gbmrgb_3[] =
213 {
214 /* r, g, b */
215 0xff,0xff,0xff, /* White */
216 0xff,0 ,0 , /* Red */
217 0 ,0xff,0 , /* Green */
218 0xff,0xff,0 , /* (Yellow) Orange */
219 0 ,0 ,0xff, /* Blue */
220 0xff,0 ,0xff, /* Magenta */
221 0 ,0xff,0xff, /* Cyan */
222 0 ,0 ,0 , /* Black */
223 };
224/*...e*/
225/*...sgbmrgb_4 \45\ 4 plane palette:0:*/
226static GBMRGB gbmrgb_4[] =
227 {
228 /* r, g, b */
229 0xff,0xff,0xff, /* White */
230 0xff,0 ,0 , /* Red */
231 0 ,0xff,0 , /* Green */
232 0xff,0xff,0 , /* (Yellow) Orange */
233 0 ,0 ,0xff, /* Blue */
234 0xff,0 ,0xff, /* Magenta */
235 0 ,0xff,0xff, /* Cyan */
236 0xcc,0xcc,0xcc, /* Grey */
237 0x80,0x80,0x80, /* Dark grey */
238 0x80,0 ,0 , /* Dark red */
239 0 ,0x80,0 , /* Dark green */
240 0x80,0x80,0 , /* Dark yellow */
241 0 ,0 ,0x80, /* Dark blue */
242 0x80,0 ,0x80, /* Dark magenta */
243 0 ,0x80,0x80, /* Dark cyan */
244 0 ,0 ,0 , /* Black */
245 };
246/*...e*/
247
248GBM_ERR gem_rpal(int fd, GBM *gbm, GBMRGB *gbmrgb)
249 {
250 GEM_PRIV *priv = (GEM_PRIV *) gbm->priv;
251 if ( priv->planes == 24 )
252 return GBM_ERR_OK;
253 if ( priv->ximg )
254/*...shandle the palette in the file:16:*/
255{
256int i, ncols = (1 << priv->planes);
257gbm_file_lseek(fd, (8+3)*2, SEEK_SET);
258for ( i = 0; i < ncols; i++ )
259 {
260 byte palentry[3*2];
261 if ( gbm_file_read(fd, palentry, 3*2) != 3*2 )
262 return GBM_ERR_READ;
263 /* Guesswork, based on sample file intel.img */
264 gbmrgb[i].r = (byte) ((getword(palentry )*255UL)/1000UL);
265 gbmrgb[i].g = (byte) ((getword(palentry+2)*255UL)/1000UL);
266 gbmrgb[i].b = (byte) ((getword(palentry+4)*255UL)/1000UL);
267 }
268}
269/*...e*/
270 else
271 switch ( gbm->bpp )
272 {
273/*...s1 \45\ fixed b\47\w palette:24:*/
274case 1:
275 gbmrgb[0].r = gbmrgb[0].g = gbmrgb[0].b = 0xff;
276 gbmrgb[1].r = gbmrgb[1].g = gbmrgb[1].b = 0x00;
277 break;
278/*...e*/
279/*...s4 \45\ either greyscale or a fixed palette:24:*/
280case 4:
281 if ( priv->lenhdr == 9 && priv->flag == 1 )
282 /* Is greyscale data */
283 /* Its guesswork that it goes dark to light */
284 {
285 int i, cols = (1<<priv->planes);
286 for ( i = 0; i < cols; i++ )
287 gbmrgb[i].r =
288 gbmrgb[i].g =
289 gbmrgb[i].b = (byte) ((i*0xff)/(cols-1));
290 }
291 else
292 switch ( priv->planes )
293 {
294 case 3:
295 memcpy(gbmrgb, gbmrgb_3, sizeof(gbmrgb_3));
296 break;
297 case 4:
298 memcpy(gbmrgb, gbmrgb_4, sizeof(gbmrgb_4));
299 break;
300 }
301 break;
302/*...e*/
303/*...s8 \45\ greyscale palette:24:*/
304case 8:
305 /* Again, its guesswork that it goes from dark to light */
306 {
307 int i;
308 for ( i = 0; i < 0x100; i++ )
309 gbmrgb[i].r =
310 gbmrgb[i].g =
311 gbmrgb[i].b = (byte) i;
312 }
313 break;
314/*...e*/
315 }
316 return GBM_ERR_OK;
317 }
318/*...e*/
319/*...sgem_rdata:0:*/
320/*...sread_gem_line:0:*/
321/* Vertical replication codes are only allowed in certain places */
322
323static void read_gem_line(
324 AHEAD *ahead,
325 byte *line, int scan,
326 int patlen,
327 int *vrep, BOOLEAN allow_vrep
328 )
329 {
330 while ( scan )
331 {
332 byte b1 = (byte) gbm_read_ahead(ahead);
333 if ( b1 == 0x80 )
334 /* Literal run */
335 {
336 byte len = (byte) gbm_read_ahead(ahead);
337 scan -= len;
338 while ( len-- > 0 )
339 *line++ = (byte) gbm_read_ahead(ahead);
340 }
341 else if ( b1 == 0x00 )
342 /* Pattern code */
343 {
344 byte rep = (byte) gbm_read_ahead(ahead);
345 if ( rep == 0 && allow_vrep )
346 /* Is actually a vertical replication */
347 {
348 gbm_read_ahead(ahead); /* Swallow 0xff */
349 *vrep = (int) gbm_read_ahead(ahead) - 1;
350 }
351 else
352 {
353 int i;
354 scan -= patlen*rep;
355 for ( i = 0; i < patlen; i++ )
356 *line++ = (byte) gbm_read_ahead(ahead);
357 while ( rep-- > 1 )
358 for ( i = 0; i < patlen; i++, line++ )
359 *line = line[-patlen];
360 }
361 }
362 else
363 /* Is a black/white (=0xff's/0x00's) run code */
364 {
365 byte store = (byte) ( (signed char) b1 >> 7 );
366 b1 &= 0x7f;
367 memset(line, store, b1);
368 line += b1;
369 scan -= b1;
370 }
371 allow_vrep = FALSE;
372 }
373 }
374/*...e*/
375/*...sspread:0:*/
376static void spread(byte b, byte bit_to_set, byte *dest)
377 {
378 if ( b & 0x80 ) dest[0] |= (bit_to_set & 0xf0);
379 if ( b & 0x40 ) dest[0] |= (bit_to_set & 0x0f);
380 if ( b & 0x20 ) dest[1] |= (bit_to_set & 0xf0);
381 if ( b & 0x10 ) dest[1] |= (bit_to_set & 0x0f);
382 if ( b & 0x08 ) dest[2] |= (bit_to_set & 0xf0);
383 if ( b & 0x04 ) dest[2] |= (bit_to_set & 0x0f);
384 if ( b & 0x02 ) dest[3] |= (bit_to_set & 0xf0);
385 if ( b & 0x01 ) dest[3] |= (bit_to_set & 0x0f);
386 }
387/*...e*/
388
389GBM_ERR gem_rdata(int fd, GBM *gbm, byte *data)
390 {
391 GEM_PRIV *priv = (GEM_PRIV *) gbm->priv;
392 int scan = (gbm->w+7)/8;
393 int stride = ((gbm->w*gbm->bpp + 31) / 32) * 4;
394 byte *line;
395 AHEAD *ahead;
396
397 if ( (ahead = gbm_create_ahead(fd)) == NULL )
398 return GBM_ERR_MEM;
399
400 if ( (line = malloc((size_t) scan)) == NULL )
401 {
402 gbm_destroy_ahead(ahead);
403 return GBM_ERR_MEM;
404 }
405
406 switch ( gbm->bpp )
407 {
408/*...s1:16:*/
409case 1:
410 {
411 int y, vrep = 0;
412 data += (gbm->h-1) * stride;
413 for ( y = gbm->h - 1; y >= 0; y--, data -= stride )
414 if ( vrep )
415 { memcpy(data, data+stride, stride); vrep--; }
416 else
417 read_gem_line(ahead, data, scan, priv->patlen, &vrep, TRUE);
418 }
419 break;
420/*...e*/
421/*...s4:16:*/
422case 4:
423 {
424 int y, vrep = 0;
425 int bytes = (gbm->w / 8);
426 int bits = (gbm->w & 7);
427
428 memset(data, 0, gbm->h * stride);
429 data += (gbm->h-1) * stride;
430 for ( y = gbm->h - 1; y >= 0; y--, data -= stride )
431 if ( vrep )
432 { memcpy(data, data+stride, stride); vrep--; }
433 else
434 {
435 int p;
436 byte bit;
437
438 for ( p = 0, bit = 0x11; p < priv->planes; p++, bit <<= 1 )
439 {
440 int x;
441 byte *dest = data;
442 read_gem_line(ahead, line, scan, priv->patlen, &vrep, p==0);
443 for ( x = 0; x < bytes; x++, dest += 4 )
444 spread(line[x], bit, dest);
445 if ( bits )
446 spread((byte) (line[x] & (0xff00U >> bits)), bit, dest);
447 }
448 }
449 }
450 break;
451/*...e*/
452/*...s8:16:*/
453case 8:
454 {
455 int y, vrep = 0;
456 memset(data, 0, gbm->h*stride);
457 data += (gbm->h-1) * stride;
458 for ( y = gbm->h - 1; y >= 0; y--, data -= stride )
459 if ( vrep )
460 { memcpy(data, data+stride, stride); vrep--; }
461 else
462 {
463 int p;
464 byte bit;
465 for ( p = 0, bit = 0x01; p < priv->planes; p++, bit <<= 1 )
466 {
467 int x;
468 read_gem_line(ahead, line, scan, priv->patlen, &vrep, p==0);
469 for ( x = 0; x < gbm->w; x++ )
470 if ( line[x>>3]&(0x80U>>(x&7)) )
471 data[x] |= bit;
472 }
473 }
474 }
475 break;
476/*...e*/
477/*...s24:16:*/
478case 24:
479 /* 24bpp data is strange in that it isn't bit planed at all like
480 the others are. This makes decoding quicker, and most 24bpp
481 hardware is not bit planar, and this may explain why.
482 Of course, my guesswork says that the order is R,G,B and as
483 GBM used B,G,R, i'll have to reverse the order. */
484 {
485 int y, vrep = 0;
486 memset(data, 0, gbm->h*stride);
487 data += (gbm->h-1) * stride;
488 for ( y = gbm->h - 1; y >= 0; y--, data -= stride )
489 if ( vrep )
490 { memcpy(data, data+stride, stride); vrep--; }
491 else
492 {
493 read_gem_line(ahead, data, gbm->w*3, priv->patlen, &vrep, TRUE);
494 rgb_bgr(data, data, gbm->w);
495 }
496 }
497 break;
498/*...e*/
499 }
500
501 free(line);
502
503 gbm_destroy_ahead(ahead);
504
505 return GBM_ERR_OK;
506 }
507/*...e*/
508/*...sgem_w:0:*/
509/*...swrite_pal:0:*/
510static BOOLEAN write_pal(int fd, const GBMRGB *gbmrgb, int cnt)
511 {
512 int i;
513 for ( i = 0; i < cnt; i++ )
514 {
515 byte buf[3*2];
516 putword(buf , (word) ((gbmrgb[i].r*1000UL)/255UL));
517 putword(buf+2, (word) ((gbmrgb[i].g*1000UL)/255UL));
518 putword(buf+4, (word) ((gbmrgb[i].b*1000UL)/255UL));
519 if ( gbm_file_write(fd, buf, 3*2) != 3*2 )
520 return FALSE;
521 }
522 return TRUE;
523 }
524/*...e*/
525/*...smap_to_grey4:0:*/
526/* Sum of R,G and B will be from 0 to 0x2fd. Sum/3 is from 0 to 0xff.
527 Sum/0x30 is from 0 to 0x0f, which is what we want. */
528
529static byte map_to_grey4(const GBMRGB *gbmrgb)
530 {
531 return (byte) ( ( (word) gbmrgb->r +
532 (word) gbmrgb->g +
533 (word) gbmrgb->b ) / 0x30 );
534 }
535/*...e*/
536/*...smap_to_col4:0:*/
537/* The default 16 colour palette is disgusting to map to quickly.
538 Still, never mind, we only expect to be called 512 times. */
539
540/*...sdist_between:0:*/
541static int dist_between(const GBMRGB *p1, const GBMRGB *p2)
542 {
543 int dr = (int) ( (unsigned int) p1->r - (unsigned int) p2->r );
544 int dg = (int) ( (unsigned int) p1->g - (unsigned int) p2->g );
545 int db = (int) ( (unsigned int) p1->b - (unsigned int) p2->b );
546 return dr*dr + dg*dg + db*db;
547 }
548/*...e*/
549
550static byte map_to_col4(const GBMRGB *gbmrgb)
551 {
552 int i, i_min = 0;
553 int dist_min = dist_between(gbmrgb, &gbmrgb_4[0]);
554 for ( i = 1; i < 0x10; i++ )
555 {
556 int dist = dist_between(gbmrgb, &gbmrgb_4[i]);
557 if ( dist < dist_min )
558 {
559 dist_min = dist;
560 i_min = i;
561 }
562 }
563 return (byte) i_min;
564 }
565/*...e*/
566/*...shandle_vrep:0:*/
567static BOOLEAN handle_vrep(int fd, const byte *data, int step, int most, int *dy, int len)
568 {
569 byte buf[4];
570 if ( most > 0xff )
571 most = 0xff;
572 for ( *dy = 1; *dy < most; (*dy)++, data += step )
573 if ( memcmp(data, data+step, len) )
574 break;
575 if ( (*dy) == 1 )
576 return TRUE;
577 buf[0] = 0x00;
578 buf[1] = 0x00;
579 buf[2] = 0xff;
580 buf[3] = (byte) (*dy);
581 return gbm_file_write(fd, buf, 4) == 4;
582 }
583/*...e*/
584/*...sencode1:0:*/
585/* Encode scan bytes of data into temporary buffer enc.
586 0x00 repeated N times codes to N does not expand
587 0xff repeated N times codes to 0x80|N does not expand
588 X repeated N times codes to 0x00 N X expands if N<3
589 other N bytes codes to 0x80 N bytes N=1 expands to 3 ie: 3:1
590 N=2 expands to 4 ie: 2:1
591
592 len(enc) = len(data)*4/2 + 2 should do it. Worst case typically like :-
593
594 A B 0xff C D 0xff F
595 0x80 0x02 A B 0x81 0x80 0x02 C D 0x81 0x80 0x01 F */
596
597/*...sfind_run1:0:*/
598/* Look for a run of the same byte */
599
600static byte find_run1(const byte *data, int len)
601 {
602 const byte *p = data;
603 byte b = *p++;
604 if ( len > 0x7f )
605 len = 0x7f;
606 while ( --len > 0 && *p == b )
607 p++;
608 return (byte) ( p-data );
609 }
610/*...e*/
611/*...sfind_lit1:0:*/
612/* Handle literal runs.
613 We know the first 3 bytes (if there are as many as 3) differ.
614 We can only return a number as high as 0x7f from this function. */
615
616static byte find_lit1(const byte *data, int len)
617 {
618 const byte *p;
619
620 if ( len <= 3 )
621 return len;
622 if ( len > 0x7f )
623 len = 0x7f;
624
625 p = data + 2;
626 while ( len-- > 3 && p[0] != p[1] && p[1] != 0x00 && p[1] != 0xff )
627 p++;
628
629 return p-data;
630 }
631/*...e*/
632
633static int encode1(const byte *data, int scan, byte *enc)
634 {
635 byte *enc_start = enc;
636 while ( scan )
637 {
638 byte len = find_run1(data, scan);
639 if ( *data == 0x00 || *data == 0xff )
640 *enc++ = ((*data&0x80)|len);
641 else if ( len >= 3 )
642 {
643 *enc++ = 0x00; /* Pattern */
644 *enc++ = len; /* Repeated len times */
645 *enc++ = *data; /* 1-byte pattern (patlen=1) */
646 }
647 else
648 {
649 len = find_lit1(data, scan);
650 *enc++ = 0x80; /* Literal run */
651 *enc++ = len;
652 memcpy(enc, data, len);
653 enc += len;
654 }
655 data += len;
656 scan -= len;
657 }
658 return enc-enc_start;
659 }
660/*...e*/
661/*...sencode3:0:*/
662/* Like encode1, except that patlen=3, so we try to find 3-byte-patterns.
663 In this code we always work in 3 byte aligned chunks each step.
664 This is not quite optimal, but nothing worth worrying too much about.
665 len(enc) = len(data)*5/3 + 2 should do it. Worst case is like :-
666
667 A B C 0xff 0xff 0xff D E F
668 0x80 0x03 A B C 0x83 0x80 0x03 D E F */
669
670/*...sfind_run3:0:*/
671/* Look for a run of the same 3-byte-pattern.
672 We know that data[0..2] are not all 0x00's or 0xff's on entry.
673 Takes length in 3-byte-units and returns length in 3-byte-units */
674
675static byte find_run3(const byte *data, int len)
676 {
677 const byte *p = data;
678 byte b0, b1, b2;
679 if ( len <= 1 )
680 return len;
681 if ( len > 0x7f )
682 len = 0x7f;
683 b0 = *p++; b1 = *p++; b2 = *p++;
684 while ( --len > 0 && p[0] == b0 && p[1] == b1 && p[2] == b2 )
685 p += 3;
686 return (byte) ( (p-data)/3 );
687 }
688/*...e*/
689/*...sfind_lit3:0:*/
690/* On entry data[0..2] differs from data[3..5], assuming len>=2.
691 Takes length in 3 byte units, returns length in bytes. */
692
693static byte find_lit3(const byte *data, int len)
694 {
695 const byte *p;
696
697 if ( len == 1 )
698 return 3;
699 if ( len > 0x7f/3 )
700 len = 0x7f/3;
701
702 p = data + 6;
703 while ( --len >= 2 && /* Another 3 */
704 (p[0]!=p[-3]||
705 p[1]!=p[-2]||
706 p[2]!=p[-1]) && /* They differ */
707 (p[0]|p[1]|p[2]) != 0x00 && /* Next not all 0x00's */
708 (p[0]&p[1]&p[2]) != 0xff ) /* And not all 0xff's */
709 p += 3;
710 return (byte) ( p-data );
711 }
712/*...e*/
713
714static int encode3(const byte *data, int scan, byte *enc)
715 {
716 byte *enc_start = enc;
717 while ( scan )
718 {
719 byte len;
720 if ( (*data == 0x00 || *data == 0xff) &&
721 (len = find_run1(data, scan)) >= 3 )
722 {
723 len = ((len/3)*3);
724 *enc++ = ((*data&0x80)|len);
725 data += len;
726 scan -= len;
727 }
728 else if ( (len = find_run3(data, scan/3)) >= 2 )
729 {
730 *enc++ = 0x00; /* Pattern */
731 *enc++ = len; /* Repeated len times */
732 *enc++ = data[0]; /* 3-byte pattern */
733 *enc++ = data[1];
734 *enc++ = data[2];
735 data += 3*len;
736 scan -= 3*len;
737 }
738 else
739 {
740 len = find_lit3(data, scan/3);
741 *enc++ = 0x80; /* Literal run */
742 *enc++ = len; /* # bytes */
743 memcpy(enc, data, len);
744 enc += len;
745 data += len;
746 scan -= len;
747 }
748 }
749 return enc-enc_start;
750 }
751/*...e*/
752/*...sliterally:0:*/
753/* The normal encode routines may result in expanding the data.
754 This routine checks that, and if so, re-encodes it literally.
755 A literal encoding only adds 2 bytes in 127. */
756
757static int literally(const byte *data, int scan, byte *enc, int len_enc)
758 {
759 byte *enc_start = enc;
760 if ( len_enc <= (scan*(0x7f+2))/0x7f )
761 return len_enc;
762 while ( scan )
763 {
764 int len = min(scan, 0x7f);
765 *enc++ = 0x80;
766 *enc++ = (byte) len;
767 memcpy(enc, data, len);
768 enc += len;
769 data += len;
770 scan -= len;
771 }
772 return enc-enc_start;
773 }
774/*...e*/
775
776GBM_ERR gem_w(const char *fn, int fd, const GBM *gbm, const GBMRGB *gbmrgb, const byte *data, const char *opt)
777 {
778 byte hdr[22];
779 int pixw = 85, pixh = 85;
780 BOOLEAN pal, grey;
781 int stride = ((gbm->w*gbm->bpp + 31) / 32) * 4;
782 int scan = (gbm->w+7)/8;
783
784/*...shandle options:8:*/
785{
786const char *s;
787
788fn=fn; /* Suppress 'unref arg' compiler warnings */
789
790pal = ( gbm_find_word(opt, "pal") != NULL );
791grey = ( gbm_find_word(opt, "grey") != NULL );
792
793if ( (s = gbm_find_word_prefix(opt, "pixw=")) != NULL )
794 sscanf(s + 5, "%d", &pixw);
795
796if ( (s = gbm_find_word_prefix(opt, "pixh=")) != NULL )
797 sscanf(s + 5, "%d", &pixh);
798}
799/*...e*/
800
801 /* Initial stab at a header */
802 putword(hdr , (word) 1); /* Version */
803 putword(hdr+1*2, (word) 8); /* Header length */
804 putword(hdr+2*2, (word) gbm->bpp); /* Number of planes */
805 putword(hdr+3*2, (word) 1); /* Pattern length */
806 putword(hdr+4*2, (word) pixw); /* Pixel width in microns */
807 putword(hdr+5*2, (word) pixh); /* Pixel height in microns */
808 putword(hdr+6*2, (word) gbm->w); /* Width in pixels */
809 putword(hdr+7*2, (word) gbm->h); /* Height in pixels */
810
811 data += (gbm->h-1) * stride;
812
813 switch ( gbm->bpp )
814 {
815/*...s1 \45\ simple case\44\ just 8 word header then data:16:*/
816case 1:
817 {
818 int y, dy;
819 byte *line, *enc;
820 BOOLEAN invert;
821
822 if ( pal )
823 {
824 putword(hdr+1*2, (word) (11+6)); /* Header length */
825 memcpy(hdr+8*2, "XIMG", 4); /* Signiture */
826 putword(hdr+10*2, 0); /* RGB */
827 if ( gbm_file_write(fd, hdr, 11*2) != 11*2 )
828 return GBM_ERR_WRITE;
829 if ( !write_pal(fd, gbmrgb, 2) )
830 return GBM_ERR_WRITE;
831 invert = FALSE;
832 }
833 else
834 {
835 if ( gbm_file_write(fd, hdr, 8*2) != 8*2 )
836 return GBM_ERR_WRITE;
837 invert = ( gbmrgb[0].r+gbmrgb[0].g+gbmrgb[0].b <
838 gbmrgb[1].r+gbmrgb[1].g+gbmrgb[1].b );
839 }
840
841 if ( (line = malloc((size_t) scan)) == NULL )
842 return GBM_ERR_MEM;
843
844 if ( (enc = malloc((size_t) (scan*2+2))) == NULL )
845 { free(line); return GBM_ERR_MEM; }
846
847 for ( y = gbm->h; y > 0; y -= dy, data -= dy*stride )
848 {
849 int len_enc;
850 const byte *p;
851 if ( !handle_vrep(fd, data, -stride, y, &dy, scan) )
852 { free(enc); free(line); return GBM_ERR_WRITE; }
853 if ( invert )
854 {
855 int x;
856 for ( x = 0; x < scan; x++ )
857 line[x] = ~data[x];
858 p = line;
859 }
860 else
861 p = data;
862 len_enc = literally(p, scan, enc, encode1(p, scan, enc));
863 if ( gbm_file_write(fd, enc, len_enc) != len_enc )
864 { free(enc); free(line); return GBM_ERR_WRITE; }
865 }
866
867 free(enc);
868 free(line);
869
870 }
871 break;
872/*...e*/
873/*...s4 \45\ map to colour palette\44\ or to greyscale\44\ or XIMG it:16:*/
874case 4:
875 {
876 int y, dy;
877 byte *line, *mapped, *enc;
878 byte map[0x100];
879
880 if ( pal )
881 {
882 putword(hdr+1*2, (word) (11+0x30)); /* Header length */
883 memcpy(hdr+8*2, "XIMG", 4); /* Signiture */
884 putword(hdr+10*2, 0); /* RGB */
885 if ( gbm_file_write(fd, hdr, 11*2) != 11*2 )
886 return GBM_ERR_WRITE;
887 if ( !write_pal(fd, gbmrgb, 0x10) )
888 return GBM_ERR_WRITE;
889 }
890 else if ( grey )
891 {
892 unsigned int i;
893 putword(hdr+1*2, (word) 9); /* Header length */
894 putword(hdr+8*2, (word) 1); /* Greyscale data */
895 if ( gbm_file_write(fd, hdr, 9*2) != 9*2 )
896 return GBM_ERR_WRITE;
897 for ( i = 0; i < 0x100; i++ )
898 map[i] = (map_to_grey4(gbmrgb+((i>>4)&15U))<<4) |
899 map_to_grey4(gbmrgb+( i &15U)) ;
900 }
901 else
902 {
903 unsigned int i;
904 if ( gbm_file_write(fd, hdr, 8*2) != 8*2 )
905 return GBM_ERR_WRITE;
906 for ( i = 0; i < 0x100; i++ )
907 map[i] = (map_to_col4(gbmrgb+((i>>4)&15U))<<4) |
908 map_to_col4(gbmrgb+( i &15U)) ;
909 }
910
911 if ( (mapped = malloc((size_t) ((gbm->w+1)/2))) == NULL )
912 return GBM_ERR_MEM;
913
914 if ( (line = malloc((size_t) scan)) == NULL )
915 { free(mapped); return GBM_ERR_MEM; }
916
917 if ( (enc = malloc((size_t) (scan*2+2))) == NULL )
918 { free(line); free(mapped); return GBM_ERR_MEM; }
919
920 for ( y = gbm->h; y > 0; y -= dy, data -= dy*stride )
921 {
922 int x, len_enc, plane;
923 const byte *p;
924 byte bit, mask;
925 if ( !handle_vrep(fd, data, -stride, y, &dy, gbm->w) )
926 { free(enc); free(line); free(mapped); return GBM_ERR_WRITE; }
927 if ( pal )
928 p = data;
929 else
930 {
931 for ( x = 0; x < (gbm->w+1)/2; x++ )
932 mapped[x] = map[data[x]];
933 p = mapped;
934 }
935 for ( plane = 0, bit = 0x11; plane < 4; plane++, bit <<= 1 )
936 {
937 memset(line, 0, scan);
938 for ( x = 0, mask = 0xf0; x < gbm->w; x++, mask ^= 0xff )
939 if ( p[(unsigned)x>>1]&(bit&mask) )
940 line[(unsigned)x>>3] |= (0x80>>((unsigned)x&7));
941 len_enc = literally(line, scan, enc, encode1(line, scan, enc));
942 if ( gbm_file_write(fd, enc, len_enc) != len_enc )
943 { free(enc); free(line); free(mapped); return GBM_ERR_MEM; }
944 }
945 }
946
947 free(enc);
948 free(line);
949 free(mapped);
950
951 }
952 break;
953/*...e*/
954/*...s8 \45\ map to greyscale\44\ or XIMG it:16:*/
955case 8:
956 {
957 int y, dy;
958 byte *line, *mapped, *enc;
959 byte map[0x100];
960
961 if ( pal )
962 {
963 putword(hdr+1*2, (word) (11+0x300)); /* Header length */
964 memcpy(hdr+8*2, "XIMG", 4); /* Signiture */
965 putword(hdr+10*2, 0); /* RGB */
966 if ( gbm_file_write(fd, hdr, 11*2) != 11*2 )
967 return GBM_ERR_WRITE;
968 if ( !write_pal(fd, gbmrgb, 0x100) )
969 return GBM_ERR_WRITE;
970 }
971 else
972 {
973 int i;
974 putword(hdr+1*2, (word) 9); /* Header length */
975 putword(hdr+8*2, (word) 1); /* Greyscale data */
976 if ( gbm_file_write(fd, hdr, 9*2) != 9*2 )
977 return GBM_ERR_WRITE;
978 for ( i = 0; i < 0x100; i++ )
979 map[i] = (byte) ( ( (word) gbmrgb[i].r+
980 (word) gbmrgb[i].g+
981 (word) gbmrgb[i].b) / 3 );
982 }
983
984 if ( (mapped = malloc((size_t) gbm->w)) == NULL )
985 return GBM_ERR_MEM;
986
987 if ( (line = malloc((size_t) scan)) == NULL )
988 { free(mapped); return GBM_ERR_MEM; }
989
990 if ( (enc = malloc((size_t) (scan*2+2))) == NULL )
991 { free(line); free(mapped); return GBM_ERR_MEM; }
992
993 for ( y = gbm->h; y > 0; y -= dy, data -= dy*stride )
994 {
995 int x, len_enc, plane;
996 const byte *p;
997 byte bit;
998 if ( !handle_vrep(fd, data, -stride, y, &dy, gbm->w) )
999 { free(enc); free(line); free(mapped); return GBM_ERR_WRITE; }
1000 if ( pal )
1001 p = data;
1002 else
1003 {
1004 for ( x = 0; x < gbm->w; x++ )
1005 mapped[x] = map[data[x]];
1006 p = mapped;
1007 }
1008 for ( plane = 0, bit = 0x01; plane < 8; plane++, bit <<= 1 )
1009 {
1010 memset(line, 0, scan);
1011 for ( x = 0; x < gbm->w; x++ )
1012 if ( p[x]&bit )
1013 line[(unsigned)x>>3] |= (0x80U>>((unsigned)x&7U));
1014 len_enc = literally(line, scan, enc, encode1(line, scan, enc));
1015 if ( gbm_file_write(fd, enc, len_enc) != len_enc )
1016 { free(enc); free(line); free(mapped); return GBM_ERR_MEM; }
1017 }
1018 }
1019
1020 free(enc);
1021 free(line);
1022 free(mapped);
1023
1024 }
1025 break;
1026/*...e*/
1027/*...s24 \45\ write raw 24 bpp data in XIMG file:16:*/
1028case 24:
1029 {
1030 int y, dy;
1031 byte *line, *enc;
1032
1033 putword(hdr+1*2, (word) 11); /* Header length */
1034 putword(hdr+3*2, (word) 3); /* Pattern length */
1035 memcpy(hdr+8*2, "XIMG", 4); /* Signiture */
1036 putword(hdr+10*2, (word) 0); /* RGB */
1037 if ( gbm_file_write(fd, hdr, 11*2) != 11*2 )
1038 return GBM_ERR_WRITE;
1039
1040 if ( (line = malloc((size_t) (gbm->w*3))) == NULL )
1041 return GBM_ERR_MEM;
1042
1043 if ( (enc = malloc((size_t) (gbm->w*3*2+2))) == NULL )
1044 { free(line); return GBM_ERR_MEM; }
1045
1046 for ( y = gbm->h; y > 0; y -= dy, data -= dy*stride )
1047 {
1048 int len_enc;
1049 if ( !handle_vrep(fd, data, -stride, y, &dy, gbm->w*3) )
1050 { free(enc); free(line); return GBM_ERR_WRITE; }
1051 rgb_bgr(data, line, gbm->w);
1052 len_enc = literally(line, gbm->w*3, enc, encode3(line, gbm->w*3, enc));
1053 if ( gbm_file_write(fd, enc, len_enc) != len_enc )
1054 { free(enc); free(line); return GBM_ERR_WRITE; }
1055 }
1056
1057 free(enc);
1058 free(line);
1059
1060 }
1061 break;
1062/*...e*/
1063 }
1064
1065 return GBM_ERR_OK;
1066 }
1067/*...e*/
1068/*...sgem_err:0:*/
1069const char *gem_err(GBM_ERR rc)
1070 {
1071 switch ( (int) rc )
1072 {
1073 case GBM_ERR_GEM_IS_DVI:
1074 return "not GEM Raster, probably green channel of an Intel DVI image";
1075 case GBM_ERR_GEM_IS_IMDS:
1076 return "not GEM Raster, probably IMDS image";
1077 case GBM_ERR_GEM_BAD_VERSION:
1078 return "version number not 1";
1079 case GBM_ERR_GEM_BAD_HDRLEN:
1080 return "header length must be 8 words or more";
1081 case GBM_ERR_GEM_BAD_PLANES:
1082 return "number of planes not in range 1 to 8, or 24";
1083 case GBM_ERR_GEM_BAD_FLAG:
1084 return "flag not 0 or 1";
1085 case GBM_ERR_GEM_FIXEDCPAL:
1086 return "number of planes in colour image must be 1,3 or 4";
1087 case GBM_ERR_GEM_XIMG_TYPE:
1088 return "palette type not 0 in XIMG header";
1089 }
1090 return NULL;
1091 }
1092/*...e*/
Note: See TracBrowser for help on using the repository browser.