/* jbig2topdf: Assemble a bunch of JBIG2 files into a PDF file. Syntax: jbig2topdf [-t title] [-a author] hresolution vresolution symbols files A bunch of JBIG2 files together with a symbol file is taken as input 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 #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); } long get_size(FILE *stream) { if (fseek(stream, 0, SEEK_END) != 0) { perror("fseek"); exit(1); } long size = ftell(stream); if (size == -1) { perror("ftell"); exit(1); } if (fseek(stream, 0, SEEK_SET) != 0) { perror("fseek"); exit(1); } return size; } void put_char(int c) { if (putchar(c) == EOF) { perror("putchar"); exit(1); } offset++; } void dump(FILE *stream, long size) { int c; while ((c = fgetc(stream)) != EOF) { put_char(c); 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 objn, obj_size; int *obj; void pobj(void) { objn++; if (objn == obj_size) { fprintf(stderr, "Increase obj_size\n"); exit(1); } obj[objn] = offset; print("%d 0 obj ", objn); } void put_16(wchar_t c) { put_char(c >> 8); put_char(c & 0xFF); } void put_string(const char *s) { put_char(254); put_char(255); mbtowc(NULL, NULL, 0); while (*s != 0) { wchar_t c; int n = mbtowc(&c, s, MB_CUR_MAX); if (n <= 0) { fprintf(stderr, "mbtowc error\n"); exit(1); } s += n; if (c < 0xD800) put_16(c); else if (c >= 0x10000 && c < 0x110000) { c -= 0x10000; put_16(0xD800 + (c >> 10)); put_16(0xDC00 + (c & 0x3FF)); } else { fprintf(stderr, "Invalid character\n"); exit(1); } } } int main(int argc, char *argv[]) { const char *title = NULL, *author = NULL; int cur; for (cur = 1; cur + 1 < argc; cur += 2) if (strcmp(argv[cur], "-t") == 0) title = argv[cur + 1]; else if (strcmp(argv[cur], "-a") == 0) author = argv[cur + 1]; else break; int hres, vres; if (cur + 3 > argc || sscanf(argv[cur], "%d", &hres) != 1 || sscanf(argv[cur + 1], "%d", &vres) != 1) { fprintf(stderr, "Usage: jbig2topdf [-t title] [-a author] hresolution vresolution symbols files\n"); exit(1); } cur += 2; obj_size = 3 * (argc - cur) + 2; obj = malloc(sizeof(int) * obj_size); if (obj == NULL) { perror("malloc"); exit(1); } objn = 0; print("%%PDF-1.4\n%%\200\200\200\200\n"); pobj(); print("<< /Type /Catalog /Pages 2 0 R >> endobj\n"); pobj(); print("<< /Type /Pages /Count %d /Kids [", argc - cur - 1); for (int k = 0; k < argc - cur - 1; k++) print(" %d 0 R", 3 * k + 4); print(" ] >> endobj\n"); FILE *stream = fopen(argv[cur], "rb"); if (stream == 0) { perror("fopen"); exit(1); } long size = get_size(stream); pobj(); print("<< /Length %d >> stream\n", size); dump(stream, size); cur++; for (; cur < argc; cur++) { FILE *stream = fopen(argv[cur], "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; long size = get_size(stream); pobj(); print("<< /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", objn + 2, ww, hh, objn + 1); pobj(); char s[64]; sprintf(s, "%.2f 0 0 %.2f 0 0 cm /image Do", ww, hh); print("<< /Length %d >> stream\n%s\nendstream endobj\n", strlen(s), s); pobj(); print("<< /Length %d /Filter /JBIG2Decode /DecodeParms << /JBIG2Globals 3 0 R >>" " /Subtype /Image /Width %d /Height %d " "/ColorSpace /DeviceGray /BitsPerComponent 1 >> stream\n", size, w, h); dump(stream, size); } if (title != NULL || author != NULL) { setlocale(LC_CTYPE, ""); pobj(); print("<< "); if (title != NULL) { print("/Title ("); put_string(title); print(") "); } if (author != NULL) { print("/Author ("); put_string(author); print(") "); } print(">> endobj\n"); } int xref = offset; print("xref\n0 %d\n0000000000 65535 f \n", objn + 1); for (int k = 1; k <= objn; k++) print("%010d 00000 n \n", obj[k]); print("trailer << /Size %d /Root 1 0 R ", objn + 1); if (title != NULL || author != NULL) print("/Info %d 0 R ", objn); print(">>\nstartxref\n%d\n%%%%EOF\n", xref); return 0; }