/* jpegtopdf: Assemble a bunch of JPEG files into a PDF file. Syntax: jpegtopdf file-names A bunch of JPEG files is taken as input and a PDF-1.1 file is printed to the standard output. Requires jpeglib. Compile with cc -ljpeg jpegtopdf.c -o jpegtopdf For gcc you might need to use an addtional option -std=c99. Written and copyrighted by Dmitri Pavlov in 2009. 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); } int main(int argc, char *argv[]) { int *obj = malloc(sizeof(int) * 3 * argc); if (obj == 0) { perror("malloc"); exit(1); } print("%%PDF-1.1\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 - 1); for (int k = 1; k < argc; k++) print(" %d 0 R", 3 * k); print(" ] >> endobj\n"); for (int k = 1; k < argc; k++) { FILE *stream = fopen(argv[k], "rb"); if (stream == 0) { perror("fopen"); exit(1); } struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); jpeg_stdio_src(&cinfo, stream); jpeg_read_header(&cinfo, TRUE); if (cinfo.density_unit == 0) { fprintf(stderr, "%s: unknown resolution, assuming 300\n", argv[k]); cinfo.density_unit = 1; cinfo.X_density = cinfo.Y_density = 300; } const char *cspace; if (cinfo.jpeg_color_space == JCS_RGB) cspace = "DeviceRGB"; else if (cinfo.jpeg_color_space == JCS_GRAYSCALE) cspace = "DeviceGray"; else if (cinfo.jpeg_color_space == JCS_YCbCr) cspace = "DeviceRGB"; else { fprintf(stderr, "unknown color space %d\n", cinfo.jpeg_color_space); return 1; } int w = cinfo.image_width, h = cinfo.image_height; double sf = cinfo.density_unit == 1 ? 72 : 72 / 2.54; double ww = w * sf / cinfo.X_density, hh = h * sf / cinfo.Y_density; jpeg_destroy_decompress(&cinfo); 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); } obj[3 * k] = 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, 3 * k + 2, ww, hh, 3 * k + 1); obj[3 * k + 1] = 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 + 1, strlen(s), s); obj[3 * k + 2] = offset; print("%d 0 obj << /Length %d /Filter /DCTDecode /Subtype /Image /Width %d /Height %d " "/ColorSpace /%s /BitsPerComponent 8 >> stream\n", 3 * k + 2, size, w, h, cspace); int c; while ((c = fgetc(stream)) != EOF) { if (putchar(c) == EOF) { perror("putchar"); exit(1); } offset++; } if (ferror(stream) != 0) { perror("fgetc"); exit(1); } if (fclose(stream) != 0) { perror("fclose"); exit(1); } print("\nendstream endobj\n"); } int xref = offset; print("xref\n0 %d\n0000000000 65535 f \n", 3 * argc); for (int k = 1; k < 3 * argc; k++) print("%010d 00000 n \n", obj[k]); print("trailer << /Size %d /Root 1 0 R >>\nstartxref\n%d\n%%%%EOF\n", 3 * argc, xref); return 0; }