/* jbig2topdf: Assemble a bunch of JBIG2 files into a PDF file. Syntax: jbig2topdf hresolution vresolution symbols file-names A bunch of JBIG2 files is taken as input together with a symbol file and a PDF-1.4 file is printed to the standard output. Compile with cc jbig2topdf.c -o jbig2topdf For gcc you might need to use an addtional option -std=c99. Written and copyrighted by Dmitri Pavlov in 2010. Distributed under the terms of GNU General Public License version 3. Feedback welcome via SMTP: host math.berkeley.edu, user pavlov. */ #include #include #include #include int offset = 0; void print( const char *format, ... ) { va_list ap; va_start(ap, format); int n = vprintf(format, ap); if (n < 0) { perror("vprintf"); exit(1); } offset += n; va_end(ap); } int get_size( FILE *stream ) { if (fseek(stream, 0, SEEK_END) != 0) { perror("fseek"); exit(1); } int size = ftell(stream); if (size == -1) { perror("ftell"); exit(1); } if (fseek(stream, 0, SEEK_SET) != 0) { perror("fseek"); exit(1); } return size; } void dump( FILE *stream, int size ) { int c; while ((c = fgetc(stream)) != EOF) { if (putchar(c) == EOF) { perror("putchar"); exit(1); } offset++; if (size == 0) { fprintf(stderr, "File size mismatch\n"); exit(1); } size--; } if (ferror(stream) != 0) { perror("fgetc"); exit(1); } if (size != 0) { fprintf(stderr, "File size mismatch\n"); exit(1); } if (fclose(stream) != 0) { perror("fclose"); exit(1); } print("\nendstream endobj\n"); } int get_int( FILE *stream ) { int n = 0, c; for (int l = 0; l < 4; l++) if ((c = fgetc(stream)) == EOF) { fprintf(stderr, "Error reading 4-byte integer\n"); exit(1); } else n = (n << 8) + c; return n; } int main( int argc, char *argv[] ) { int hres, vres; if (argc < 4 || sscanf(argv[1], "%d", &hres) != 1 || sscanf(argv[2], "%d", &vres) != 1) { fprintf(stderr, "Usage: jbig2topdf hresolution vresolution symbols file-names\n"); exit(1); } int *obj = malloc(sizeof(int) * 3 * argc - 8); if (obj == 0) { perror("malloc"); exit(1); } print("%%PDF-1.4\n%%\200\200\200\200\n"); obj[1] = offset; print("1 0 obj << /Type /Catalog /Pages 2 0 R >> endobj\n"); obj[2] = offset; print("2 0 obj << /Type /Pages /Count %d /Kids [", argc - 4); for (int k = 4; k < argc; k++) print(" %d 0 R", 3 * k - 8); print(" ] >> endobj\n"); FILE *stream = fopen(argv[3], "rb"); if (stream == 0) { perror("fopen"); exit(1); } int size = get_size(stream); obj[3] = offset; print("3 0 obj << /Length %d >> stream\n", size); dump(stream, size); for (int k = 4; k < argc; k++) { FILE *stream = fopen(argv[k], "rb"); if (stream == 0) { perror("fopen"); exit(1); } if (fseek(stream, 11, SEEK_SET) != 0) { perror("fseek"); exit(1); } int w = get_int(stream), h = get_int(stream); double ww = 72.0 * w / hres, hh = 72.0 * h / vres; int size = get_size(stream); obj[3 * k - 8] = offset; print("%d 0 obj << /Type /Page /Parent 2 0 R /Resources << /ProcSet [ /PDF /ImageB ] " "/XObject << /image %d 0 R >> >> /MediaBox [ 0 0 %.2f %.2f ] " "/Contents [ %d 0 R ] >> endobj\n", 3 * k - 8, 3 * k - 6, ww, hh, 3 * k - 7); obj[3 * k - 7] = offset; char s[64]; sprintf(s, "%.2f 0 0 %.2f 0 0 cm /image Do", ww, hh); print("%d 0 obj << /Length %d >> stream\n%s\nendstream endobj\n", 3 * k - 7, strlen(s), s); obj[3 * k - 6] = offset; print("%d 0 obj << /Length %d /Filter /JBIG2Decode /DecodeParms << /JBIG2Globals 3 0 R >>" " /Subtype /Image /Width %d /Height %d " "/ColorSpace /DeviceGray /BitsPerComponent 1 >> stream\n", 3 * k - 6, size, w, h); dump(stream, size); } int xref = offset; print("xref\n0 %d\n0000000000 65535 f \n", 3 * argc - 8); for (int k = 1; k < 3 * argc - 8; k++) print("%010d 00000 n \n", obj[k]); print("trailer << /Size %d /Root 1 0 R >>\nstartxref\n%d\n%%%%EOF\n", 3 * argc - 8, xref); return 0; }