gocr-ruby 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +49 -0
- data/ext/gocr/Makefile +141 -0
- data/ext/gocr/Makefile.in +140 -0
- data/ext/gocr/amiga.h +31 -0
- data/ext/gocr/barcode.c +2108 -0
- data/ext/gocr/barcode.h +11 -0
- data/ext/gocr/box.c +496 -0
- data/ext/gocr/config.h +37 -0
- data/ext/gocr/config.h.in +36 -0
- data/ext/gocr/database.c +468 -0
- data/ext/gocr/detect.c +1003 -0
- data/ext/gocr/extconf.rb +6 -0
- data/ext/gocr/gocr.c +436 -0
- data/ext/gocr/gocr.h +290 -0
- data/ext/gocr/jconv.c +168 -0
- data/ext/gocr/job.c +92 -0
- data/ext/gocr/lines.c +364 -0
- data/ext/gocr/list.c +334 -0
- data/ext/gocr/list.h +91 -0
- data/ext/gocr/ocr0.c +7312 -0
- data/ext/gocr/ocr0.h +63 -0
- data/ext/gocr/ocr0n.c +1527 -0
- data/ext/gocr/ocr1.c +85 -0
- data/ext/gocr/ocr1.h +3 -0
- data/ext/gocr/otsu.c +310 -0
- data/ext/gocr/otsu.h +23 -0
- data/ext/gocr/output.c +291 -0
- data/ext/gocr/output.h +37 -0
- data/ext/gocr/pcx.c +153 -0
- data/ext/gocr/pcx.h +9 -0
- data/ext/gocr/pgm2asc.c +3259 -0
- data/ext/gocr/pgm2asc.h +105 -0
- data/ext/gocr/pixel.c +538 -0
- data/ext/gocr/pnm.c +538 -0
- data/ext/gocr/pnm.h +35 -0
- data/ext/gocr/progress.c +87 -0
- data/ext/gocr/progress.h +42 -0
- data/ext/gocr/remove.c +715 -0
- data/ext/gocr/tga.c +87 -0
- data/ext/gocr/tga.h +6 -0
- data/ext/gocr/unicode.c +1318 -0
- data/ext/gocr/unicode.h +62 -0
- data/ext/gocr/unicode_defs.h +1245 -0
- data/ext/gocr/version.h +2 -0
- data/gocr-ruby.gemspec +28 -0
- data/image.png +0 -0
- data/lib/gocr.rb +6 -0
- data/lib/gocr/image.rb +8 -0
- data/lib/gocr/version.rb +3 -0
- metadata +156 -0
data/ext/gocr/pnm.c
ADDED
@@ -0,0 +1,538 @@
|
|
1
|
+
/*
|
2
|
+
This is a Optical-Character-Recognition program
|
3
|
+
Copyright (C) 2000-2010 Joerg Schulenburg
|
4
|
+
|
5
|
+
This program is free software; you can redistribute it and/or
|
6
|
+
modify it under the terms of the GNU General Public License
|
7
|
+
as published by the Free Software Foundation; either version 2
|
8
|
+
of the License, or (at your option) any later version.
|
9
|
+
|
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 General Public License for more details.
|
14
|
+
|
15
|
+
You should have received a copy of the GNU General Public License
|
16
|
+
along with this program; if not, write to the Free Software
|
17
|
+
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
18
|
+
|
19
|
+
see README for EMAIL-address
|
20
|
+
|
21
|
+
v0.1.0 initial version (stdin added)
|
22
|
+
v0.2.0 popen added
|
23
|
+
v0.2.7 review by Bruno Barberi Gnecco
|
24
|
+
v0.39 autoconf
|
25
|
+
v0.41 fix integer and heap overflow, change color output
|
26
|
+
v0.46 fix blank spaces problem in filenames
|
27
|
+
*/
|
28
|
+
|
29
|
+
#include <stdlib.h>
|
30
|
+
#include <stdio.h>
|
31
|
+
#include <string.h>
|
32
|
+
#include <assert.h>
|
33
|
+
#ifdef HAVE_UNISTD_H
|
34
|
+
/* #include <unistd.h> */
|
35
|
+
#endif
|
36
|
+
|
37
|
+
/* Windows needs extra code to work fine, ^Z in BMP's will stop input else.
|
38
|
+
* I do not have any idea when this text mode will be an advantage
|
39
|
+
* but the MS community seems to like to do simple things in a complex way. */
|
40
|
+
#if defined(O_BINARY) && (defined(__WIN32) || defined(__WIN32__)\
|
41
|
+
|| defined(__WIN64) || defined(__WIN64__) || defined(__MSDOS__))
|
42
|
+
# include <fcntl.h>
|
43
|
+
# define SET_BINARY(_f) do {if (!isatty(_f)) setmode (_f, O_BINARY);} while (0)
|
44
|
+
#else
|
45
|
+
# define SET_BINARY(f) (void)0
|
46
|
+
#endif
|
47
|
+
|
48
|
+
#include "pnm.h"
|
49
|
+
#ifdef HAVE_PAM_H
|
50
|
+
# include <pam.h>
|
51
|
+
# include <sys/types.h>
|
52
|
+
# include <sys/stat.h>
|
53
|
+
# include <fcntl.h>
|
54
|
+
#else
|
55
|
+
# include <ctype.h>
|
56
|
+
#endif
|
57
|
+
|
58
|
+
#define EE() fprintf(stderr,"\nERROR "__FILE__" L%d: ",__LINE__)
|
59
|
+
#define E0(x0) {EE();fprintf(stderr,x0 "\n"); }
|
60
|
+
#define F0(x0) {EE();fprintf(stderr,x0 "\n"); exit(1);}
|
61
|
+
#define F1(x0,x1) {EE();fprintf(stderr,x0 "\n",x1); exit(1);}
|
62
|
+
|
63
|
+
/*
|
64
|
+
* Weights to use for the different colours when converting a ppm
|
65
|
+
* to greyscale. These weights should sum to 1.0
|
66
|
+
*
|
67
|
+
* The below values have been chosen to reflect the fact that paper
|
68
|
+
* goes a reddish-yellow as it ages.
|
69
|
+
*
|
70
|
+
* v0.41: for better performance, we use integer instead of double
|
71
|
+
* this integer value divided by 1024 (2^10) gives the factor
|
72
|
+
*/
|
73
|
+
#define PPM_RED_WEIGHT 511 /* .499 */
|
74
|
+
#define PPM_GREEN_WEIGHT 396 /* .387 */
|
75
|
+
#define PPM_BLUE_WEIGHT 117 /* .114 */
|
76
|
+
|
77
|
+
/*
|
78
|
+
feel free to expand this list of usable converting programs
|
79
|
+
Note 1: the last field must be NULL.
|
80
|
+
Note 2: "smaller" extensions must come later: ".pnm.gz" must come
|
81
|
+
before ".pnm".
|
82
|
+
calling external programs is a security risk
|
83
|
+
ToDo: for better security replace gzip by /usr/bin/gzip !
|
84
|
+
*/
|
85
|
+
char *xlist[]={
|
86
|
+
".pnm.gz", "gzip -cd", /* compressed pnm-files, gzip package */
|
87
|
+
".pbm.gz", "gzip -cd",
|
88
|
+
".pgm.gz", "gzip -cd",
|
89
|
+
".ppm.gz", "gzip -cd",
|
90
|
+
".pnm.bz2", "bzip2 -cd",
|
91
|
+
".pbm.bz2", "bzip2 -cd",
|
92
|
+
".pgm.bz2", "bzip2 -cd",
|
93
|
+
".ppm.bz2", "bzip2 -cd",
|
94
|
+
".jpg", "djpeg -gray -pnm", /* JPG/JPEG, jpeg package */
|
95
|
+
".jpeg", "djpeg -gray -pnm",
|
96
|
+
".gif", "giftopnm -image=all", /* GIF, netpbm package */
|
97
|
+
".bmp", "bmptoppm",
|
98
|
+
".tiff", "tifftopnm",
|
99
|
+
".png", "pngtopnm", /* Portable Network Graphics (PNG) format */
|
100
|
+
".ps", "pstopnm -stdout -portrait -pgm", /* postscript */
|
101
|
+
".eps", "pstopnm -stdout -portrait -pgm", /* encapsulated postscript */
|
102
|
+
/* gs -sDEVICE=pgmraw -sOutputFile=- -g609x235 -r141x141 -q -dNOPAUSE */
|
103
|
+
".fig", "fig2dev -L ppm -m 3", /* xfig files, transfig package */
|
104
|
+
NULL
|
105
|
+
};
|
106
|
+
|
107
|
+
/* return a pointer to command converting file to pnm or NULL */
|
108
|
+
char *testsuffix(char *name){
|
109
|
+
int i; char *rr;
|
110
|
+
|
111
|
+
for(i = 0; xlist[i] != NULL; i += 2 ) {
|
112
|
+
// ToDo: new version = no case sensitivity, .JPG = .jpg
|
113
|
+
// xlen=length(xlist[i]);
|
114
|
+
// rlen=length(rr);
|
115
|
+
// if (xlen>rlen && strncasecmp(rr+rlen-xlen,xlist[i])==0) ...
|
116
|
+
// old version = case sensitivity!
|
117
|
+
if((rr=strstr(name, xlist[i])) != NULL)
|
118
|
+
if(strlen(rr)==strlen(xlist[i])) /* handle *.eps.pbm correct */
|
119
|
+
return xlist[i+1];
|
120
|
+
}
|
121
|
+
return NULL;
|
122
|
+
}
|
123
|
+
|
124
|
+
|
125
|
+
char read_char(FILE *f1){ // filter #-comments
|
126
|
+
char c;
|
127
|
+
int m;
|
128
|
+
for(m=0;;){
|
129
|
+
c=fgetc(f1);
|
130
|
+
if( feof(f1) ) E0("read feof");
|
131
|
+
if( ferror(f1) ) F0("read ferror");
|
132
|
+
if( c == '#' ) { m = 1; continue; }
|
133
|
+
if( m == 0 ) return c;
|
134
|
+
if( c == '\n' ) m = 0;
|
135
|
+
}
|
136
|
+
}
|
137
|
+
|
138
|
+
|
139
|
+
/*
|
140
|
+
for simplicity only PAM of netpbm is used, the older formats
|
141
|
+
PBM, PGM and PPM can be handled implicitly by PAM routines (js05)
|
142
|
+
v0.43: return 1 if multiple file (hold it open), 0 otherwise
|
143
|
+
*/
|
144
|
+
#ifdef HAVE_PAM_H
|
145
|
+
int readpgm(char *name, pix * p, int vvv) {
|
146
|
+
static FILE *fp=NULL;
|
147
|
+
static char *pip;
|
148
|
+
char magic1, magic2;
|
149
|
+
int i, j, sample, minv = 0, maxv = 0, eofP=0;
|
150
|
+
struct pam inpam;
|
151
|
+
tuple *tuplerow;
|
152
|
+
|
153
|
+
assert(p);
|
154
|
+
|
155
|
+
if (!fp) { // fp!=0 for multi-pnm and idx>0
|
156
|
+
/* open file; test if conversion is needed. */
|
157
|
+
if (name[0] == '-' && name[1] == '\0') {
|
158
|
+
fp = stdin;
|
159
|
+
SET_BINARY (fileno(fp)); // Windows needs it for correct work
|
160
|
+
}
|
161
|
+
else {
|
162
|
+
pip = testsuffix(name);
|
163
|
+
if (!pip) {
|
164
|
+
fp = fopen(name, "rb");
|
165
|
+
if (!fp)
|
166
|
+
F1("opening file %s", name);
|
167
|
+
}
|
168
|
+
else {
|
169
|
+
char *buf = (char *)malloc((strlen(pip)+strlen(name)+4));
|
170
|
+
sprintf(buf, "%s \"%s\"", pip, name); /* allow spaces in filename */
|
171
|
+
if (vvv) {
|
172
|
+
fprintf(stderr, "# popen( %s )\n", buf);
|
173
|
+
}
|
174
|
+
#ifdef HAVE_POPEN
|
175
|
+
/* potential security vulnerability, if name contains tricks */
|
176
|
+
/* example: gunzip -c dummy | rm -rf * */
|
177
|
+
/* windows needs "rb" for correct work, linux not, cygwin? */
|
178
|
+
/* ToDo: do you have better code to go arround this? */
|
179
|
+
#if defined(__WIN32) || defined(__WIN32__) || defined(__WIN64) || defined(__WIN64__)
|
180
|
+
fp = popen(buf, "rb"); /* ToDo: may fail, please report */
|
181
|
+
if (!fp) fp = popen(buf, "r"); /* 2nd try, the gnu way */
|
182
|
+
#else
|
183
|
+
fp = popen(buf, "r");
|
184
|
+
#endif
|
185
|
+
#else
|
186
|
+
F0("sorry, compile with HAVE_POPEN to use pipes");
|
187
|
+
#endif
|
188
|
+
if (!fp)
|
189
|
+
F1("opening pipe %s", buf);
|
190
|
+
free(buf);
|
191
|
+
}
|
192
|
+
}
|
193
|
+
}
|
194
|
+
|
195
|
+
/* netpbm 0.10.36 tries to write a comment to nonzero char** comment_p */
|
196
|
+
/* patch by C.P.Schmidt 21Nov06 */
|
197
|
+
memset (&inpam, 0, sizeof(inpam));
|
198
|
+
|
199
|
+
/* read pgm-header */
|
200
|
+
/* struct pam may change between netpbm-versions, causing problems? */
|
201
|
+
#ifdef PAM_STRUCT_SIZE /* ok for netpbm-10.35 */
|
202
|
+
/* new-and-better? but PAM_STRUCT_SIZE is not defined in netpbm-10.18 */
|
203
|
+
pnm_readpaminit(fp, &inpam, PAM_STRUCT_SIZE(tuple_type));
|
204
|
+
#else /* ok for netpbm-10.18 old-and-bad for new netpbms */
|
205
|
+
pnm_readpaminit(fp, &inpam, sizeof(inpam));
|
206
|
+
#endif
|
207
|
+
|
208
|
+
p->x = inpam.width;
|
209
|
+
p->y = inpam.height;
|
210
|
+
magic1=(inpam.format >> 8) & 255; /* 'P' for PNM,PAM */
|
211
|
+
magic2=(inpam.format ) & 255; /* '7' for PAM */
|
212
|
+
minv=inpam.maxval;
|
213
|
+
if (vvv) {
|
214
|
+
fprintf(stderr, "# readpam: format=0x%04x=%c%c h*w(d*b)=%d*%d(%d*%d)\n",
|
215
|
+
inpam.format, /* magic1*256+magic2 */
|
216
|
+
((magic1>31 && magic1<127)?magic1:'.'),
|
217
|
+
((magic2>31 && magic2<127)?magic2:'.'),
|
218
|
+
inpam.height,
|
219
|
+
inpam.width,
|
220
|
+
inpam.depth,
|
221
|
+
inpam.bytes_per_sample);
|
222
|
+
}
|
223
|
+
if ( (1.*(p->x*p->y))!=((1.*p->x)*p->y) )
|
224
|
+
F0("Error integer overflow");
|
225
|
+
if ( !(p->p = (unsigned char *)malloc(p->x*p->y)) )
|
226
|
+
F1("Error at malloc: p->p: %d bytes", p->x*p->y);
|
227
|
+
tuplerow = pnm_allocpamrow(&inpam);
|
228
|
+
for ( i=0; i < inpam.height; i++ ) {
|
229
|
+
pnm_readpamrow(&inpam, tuplerow); /* exit on error */
|
230
|
+
for ( j = 0; j < inpam.width; j++ ) {
|
231
|
+
if (inpam.depth>=3)
|
232
|
+
/* tuplerow is unsigned long (see pam.h sample) */
|
233
|
+
/* we expect 8bit or 16bit integers,
|
234
|
+
no overflow up to 32-10-2=20 bits */
|
235
|
+
sample
|
236
|
+
= ((PPM_RED_WEIGHT * tuplerow[j][0] + 511)>>10)
|
237
|
+
+ ((PPM_GREEN_WEIGHT * tuplerow[j][1] + 511)>>10)
|
238
|
+
+ ((PPM_BLUE_WEIGHT * tuplerow[j][2] + 511)>>10);
|
239
|
+
else
|
240
|
+
sample = tuplerow[j][0];
|
241
|
+
sample = 255 * sample / inpam.maxval; /* normalize to 8 bit */
|
242
|
+
p->p[i*inpam.width+j] = sample;
|
243
|
+
if (maxv<sample) maxv=sample;
|
244
|
+
if (minv>sample) minv=sample;
|
245
|
+
}
|
246
|
+
}
|
247
|
+
pnm_freepamrow(tuplerow);
|
248
|
+
pnm_nextimage(fp,&eofP);
|
249
|
+
if (vvv)
|
250
|
+
fprintf(stderr,"# readpam: min=%d max=%d eof=%d\n", minv, maxv, eofP);
|
251
|
+
p->bpp = 1;
|
252
|
+
if (eofP) {
|
253
|
+
if (!pip) fclose(fp);
|
254
|
+
#ifdef HAVE_POPEN
|
255
|
+
else pclose(fp); /* close pipe (v0.43) */
|
256
|
+
#endif
|
257
|
+
fp=NULL; return 0;
|
258
|
+
}
|
259
|
+
return 1; /* multiple image = concatenated pnm */
|
260
|
+
}
|
261
|
+
|
262
|
+
#else
|
263
|
+
/*
|
264
|
+
if PAM not installed, here is the fallback routine,
|
265
|
+
which is not so powerful but needs no dependencies from other libs
|
266
|
+
*/
|
267
|
+
static int fread_num(char *buf, int bps, FILE *f1) {
|
268
|
+
int mode, j2, j3; char c1;
|
269
|
+
for (j2=0;j2<bps;j2++) buf[j2]=0; // initialize value to zero
|
270
|
+
for(mode=0;!feof(f1);){ // mod=0 means skip leading spaces, 1 scan digits
|
271
|
+
c1=read_char(f1);
|
272
|
+
if (isspace(c1)) { if (mode==0) continue; else break; }
|
273
|
+
mode=1; // digits scan mode
|
274
|
+
if( !isdigit(c1) ) F0("unexpected char");
|
275
|
+
for (j3=j2=0;j2<bps;j2++) { // multiply bps*bytes by 10
|
276
|
+
j3 = buf[j2]*10 + j3; // j3 is used as result and carry
|
277
|
+
buf[j2]=j3 & 255; j3>>=8;
|
278
|
+
}
|
279
|
+
buf[0] += c1-'0';
|
280
|
+
}
|
281
|
+
return 0;
|
282
|
+
}
|
283
|
+
|
284
|
+
/*
|
285
|
+
* read image file, used to read the OCR-image and database images,
|
286
|
+
* image file can be PBM/PGM/PPM in RAW or TEXT
|
287
|
+
* name: filename of image (input)
|
288
|
+
* p: pointer where to store the loaded image (input)
|
289
|
+
* vvv: verbose mode (input)
|
290
|
+
* return: 0=ok, 1=further image follows (multiple image), -1 on error
|
291
|
+
* this is the fall back routine if libpnm cant be used
|
292
|
+
*/
|
293
|
+
int readpgm( char *name, pix *p, int vvv){
|
294
|
+
static char c1, c2; /* magic bytes, file type */
|
295
|
+
static char *pip; // static to survive multiple calls
|
296
|
+
int nx,ny,nc,mod,i,j; // buffer
|
297
|
+
static FILE *f1=NULL; // trigger read new file or multi image file
|
298
|
+
unsigned char *pic;
|
299
|
+
char buf[512];
|
300
|
+
int lx, ly, dx;
|
301
|
+
int bps=1; /* bytes per sample (0..255..65535...) */
|
302
|
+
|
303
|
+
if (!f1) { /* first of multiple image, on MultipleImageFiles c1 was read */
|
304
|
+
pip=NULL;
|
305
|
+
if (name[0]=='-' && name[1]==0) {
|
306
|
+
f1=stdin; /* is this correct ??? */
|
307
|
+
SET_BINARY (fileno(f1)); // Windows needs it for correct work
|
308
|
+
} else {
|
309
|
+
pip=testsuffix(name);
|
310
|
+
if (!pip) {
|
311
|
+
f1=fopen(name,"rb"); if (!f1) F1("opening file %s",name);
|
312
|
+
} else {
|
313
|
+
sprintf(buf,"%s \"%s\"",pip,name); /* ToDo: how to prevent OVL ? */
|
314
|
+
if (vvv) { fprintf(stderr,"# popen( %s )\n",buf); }
|
315
|
+
#ifdef HAVE_POPEN
|
316
|
+
#if defined(__WIN32) || defined(__WIN32__) || defined(__WIN64) || defined(__WIN64__)
|
317
|
+
f1 = popen(buf, "rb"); /* ToDo: may fail, please report */
|
318
|
+
if (!f1) f1 = popen(buf, "r"); /* 2nd try, the gnu way */
|
319
|
+
#else
|
320
|
+
f1=popen(buf,"r");
|
321
|
+
#endif
|
322
|
+
#else
|
323
|
+
F0("only PNM files supported (compiled without HAVE_POPEN)");
|
324
|
+
#endif
|
325
|
+
if (!f1) F1("opening pipe %s",buf);
|
326
|
+
}
|
327
|
+
}
|
328
|
+
c1=fgetc(f1); if (feof(f1)) { E0("unexpected EOF"); return -1; }
|
329
|
+
}
|
330
|
+
c2=fgetc(f1); if (feof(f1)) { E0("unexpected EOF"); return -1; }
|
331
|
+
// check the first two bytes of the PNM file
|
332
|
+
// PBM PGM PPM
|
333
|
+
// TXT P1 P2 P3
|
334
|
+
// RAW P4 P5 P6
|
335
|
+
if (c1!='P' || c2 <'1' || c2 >'6') {
|
336
|
+
fprintf(stderr,"\nread-PNM-error: file number is %2d,"
|
337
|
+
" position %ld", fileno(f1), ftell(f1));
|
338
|
+
fprintf(stderr,"\nread-PNM-error: bad magic bytes, expect 0x50 0x3[1-6]"
|
339
|
+
" but got 0x%02x 0x%02x", 255&c1, 255&c2);
|
340
|
+
if (f1) fclose(f1); f1=NULL; return(-1);
|
341
|
+
}
|
342
|
+
nx=ny=nc=0; if (c2=='4' || c2=='1') nc=1;
|
343
|
+
for(mod=0;((c2=='5' || c2=='2') && (mod&7)<6)
|
344
|
+
|| ((c2=='6' || c2=='3') && (mod&7)<6)
|
345
|
+
|| ((c2=='4' || c2=='1') && (mod&7)<4);)
|
346
|
+
{ // mode: 0,2,4=[ |\t|\r|\n]
|
347
|
+
// 1=nx 3=ny 5=nc 8-13=#rem
|
348
|
+
c1=read_char(f1); // former: # mod|=8
|
349
|
+
if( (mod & 1)==0 ) // whitespaces
|
350
|
+
if( !isspace(c1) ) mod++;
|
351
|
+
if( (mod & 1)==1 ) {
|
352
|
+
if( !isdigit(c1) ) {
|
353
|
+
if( !isspace(c1) )F0("unexpected character");
|
354
|
+
mod++; }
|
355
|
+
else if(mod==1) nx=nx*10+c1-'0';
|
356
|
+
else if(mod==3) ny=ny*10+c1-'0';
|
357
|
+
else if(mod==5) nc=nc*10+c1-'0';
|
358
|
+
}
|
359
|
+
}
|
360
|
+
if(vvv)
|
361
|
+
fprintf(stderr,"# PNM P%c h*w=%d*%d c=%d head=%ld",c2,ny,nx,nc,ftell(f1));
|
362
|
+
if( c2=='4' && (nx&7)!=0 ){
|
363
|
+
/* nx=(nx+7)&~7;*/ if(vvv)fprintf(stderr," PBM2PGM nx %d",(nx+7)&~7);
|
364
|
+
}
|
365
|
+
if (nc>> 8) bps=2; // bytes per color and pixel
|
366
|
+
if (nc>>16) bps=3;
|
367
|
+
if (nc>>24) bps=4;
|
368
|
+
fflush(stdout);
|
369
|
+
if ( (1.*(nx*ny))!=((1.*nx)*ny) )
|
370
|
+
F0("Error integer overflow");
|
371
|
+
pic=(unsigned char *)malloc( nx*ny );
|
372
|
+
if(pic==NULL)F0("memory failed"); // no memory
|
373
|
+
for (i=0;i<nx*ny;i++) pic[i]=255; // init to white if reading fails
|
374
|
+
/* this is a slow but short routine for P1 to P6 formats */
|
375
|
+
if( c2=='5' || c2=='2' ) /* slow PGM-RAW/ASC read pixelwise */
|
376
|
+
for (i=0;i<nx*ny;i++) {
|
377
|
+
if (c2=='5') { if(bps!=(int)fread(buf,1,bps,f1)) {
|
378
|
+
fprintf(stderr," ERROR reading at head+%d*%d\n", bps, i); break; } }
|
379
|
+
else for (j=0;j<3;j++) fread_num(buf+j*bps, bps, f1);
|
380
|
+
pic[i]=buf[bps-1]; /* store the most significant byte */
|
381
|
+
}
|
382
|
+
// we want to normalize brightness to 0..255
|
383
|
+
if (c2=='6' || c2=='3') { // PPM-RAW/ASC
|
384
|
+
for (i=0;i<nx*ny;i++) {
|
385
|
+
if (c2=='6') { if (3*bps!=(int)fread(buf,1,3*bps,f1)){
|
386
|
+
fprintf(stderr," ERROR reading at head+3*%d*%d\n", bps, i); break; } }
|
387
|
+
else for (j=0;j<3;j++) fread_num(buf+j*bps, bps, f1);
|
388
|
+
pic[i]
|
389
|
+
= ((PPM_RED_WEIGHT * (unsigned char)buf[ bps-1] + 511)>>10)
|
390
|
+
+ ((PPM_GREEN_WEIGHT * (unsigned char)buf[2*bps-1] + 511)>>10)
|
391
|
+
+ ((PPM_BLUE_WEIGHT * (unsigned char)buf[3*bps-1] + 511)>>10);
|
392
|
+
/* normalized to 0..255 */
|
393
|
+
}
|
394
|
+
}
|
395
|
+
if( c2=='1' )
|
396
|
+
for(mod=j=i=0,nc=255;i<nx*ny && !feof(f1);){ // PBM-ASCII 0001100
|
397
|
+
c1=read_char(f1);
|
398
|
+
if( isdigit(c1) ) { pic[i]=((c1=='0')?255:0); i++; }
|
399
|
+
else if( !isspace(c1) )F0("unexpected char");
|
400
|
+
}
|
401
|
+
if( c2=='4' ){ // PBM-RAW
|
402
|
+
dx=(nx+7)&~7; // dx (mod 8)
|
403
|
+
if(ny!=(int)fread(pic,dx>>3,ny,f1))F0("read"); // read all bytes
|
404
|
+
for(ly=ny-1;ly>=0;ly--)
|
405
|
+
for(lx=nx-1;lx>=0;lx--)
|
406
|
+
pic[lx+ly*nx]=( (128 & (pic[(lx+ly*dx)>>3]<<(lx & 7))) ? 0 : 255 );
|
407
|
+
nc=255;
|
408
|
+
}
|
409
|
+
{
|
410
|
+
int minc=255, maxc=0;
|
411
|
+
for (i=0;i<nx*ny;i++) {
|
412
|
+
if (pic[i]>maxc) maxc=pic[i];
|
413
|
+
if (pic[i]<minc) minc=pic[i];
|
414
|
+
}
|
415
|
+
if (vvv) fprintf(stderr," min=%d max=%d", minc, maxc);
|
416
|
+
}
|
417
|
+
p->p=pic; p->x=nx; p->y=ny; p->bpp=1;
|
418
|
+
if (vvv) fprintf(stderr,"\n");
|
419
|
+
c1=0; c1=fgetc(f1); /* needed to trigger feof() */
|
420
|
+
if (feof(f1) || c1!='P') { /* EOF ^Z or not 'P' -> single image */
|
421
|
+
if (vvv) fprintf(stderr,"# PNM EOF\n");
|
422
|
+
if(name[0]!='-' || name[1]!=0){ /* do not close stdin */
|
423
|
+
if(!pip) fclose(f1);
|
424
|
+
#ifdef HAVE_POPEN
|
425
|
+
else pclose(f1); /* close pipe (Jul00) */
|
426
|
+
#endif
|
427
|
+
}
|
428
|
+
f1=NULL; /* set file is closed flag */
|
429
|
+
return 0;
|
430
|
+
}
|
431
|
+
return 1; /* multiple image = concatenated pnm's */
|
432
|
+
}
|
433
|
+
#endif /* HAVE_PAM_H */
|
434
|
+
|
435
|
+
int writepgm(char *nam,pix *p){// P5 raw-pgm
|
436
|
+
FILE *f1;int a,x,y;
|
437
|
+
f1=fopen(nam,"wb");if(!f1)F0("open"); // open-error
|
438
|
+
fprintf(f1,"P5\n%d %d\n255\n",p->x,p->y);
|
439
|
+
if(p->bpp==3)
|
440
|
+
for(y=0;y<p->y;y++)
|
441
|
+
for(x=0;x<p->x;x++){ // set bit
|
442
|
+
a=x+y*p->x;
|
443
|
+
p->p[a]=(p->p[3*a+0]+p->p[3*a+1]+p->p[3*a+2])/3;
|
444
|
+
}
|
445
|
+
if(p->y!=(int)fwrite(p->p,p->x,p->y,f1))F0("write"); // write all lines
|
446
|
+
fclose(f1);
|
447
|
+
return 0;
|
448
|
+
}
|
449
|
+
|
450
|
+
/* adding colours, care about range */
|
451
|
+
void addrgb(unsigned char rgb[3], int sr, int sg, int sb) {
|
452
|
+
int add[3], i;
|
453
|
+
/* add colour on dark pixels, subtract on white pixels */
|
454
|
+
add[0]=2*sr; add[1]=2*sg; add[2]=2*sb;
|
455
|
+
if (((int)rgb[0])+((int)rgb[1])+((int)rgb[2])>=3*160)
|
456
|
+
{ add[0]=(-sg-sb); add[1]=(-sr-sb); add[2]=(-sr-sg); } // rgb/2?
|
457
|
+
/* care about colour range */
|
458
|
+
for (i=0;i<3;i++)
|
459
|
+
if (add[i]<0) rgb[i]-=(( rgb[i]<-add[i])? rgb[i]:-add[i]);
|
460
|
+
else rgb[i]+=((255-rgb[i]< add[i])?255-rgb[i]: add[i]);
|
461
|
+
}
|
462
|
+
/*
|
463
|
+
* pgmtoppm or pnmtopng, use last 3 bits for farbcoding
|
464
|
+
* replaces old writebmp variant
|
465
|
+
*/
|
466
|
+
int writeppm(char *nam, pix *p){ /* P6 raw-ppm */
|
467
|
+
FILE *f1=NULL; int x,y,f1t=0; unsigned char rgb[3], gray, bits;
|
468
|
+
char buf[128];
|
469
|
+
if (strchr(nam,'|')) return -1; /* no nasty code */
|
470
|
+
if (strstr(nam,".ppm")) { f1=fopen(nam,"wb"); }
|
471
|
+
#ifdef HAVE_POPEN
|
472
|
+
/* be sure that nam contains hacker code like "dummy | rm -rf *" */
|
473
|
+
if (!f1) {
|
474
|
+
strncpy(buf,"pnmtopng > ",12); /* no spaces within filenames allowed! */
|
475
|
+
strncpy(buf+11,nam,111); buf[123]=0;
|
476
|
+
strncpy(buf+strlen(buf),".png",5);
|
477
|
+
/* we dont care about win "wb" here, never debug on win systems */
|
478
|
+
f1 = popen(buf, "w"); if(f1) f1t=1; else E0("popen pnmtopng");
|
479
|
+
}
|
480
|
+
if (!f1) {
|
481
|
+
strncpy(buf,"gzip -c > ",11);
|
482
|
+
strncpy(buf+10,nam,109); buf[120]=0;
|
483
|
+
strncpy(buf+strlen(buf),".ppm.gz",8);
|
484
|
+
/* we dont care about win "wb" here, never debug on win systems */
|
485
|
+
f1 = popen(buf, "w"); if(f1) f1t=1; else E0("popen gzip -c");
|
486
|
+
}
|
487
|
+
#endif
|
488
|
+
if (!f1) {
|
489
|
+
strncpy(buf,nam,113); buf[114]=0;
|
490
|
+
strncpy(buf+strlen(buf),".ppm",5);
|
491
|
+
f1=fopen(buf,"wb");
|
492
|
+
}
|
493
|
+
if (!f1) F0("open"); /* open-error */
|
494
|
+
fprintf(f1,"P6\n%d %d\n255\n",p->x,p->y);
|
495
|
+
if ( p->bpp==1 )
|
496
|
+
for (y=0;y<p->y;y++)
|
497
|
+
for (x=0;x<p->x;x++){
|
498
|
+
gray=p->p[x+y*p->x];
|
499
|
+
bits=(gray&0x0F); /* save marker bits */
|
500
|
+
/* replace used bits to get max. contrast, 160=0xA0 */
|
501
|
+
gray = ((gray<160) ? (gray&~0x0F)>>1 : 0xC3|(gray>>1) );
|
502
|
+
rgb[0] = rgb[1] = rgb[2] = gray;
|
503
|
+
if ((bits & 1)==1) { addrgb(rgb,0,0,8+8*((x+y)&1)); } /* dark blue */
|
504
|
+
if ((bits & 8)==8) { addrgb(rgb,0,0, 16); } /* blue (low priority) */
|
505
|
+
if ((bits & 6)==6) { addrgb(rgb,0,0, 32); } /* blue */
|
506
|
+
if ((bits & 6)==4) { addrgb(rgb,0,48,0); } /* green */
|
507
|
+
if ((bits & 6)==2) { addrgb(rgb,32,0,0); } /* red */
|
508
|
+
if ( 1!=(int)fwrite(rgb,3,1,f1) ) { E0("write"); y=p->y; break; }
|
509
|
+
}
|
510
|
+
if ( p->bpp==3 )
|
511
|
+
if ( p->y!=(int)fwrite(p->p,3*p->x,p->y,f1) ) E0("write");
|
512
|
+
#ifdef HAVE_POPEN
|
513
|
+
if (f1t) { pclose (f1); f1=NULL; }
|
514
|
+
#endif
|
515
|
+
if (f1) fclose(f1);
|
516
|
+
return 0;
|
517
|
+
}
|
518
|
+
|
519
|
+
// high bit = first,
|
520
|
+
int writepbm(char *nam,pix *p){// P4 raw-pbm
|
521
|
+
FILE *f1;int x,y,a,b,dx,i;
|
522
|
+
dx=(p->x+7)&~7; // enlarge to a factor of 8
|
523
|
+
for(y=0;y<p->y;y++)
|
524
|
+
for(x=0;x<p->x;x++){ // set bit
|
525
|
+
a=(x+y*dx)>>3;b=7-(x&7); // adress an bitisnumber
|
526
|
+
i=x+y*p->x;
|
527
|
+
if(p->bpp==3) i=(p->p[3*i+0]+p->p[3*i+1]+p->p[3*i+2])/3;
|
528
|
+
else i= p->p[ i ];
|
529
|
+
i=((i>127)?0:1);
|
530
|
+
p->p[a]=(p->p[a] & (~1<<b)) | (i<<b);
|
531
|
+
}
|
532
|
+
f1=fopen(nam,"wb");if(!f1)F0("open"); // open-error
|
533
|
+
fprintf(f1,"P4\n%d %d\n",p->x,p->y);
|
534
|
+
if(p->y!=(int)fwrite(p->p,dx>>3,p->y,f1))F0("write"); // write all lines
|
535
|
+
fclose(f1);
|
536
|
+
return 0;
|
537
|
+
}
|
538
|
+
// ------------------------------------------------------------------------
|