| 1 | #include "mupdf/fitz.h" |
| 2 | #include "mupdf/pdf.h" |
| 3 | |
| 4 | typedef struct pdf_output_processor_s pdf_output_processor; |
| 5 | |
| 6 | struct pdf_output_processor_s |
| 7 | { |
| 8 | pdf_processor super; |
| 9 | fz_output *out; |
| 10 | int ahxencode; |
| 11 | int extgstate; |
| 12 | }; |
| 13 | |
| 14 | /* general graphics state */ |
| 15 | |
| 16 | static void |
| 17 | pdf_out_w(fz_context *ctx, pdf_processor *proc, float linewidth) |
| 18 | { |
| 19 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 20 | if (!((pdf_output_processor*)proc)->extgstate) |
| 21 | fz_write_printf(ctx, out, "%g w\n" , linewidth); |
| 22 | } |
| 23 | |
| 24 | static void |
| 25 | pdf_out_j(fz_context *ctx, pdf_processor *proc, int linejoin) |
| 26 | { |
| 27 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 28 | if (!((pdf_output_processor*)proc)->extgstate) |
| 29 | fz_write_printf(ctx, out, "%d j\n" , linejoin); |
| 30 | } |
| 31 | |
| 32 | static void |
| 33 | pdf_out_J(fz_context *ctx, pdf_processor *proc, int linecap) |
| 34 | { |
| 35 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 36 | if (!((pdf_output_processor*)proc)->extgstate) |
| 37 | fz_write_printf(ctx, out, "%d J\n" , linecap); |
| 38 | } |
| 39 | |
| 40 | static void |
| 41 | pdf_out_M(fz_context *ctx, pdf_processor *proc, float a) |
| 42 | { |
| 43 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 44 | if (!((pdf_output_processor*)proc)->extgstate) |
| 45 | fz_write_printf(ctx, out, "%g M\n" , a); |
| 46 | } |
| 47 | |
| 48 | static void |
| 49 | pdf_out_d(fz_context *ctx, pdf_processor *proc, pdf_obj *array, float phase) |
| 50 | { |
| 51 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 52 | int ahx = ((pdf_output_processor*)proc)->ahxencode; |
| 53 | if (!((pdf_output_processor*)proc)->extgstate) |
| 54 | { |
| 55 | pdf_print_obj(ctx, out, array, 1, ahx); |
| 56 | fz_write_printf(ctx, out, " %g d\n" , phase); |
| 57 | } |
| 58 | } |
| 59 | |
| 60 | static void |
| 61 | pdf_out_ri(fz_context *ctx, pdf_processor *proc, const char *intent) |
| 62 | { |
| 63 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 64 | if (!((pdf_output_processor*)proc)->extgstate) |
| 65 | fz_write_printf(ctx, out, "%n ri\n" , intent); |
| 66 | } |
| 67 | |
| 68 | static void |
| 69 | pdf_out_gs_OP(fz_context *ctx, pdf_processor *proc, int b) |
| 70 | { |
| 71 | } |
| 72 | |
| 73 | static void |
| 74 | pdf_out_gs_op(fz_context *ctx, pdf_processor *proc, int b) |
| 75 | { |
| 76 | } |
| 77 | |
| 78 | static void |
| 79 | pdf_out_gs_OPM(fz_context *ctx, pdf_processor *proc, int i) |
| 80 | { |
| 81 | } |
| 82 | |
| 83 | static void |
| 84 | pdf_out_gs_UseBlackPtComp(fz_context *ctx, pdf_processor *proc, pdf_obj *name) |
| 85 | { |
| 86 | } |
| 87 | |
| 88 | static void |
| 89 | pdf_out_i(fz_context *ctx, pdf_processor *proc, float flatness) |
| 90 | { |
| 91 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 92 | if (!((pdf_output_processor*)proc)->extgstate) |
| 93 | fz_write_printf(ctx, out, "%g i\n" , flatness); |
| 94 | } |
| 95 | |
| 96 | static void |
| 97 | pdf_out_gs_begin(fz_context *ctx, pdf_processor *proc, const char *name, pdf_obj *extgstate) |
| 98 | { |
| 99 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 100 | ((pdf_output_processor*)proc)->extgstate = 1; |
| 101 | fz_write_printf(ctx, out, "%n gs\n" , name); |
| 102 | } |
| 103 | |
| 104 | static void |
| 105 | pdf_out_gs_end(fz_context *ctx, pdf_processor *proc) |
| 106 | { |
| 107 | ((pdf_output_processor*)proc)->extgstate = 0; |
| 108 | } |
| 109 | |
| 110 | /* special graphics state */ |
| 111 | |
| 112 | static void |
| 113 | pdf_out_q(fz_context *ctx, pdf_processor *proc) |
| 114 | { |
| 115 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 116 | fz_write_string(ctx, out, "q\n" ); |
| 117 | } |
| 118 | |
| 119 | static void |
| 120 | pdf_out_Q(fz_context *ctx, pdf_processor *proc) |
| 121 | { |
| 122 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 123 | fz_write_string(ctx, out, "Q\n" ); |
| 124 | } |
| 125 | |
| 126 | static void |
| 127 | pdf_out_cm(fz_context *ctx, pdf_processor *proc, float a, float b, float c, float d, float e, float f) |
| 128 | { |
| 129 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 130 | fz_write_printf(ctx, out, "%g %g %g %g %g %g cm\n" , a, b, c, d, e, f); |
| 131 | } |
| 132 | |
| 133 | /* path construction */ |
| 134 | |
| 135 | static void |
| 136 | pdf_out_m(fz_context *ctx, pdf_processor *proc, float x, float y) |
| 137 | { |
| 138 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 139 | fz_write_printf(ctx, out, "%g %g m\n" , x, y); |
| 140 | } |
| 141 | |
| 142 | static void |
| 143 | pdf_out_l(fz_context *ctx, pdf_processor *proc, float x, float y) |
| 144 | { |
| 145 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 146 | fz_write_printf(ctx, out, "%g %g l\n" , x, y); |
| 147 | } |
| 148 | |
| 149 | static void |
| 150 | pdf_out_c(fz_context *ctx, pdf_processor *proc, float x1, float y1, float x2, float y2, float x3, float y3) |
| 151 | { |
| 152 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 153 | fz_write_printf(ctx, out, "%g %g %g %g %g %g c\n" , x1, y1, x2, y2, x3, y3); |
| 154 | } |
| 155 | |
| 156 | static void |
| 157 | pdf_out_v(fz_context *ctx, pdf_processor *proc, float x2, float y2, float x3, float y3) |
| 158 | { |
| 159 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 160 | fz_write_printf(ctx, out, "%g %g %g %g v\n" , x2, y2, x3, y3); |
| 161 | } |
| 162 | |
| 163 | static void |
| 164 | pdf_out_y(fz_context *ctx, pdf_processor *proc, float x1, float y1, float x3, float y3) |
| 165 | { |
| 166 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 167 | fz_write_printf(ctx, out, "%g %g %g %g y\n" , x1, y1, x3, y3); |
| 168 | } |
| 169 | |
| 170 | static void |
| 171 | pdf_out_h(fz_context *ctx, pdf_processor *proc) |
| 172 | { |
| 173 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 174 | fz_write_string(ctx, out, "h\n" ); |
| 175 | } |
| 176 | |
| 177 | static void |
| 178 | pdf_out_re(fz_context *ctx, pdf_processor *proc, float x, float y, float w, float h) |
| 179 | { |
| 180 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 181 | fz_write_printf(ctx, out, "%g %g %g %g re\n" , x, y, w, h); |
| 182 | } |
| 183 | |
| 184 | /* path painting */ |
| 185 | |
| 186 | static void |
| 187 | pdf_out_S(fz_context *ctx, pdf_processor *proc) |
| 188 | { |
| 189 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 190 | fz_write_string(ctx, out, "S\n" ); |
| 191 | } |
| 192 | |
| 193 | static void |
| 194 | pdf_out_s(fz_context *ctx, pdf_processor *proc) |
| 195 | { |
| 196 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 197 | fz_write_string(ctx, out, "s\n" ); |
| 198 | } |
| 199 | |
| 200 | static void |
| 201 | pdf_out_F(fz_context *ctx, pdf_processor *proc) |
| 202 | { |
| 203 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 204 | fz_write_string(ctx, out, "F\n" ); |
| 205 | } |
| 206 | |
| 207 | static void |
| 208 | pdf_out_f(fz_context *ctx, pdf_processor *proc) |
| 209 | { |
| 210 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 211 | fz_write_string(ctx, out, "f\n" ); |
| 212 | } |
| 213 | |
| 214 | static void |
| 215 | pdf_out_fstar(fz_context *ctx, pdf_processor *proc) |
| 216 | { |
| 217 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 218 | fz_write_string(ctx, out, "f*\n" ); |
| 219 | } |
| 220 | |
| 221 | static void |
| 222 | pdf_out_B(fz_context *ctx, pdf_processor *proc) |
| 223 | { |
| 224 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 225 | fz_write_string(ctx, out, "B\n" ); |
| 226 | } |
| 227 | |
| 228 | static void |
| 229 | pdf_out_Bstar(fz_context *ctx, pdf_processor *proc) |
| 230 | { |
| 231 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 232 | fz_write_string(ctx, out, "B*\n" ); |
| 233 | } |
| 234 | |
| 235 | static void |
| 236 | pdf_out_b(fz_context *ctx, pdf_processor *proc) |
| 237 | { |
| 238 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 239 | fz_write_string(ctx, out, "b\n" ); |
| 240 | } |
| 241 | |
| 242 | static void |
| 243 | pdf_out_bstar(fz_context *ctx, pdf_processor *proc) |
| 244 | { |
| 245 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 246 | fz_write_string(ctx, out, "b*\n" ); |
| 247 | } |
| 248 | |
| 249 | static void |
| 250 | pdf_out_n(fz_context *ctx, pdf_processor *proc) |
| 251 | { |
| 252 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 253 | fz_write_string(ctx, out, "n\n" ); |
| 254 | } |
| 255 | |
| 256 | /* clipping paths */ |
| 257 | |
| 258 | static void |
| 259 | pdf_out_W(fz_context *ctx, pdf_processor *proc) |
| 260 | { |
| 261 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 262 | fz_write_string(ctx, out, "W\n" ); |
| 263 | } |
| 264 | |
| 265 | static void |
| 266 | pdf_out_Wstar(fz_context *ctx, pdf_processor *proc) |
| 267 | { |
| 268 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 269 | fz_write_string(ctx, out, "W*\n" ); |
| 270 | } |
| 271 | |
| 272 | /* text objects */ |
| 273 | |
| 274 | static void |
| 275 | pdf_out_BT(fz_context *ctx, pdf_processor *proc) |
| 276 | { |
| 277 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 278 | fz_write_string(ctx, out, "BT\n" ); |
| 279 | } |
| 280 | |
| 281 | static void |
| 282 | pdf_out_ET(fz_context *ctx, pdf_processor *proc) |
| 283 | { |
| 284 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 285 | fz_write_string(ctx, out, "ET\n" ); |
| 286 | } |
| 287 | |
| 288 | /* text state */ |
| 289 | |
| 290 | static void |
| 291 | pdf_out_Tc(fz_context *ctx, pdf_processor *proc, float charspace) |
| 292 | { |
| 293 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 294 | fz_write_printf(ctx, out, "%g Tc\n" , charspace); |
| 295 | } |
| 296 | |
| 297 | static void |
| 298 | pdf_out_Tw(fz_context *ctx, pdf_processor *proc, float wordspace) |
| 299 | { |
| 300 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 301 | fz_write_printf(ctx, out, "%g Tw\n" , wordspace); |
| 302 | } |
| 303 | |
| 304 | static void |
| 305 | pdf_out_Tz(fz_context *ctx, pdf_processor *proc, float scale) |
| 306 | { |
| 307 | /* scale is exactly as read from the file. */ |
| 308 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 309 | fz_write_printf(ctx, out, "%g Tz\n" , scale); |
| 310 | } |
| 311 | |
| 312 | static void |
| 313 | pdf_out_TL(fz_context *ctx, pdf_processor *proc, float leading) |
| 314 | { |
| 315 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 316 | fz_write_printf(ctx, out, "%g TL\n" , leading); |
| 317 | } |
| 318 | |
| 319 | static void |
| 320 | pdf_out_Tf(fz_context *ctx, pdf_processor *proc, const char *name, pdf_font_desc *font, float size) |
| 321 | { |
| 322 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 323 | if (!((pdf_output_processor*)proc)->extgstate) |
| 324 | { |
| 325 | fz_write_printf(ctx, out, "%n %g Tf\n" , name, size); |
| 326 | } |
| 327 | } |
| 328 | |
| 329 | static void |
| 330 | pdf_out_Tr(fz_context *ctx, pdf_processor *proc, int render) |
| 331 | { |
| 332 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 333 | fz_write_printf(ctx, out, "%d Tr\n" , render); |
| 334 | } |
| 335 | |
| 336 | static void |
| 337 | pdf_out_Ts(fz_context *ctx, pdf_processor *proc, float rise) |
| 338 | { |
| 339 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 340 | fz_write_printf(ctx, out, "%g Ts\n" , rise); |
| 341 | } |
| 342 | |
| 343 | /* text positioning */ |
| 344 | |
| 345 | static void |
| 346 | pdf_out_Td(fz_context *ctx, pdf_processor *proc, float tx, float ty) |
| 347 | { |
| 348 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 349 | fz_write_printf(ctx, out, "%g %g Td\n" , tx, ty); |
| 350 | } |
| 351 | |
| 352 | static void |
| 353 | pdf_out_TD(fz_context *ctx, pdf_processor *proc, float tx, float ty) |
| 354 | { |
| 355 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 356 | fz_write_printf(ctx, out, "%g %g TD\n" , tx, ty); |
| 357 | } |
| 358 | |
| 359 | static void |
| 360 | pdf_out_Tm(fz_context *ctx, pdf_processor *proc, float a, float b, float c, float d, float e, float f) |
| 361 | { |
| 362 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 363 | fz_write_printf(ctx, out, "%g %g %g %g %g %g Tm\n" , a, b, c, d, e, f); |
| 364 | } |
| 365 | |
| 366 | static void |
| 367 | pdf_out_Tstar(fz_context *ctx, pdf_processor *proc) |
| 368 | { |
| 369 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 370 | fz_write_string(ctx, out, "T*\n" ); |
| 371 | } |
| 372 | |
| 373 | /* text showing */ |
| 374 | |
| 375 | static void |
| 376 | fz_write_pdf_string(fz_context *ctx, fz_output *out, const unsigned char *str, int len) |
| 377 | { |
| 378 | int i; |
| 379 | |
| 380 | for (i = 0; i < len; ++i) |
| 381 | if (str[i] < 32 || str[i] >= 127) |
| 382 | break; |
| 383 | |
| 384 | if (i < len) |
| 385 | { |
| 386 | fz_write_byte(ctx, out, '<'); |
| 387 | for (i = 0; i < len; ++i) |
| 388 | { |
| 389 | unsigned char c = str[i]; |
| 390 | fz_write_byte(ctx, out, "0123456789abcdef" [(c>>4)&15]); |
| 391 | fz_write_byte(ctx, out, "0123456789abcdef" [(c)&15]); |
| 392 | } |
| 393 | fz_write_byte(ctx, out, '>'); |
| 394 | } |
| 395 | else |
| 396 | { |
| 397 | fz_write_byte(ctx, out, '('); |
| 398 | for (i = 0; i < len; ++i) |
| 399 | { |
| 400 | unsigned char c = str[i]; |
| 401 | if (c == '(' || c == ')' || c == '\\') |
| 402 | fz_write_byte(ctx, out, '\\'); |
| 403 | fz_write_byte(ctx, out, c); |
| 404 | } |
| 405 | fz_write_byte(ctx, out, ')'); |
| 406 | } |
| 407 | } |
| 408 | |
| 409 | static void |
| 410 | pdf_out_TJ(fz_context *ctx, pdf_processor *proc, pdf_obj *array) |
| 411 | { |
| 412 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 413 | int ahx = ((pdf_output_processor*)proc)->ahxencode; |
| 414 | pdf_print_obj(ctx, out, array, 1, ahx); |
| 415 | fz_write_string(ctx, out, " TJ\n" ); |
| 416 | } |
| 417 | |
| 418 | static void |
| 419 | pdf_out_Tj(fz_context *ctx, pdf_processor *proc, char *str, int len) |
| 420 | { |
| 421 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 422 | fz_write_pdf_string(ctx, out, (const unsigned char *)str, len); |
| 423 | fz_write_string(ctx, out, " Tj\n" ); |
| 424 | } |
| 425 | |
| 426 | static void |
| 427 | pdf_out_squote(fz_context *ctx, pdf_processor *proc, char *str, int len) |
| 428 | { |
| 429 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 430 | fz_write_pdf_string(ctx, out, (const unsigned char *)str, len); |
| 431 | fz_write_string(ctx, out, " '\n" ); |
| 432 | } |
| 433 | |
| 434 | static void |
| 435 | pdf_out_dquote(fz_context *ctx, pdf_processor *proc, float aw, float ac, char *str, int len) |
| 436 | { |
| 437 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 438 | fz_write_printf(ctx, out, "%g %g " , aw, ac); |
| 439 | fz_write_pdf_string(ctx, out, (const unsigned char *)str, len); |
| 440 | fz_write_string(ctx, out, " \"\n" ); |
| 441 | } |
| 442 | |
| 443 | /* type 3 fonts */ |
| 444 | |
| 445 | static void |
| 446 | pdf_out_d0(fz_context *ctx, pdf_processor *proc, float wx, float wy) |
| 447 | { |
| 448 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 449 | fz_write_printf(ctx, out, "%g %g d0\n" , wx, wy); |
| 450 | } |
| 451 | |
| 452 | static void |
| 453 | pdf_out_d1(fz_context *ctx, pdf_processor *proc, float wx, float wy, float llx, float lly, float urx, float ury) |
| 454 | { |
| 455 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 456 | fz_write_printf(ctx, out, "%g %g %g %g %g %g d1\n" , wx, wy, llx, lly, urx, ury); |
| 457 | } |
| 458 | |
| 459 | /* color */ |
| 460 | |
| 461 | static void |
| 462 | pdf_out_CS(fz_context *ctx, pdf_processor *proc, const char *name, fz_colorspace *cs) |
| 463 | { |
| 464 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 465 | fz_write_printf(ctx, out, "%n CS\n" , name); |
| 466 | } |
| 467 | |
| 468 | static void |
| 469 | pdf_out_cs(fz_context *ctx, pdf_processor *proc, const char *name, fz_colorspace *cs) |
| 470 | { |
| 471 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 472 | fz_write_printf(ctx, out, "%n cs\n" , name); |
| 473 | } |
| 474 | |
| 475 | static void |
| 476 | pdf_out_SC_pattern(fz_context *ctx, pdf_processor *proc, const char *name, pdf_pattern *pat, int n, float *color) |
| 477 | { |
| 478 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 479 | int i; |
| 480 | for (i = 0; i < n; ++i) |
| 481 | fz_write_printf(ctx, out, "%g " , color[i]); |
| 482 | fz_write_printf(ctx, out, "%n SCN\n" , name); |
| 483 | } |
| 484 | |
| 485 | static void |
| 486 | pdf_out_sc_pattern(fz_context *ctx, pdf_processor *proc, const char *name, pdf_pattern *pat, int n, float *color) |
| 487 | { |
| 488 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 489 | int i; |
| 490 | for (i = 0; i < n; ++i) |
| 491 | fz_write_printf(ctx, out, "%g " , color[i]); |
| 492 | fz_write_printf(ctx, out, "%n scn\n" , name); |
| 493 | } |
| 494 | |
| 495 | static void |
| 496 | pdf_out_SC_shade(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade) |
| 497 | { |
| 498 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 499 | fz_write_printf(ctx, out, "%n SCN\n" , name); |
| 500 | } |
| 501 | |
| 502 | static void |
| 503 | pdf_out_sc_shade(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade) |
| 504 | { |
| 505 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 506 | fz_write_printf(ctx, out, "%n scn\n" , name); |
| 507 | } |
| 508 | |
| 509 | static void |
| 510 | pdf_out_SC_color(fz_context *ctx, pdf_processor *proc, int n, float *color) |
| 511 | { |
| 512 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 513 | int i; |
| 514 | for (i = 0; i < n; ++i) |
| 515 | fz_write_printf(ctx, out, "%g " , color[i]); |
| 516 | fz_write_string(ctx, out, "SCN\n" ); |
| 517 | } |
| 518 | |
| 519 | static void |
| 520 | pdf_out_sc_color(fz_context *ctx, pdf_processor *proc, int n, float *color) |
| 521 | { |
| 522 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 523 | int i; |
| 524 | for (i = 0; i < n; ++i) |
| 525 | fz_write_printf(ctx, out, "%g " , color[i]); |
| 526 | fz_write_string(ctx, out, "scn\n" ); |
| 527 | } |
| 528 | |
| 529 | static void |
| 530 | pdf_out_G(fz_context *ctx, pdf_processor *proc, float g) |
| 531 | { |
| 532 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 533 | fz_write_printf(ctx, out, "%g G\n" , g); |
| 534 | } |
| 535 | |
| 536 | static void |
| 537 | pdf_out_g(fz_context *ctx, pdf_processor *proc, float g) |
| 538 | { |
| 539 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 540 | fz_write_printf(ctx, out, "%g g\n" , g); |
| 541 | } |
| 542 | |
| 543 | static void |
| 544 | pdf_out_RG(fz_context *ctx, pdf_processor *proc, float r, float g, float b) |
| 545 | { |
| 546 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 547 | fz_write_printf(ctx, out, "%g %g %g RG\n" , r, g, b); |
| 548 | } |
| 549 | |
| 550 | static void |
| 551 | pdf_out_rg(fz_context *ctx, pdf_processor *proc, float r, float g, float b) |
| 552 | { |
| 553 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 554 | fz_write_printf(ctx, out, "%g %g %g rg\n" , r, g, b); |
| 555 | } |
| 556 | |
| 557 | static void |
| 558 | pdf_out_K(fz_context *ctx, pdf_processor *proc, float c, float m, float y, float k) |
| 559 | { |
| 560 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 561 | fz_write_printf(ctx, out, "%g %g %g %g K\n" , c, m, y, k); |
| 562 | } |
| 563 | |
| 564 | static void |
| 565 | pdf_out_k(fz_context *ctx, pdf_processor *proc, float c, float m, float y, float k) |
| 566 | { |
| 567 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 568 | fz_write_printf(ctx, out, "%g %g %g %g k\n" , c, m, y, k); |
| 569 | } |
| 570 | |
| 571 | /* shadings, images, xobjects */ |
| 572 | |
| 573 | static void |
| 574 | pdf_out_BI(fz_context *ctx, pdf_processor *proc, fz_image *img, const char *colorspace) |
| 575 | { |
| 576 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 577 | int ahx = ((pdf_output_processor*)proc)->ahxencode; |
| 578 | fz_compressed_buffer *cbuf; |
| 579 | fz_buffer *buf; |
| 580 | int i; |
| 581 | unsigned char *data; |
| 582 | size_t len; |
| 583 | |
| 584 | if (img == NULL) |
| 585 | return; |
| 586 | cbuf = fz_compressed_image_buffer(ctx, img); |
| 587 | if (cbuf == NULL) |
| 588 | return; |
| 589 | buf = cbuf->buffer; |
| 590 | if (buf == NULL) |
| 591 | return; |
| 592 | |
| 593 | fz_write_string(ctx, out, "BI\n" ); |
| 594 | fz_write_printf(ctx, out, "/W %d\n" , img->w); |
| 595 | fz_write_printf(ctx, out, "/H %d\n" , img->h); |
| 596 | fz_write_printf(ctx, out, "/BPC %d\n" , img->bpc); |
| 597 | if (img->imagemask) |
| 598 | fz_write_string(ctx, out, "/IM true\n" ); |
| 599 | else if (img->colorspace == fz_device_gray(ctx)) |
| 600 | fz_write_string(ctx, out, "/CS/G\n" ); |
| 601 | else if (img->colorspace == fz_device_rgb(ctx)) |
| 602 | fz_write_string(ctx, out, "/CS/RGB\n" ); |
| 603 | else if (img->colorspace == fz_device_cmyk(ctx)) |
| 604 | fz_write_string(ctx, out, "/CS/CMYK\n" ); |
| 605 | else if (colorspace) |
| 606 | fz_write_printf(ctx, out, "/CS%n/n" , colorspace); |
| 607 | else |
| 608 | fz_throw(ctx, FZ_ERROR_GENERIC, "BI operator can only show ImageMask, Gray, RGB, or CMYK images" ); |
| 609 | if (img->interpolate) |
| 610 | fz_write_string(ctx, out, "/I true\n" ); |
| 611 | fz_write_string(ctx, out, "/D[" ); |
| 612 | for (i = 0; i < img->n * 2; ++i) |
| 613 | { |
| 614 | if (i > 0) |
| 615 | fz_write_byte(ctx, out, ' '); |
| 616 | fz_write_printf(ctx, out, "%g" , img->decode[i]); |
| 617 | } |
| 618 | fz_write_string(ctx, out, "]\n" ); |
| 619 | |
| 620 | switch (cbuf->params.type) |
| 621 | { |
| 622 | default: |
| 623 | fz_throw(ctx, FZ_ERROR_GENERIC, "unknown compressed buffer type" ); |
| 624 | break; |
| 625 | |
| 626 | case FZ_IMAGE_JPEG: |
| 627 | fz_write_string(ctx, out, ahx ? "/F[/AHx/DCT]\n" : "/F/DCT\n" ); |
| 628 | if (cbuf->params.u.jpeg.color_transform != -1) |
| 629 | fz_write_printf(ctx, out, "/DP<</ColorTransform %d>>\n" , |
| 630 | cbuf->params.u.jpeg.color_transform); |
| 631 | break; |
| 632 | |
| 633 | case FZ_IMAGE_FAX: |
| 634 | fz_write_string(ctx, out, ahx ? "/F[/AHx/CCF]\n/DP[null<<\n" : "/F/CCF\n/DP<<\n" ); |
| 635 | fz_write_printf(ctx, out, "/K %d\n" , cbuf->params.u.fax.k); |
| 636 | if (cbuf->params.u.fax.columns != 1728) |
| 637 | fz_write_printf(ctx, out, "/Columns %d\n" , cbuf->params.u.fax.columns); |
| 638 | if (cbuf->params.u.fax.rows > 0) |
| 639 | fz_write_printf(ctx, out, "/Rows %d\n" , cbuf->params.u.fax.rows); |
| 640 | if (cbuf->params.u.fax.end_of_line) |
| 641 | fz_write_string(ctx, out, "/EndOfLine true\n" ); |
| 642 | if (cbuf->params.u.fax.encoded_byte_align) |
| 643 | fz_write_string(ctx, out, "/EncodedByteAlign true\n" ); |
| 644 | if (!cbuf->params.u.fax.end_of_block) |
| 645 | fz_write_string(ctx, out, "/EndOfBlock false\n" ); |
| 646 | if (cbuf->params.u.fax.black_is_1) |
| 647 | fz_write_string(ctx, out, "/BlackIs1 true\n" ); |
| 648 | if (cbuf->params.u.fax.damaged_rows_before_error > 0) |
| 649 | fz_write_printf(ctx, out, "/DamagedRowsBeforeError %d\n" , |
| 650 | cbuf->params.u.fax.damaged_rows_before_error); |
| 651 | fz_write_string(ctx, out, ahx ? ">>]\n" : ">>\n" ); |
| 652 | break; |
| 653 | |
| 654 | case FZ_IMAGE_RAW: |
| 655 | if (ahx) |
| 656 | fz_write_string(ctx, out, "/F/AHx\n" ); |
| 657 | break; |
| 658 | |
| 659 | case FZ_IMAGE_RLD: |
| 660 | fz_write_string(ctx, out, ahx ? "/F[/AHx/RL]\n" : "/F/RL\n" ); |
| 661 | break; |
| 662 | |
| 663 | case FZ_IMAGE_FLATE: |
| 664 | fz_write_string(ctx, out, ahx ? "/F[/AHx/Fl]\n" : "/F/Fl\n" ); |
| 665 | if (cbuf->params.u.flate.predictor > 1) |
| 666 | { |
| 667 | fz_write_string(ctx, out, ahx ? "/DP[null<<\n" : "/DP<<\n" ); |
| 668 | fz_write_printf(ctx, out, "/Predictor %d\n" , cbuf->params.u.flate.predictor); |
| 669 | if (cbuf->params.u.flate.columns != 1) |
| 670 | fz_write_printf(ctx, out, "/Columns %d\n" , cbuf->params.u.flate.columns); |
| 671 | if (cbuf->params.u.flate.colors != 1) |
| 672 | fz_write_printf(ctx, out, "/Colors %d\n" , cbuf->params.u.flate.colors); |
| 673 | if (cbuf->params.u.flate.bpc != 8) |
| 674 | fz_write_printf(ctx, out, "/BitsPerComponent %d\n" , cbuf->params.u.flate.bpc); |
| 675 | fz_write_string(ctx, out, ahx ? ">>]\n" : ">>\n" ); |
| 676 | } |
| 677 | break; |
| 678 | |
| 679 | case FZ_IMAGE_LZW: |
| 680 | fz_write_string(ctx, out, ahx ? "/F[/AHx/LZW]\n" : "/F/LZW\n" ); |
| 681 | if (cbuf->params.u.lzw.predictor > 1) |
| 682 | { |
| 683 | fz_write_string(ctx, out, ahx ? "/DP[<<null\n" : "/DP<<\n" ); |
| 684 | fz_write_printf(ctx, out, "/Predictor %d\n" , cbuf->params.u.lzw.predictor); |
| 685 | if (cbuf->params.u.lzw.columns != 1) |
| 686 | fz_write_printf(ctx, out, "/Columns %d\n" , cbuf->params.u.lzw.columns); |
| 687 | if (cbuf->params.u.lzw.colors != 1) |
| 688 | fz_write_printf(ctx, out, "/Colors %d\n" , cbuf->params.u.lzw.colors); |
| 689 | if (cbuf->params.u.lzw.bpc != 8) |
| 690 | fz_write_printf(ctx, out, "/BitsPerComponent %d\n" , cbuf->params.u.lzw.bpc); |
| 691 | if (cbuf->params.u.lzw.early_change != 1) |
| 692 | fz_write_printf(ctx, out, "/EarlyChange %d\n" , cbuf->params.u.lzw.early_change); |
| 693 | fz_write_string(ctx, out, ahx ? ">>]\n" : ">>\n" ); |
| 694 | } |
| 695 | break; |
| 696 | } |
| 697 | |
| 698 | fz_write_string(ctx, out, "ID\n" ); |
| 699 | len = fz_buffer_storage(ctx, buf, &data); |
| 700 | if (ahx) |
| 701 | { |
| 702 | size_t z; |
| 703 | for (z = 0; z < len; ++z) |
| 704 | { |
| 705 | int c = data[z]; |
| 706 | fz_write_byte(ctx, out, "0123456789abcdef" [(c >> 4) & 0xf]); |
| 707 | fz_write_byte(ctx, out, "0123456789abcdef" [c & 0xf]); |
| 708 | if ((z & 31) == 31) |
| 709 | fz_write_byte(ctx, out, '\n'); |
| 710 | } |
| 711 | fz_write_byte(ctx, out, '>'); |
| 712 | } |
| 713 | else |
| 714 | { |
| 715 | fz_write_data(ctx, out, data, len); |
| 716 | } |
| 717 | fz_write_string(ctx, out, "\nEI\n" ); |
| 718 | } |
| 719 | |
| 720 | static void |
| 721 | pdf_out_sh(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade) |
| 722 | { |
| 723 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 724 | fz_write_printf(ctx, out, "%n sh\n" , name); |
| 725 | } |
| 726 | |
| 727 | static void |
| 728 | pdf_out_Do_image(fz_context *ctx, pdf_processor *proc, const char *name, fz_image *image) |
| 729 | { |
| 730 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 731 | fz_write_printf(ctx, out, "%n Do\n" , name); |
| 732 | } |
| 733 | |
| 734 | static void |
| 735 | pdf_out_Do_form(fz_context *ctx, pdf_processor *proc, const char *name, pdf_obj *xobj, pdf_obj *page_resources) |
| 736 | { |
| 737 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 738 | fz_write_printf(ctx, out, "%n Do\n" , name); |
| 739 | } |
| 740 | |
| 741 | /* marked content */ |
| 742 | |
| 743 | static void |
| 744 | pdf_out_MP(fz_context *ctx, pdf_processor *proc, const char *tag) |
| 745 | { |
| 746 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 747 | fz_write_printf(ctx, out, "%n MP\n" , tag); |
| 748 | } |
| 749 | |
| 750 | static void |
| 751 | pdf_out_DP(fz_context *ctx, pdf_processor *proc, const char *tag, pdf_obj *raw, pdf_obj *cooked) |
| 752 | { |
| 753 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 754 | int ahx = ((pdf_output_processor*)proc)->ahxencode; |
| 755 | fz_write_printf(ctx, out, "%n " , tag); |
| 756 | pdf_print_obj(ctx, out, raw, 1, ahx); |
| 757 | fz_write_string(ctx, out, " DP\n" ); |
| 758 | } |
| 759 | |
| 760 | static void |
| 761 | pdf_out_BMC(fz_context *ctx, pdf_processor *proc, const char *tag) |
| 762 | { |
| 763 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 764 | fz_write_printf(ctx, out, "%n BMC\n" , tag); |
| 765 | } |
| 766 | |
| 767 | static void |
| 768 | pdf_out_BDC(fz_context *ctx, pdf_processor *proc, const char *tag, pdf_obj *raw, pdf_obj *cooked) |
| 769 | { |
| 770 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 771 | int ahx = ((pdf_output_processor*)proc)->ahxencode; |
| 772 | fz_write_printf(ctx, out, "%n " , tag); |
| 773 | pdf_print_obj(ctx, out, raw, 1, ahx); |
| 774 | fz_write_string(ctx, out, " BDC\n" ); |
| 775 | } |
| 776 | |
| 777 | static void |
| 778 | pdf_out_EMC(fz_context *ctx, pdf_processor *proc) |
| 779 | { |
| 780 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 781 | fz_write_string(ctx, out, "EMC\n" ); |
| 782 | } |
| 783 | |
| 784 | /* compatibility */ |
| 785 | |
| 786 | static void |
| 787 | pdf_out_BX(fz_context *ctx, pdf_processor *proc) |
| 788 | { |
| 789 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 790 | fz_write_string(ctx, out, "BX\n" ); |
| 791 | } |
| 792 | |
| 793 | static void |
| 794 | pdf_out_EX(fz_context *ctx, pdf_processor *proc) |
| 795 | { |
| 796 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 797 | fz_write_string(ctx, out, "EX\n" ); |
| 798 | } |
| 799 | |
| 800 | static void |
| 801 | pdf_close_output_processor(fz_context *ctx, pdf_processor *proc) |
| 802 | { |
| 803 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 804 | fz_close_output(ctx, out); |
| 805 | } |
| 806 | |
| 807 | static void |
| 808 | pdf_drop_output_processor(fz_context *ctx, pdf_processor *proc) |
| 809 | { |
| 810 | fz_output *out = ((pdf_output_processor*)proc)->out; |
| 811 | fz_drop_output(ctx, out); |
| 812 | } |
| 813 | |
| 814 | /* |
| 815 | Create an output processor. This |
| 816 | sends the incoming PDF operator stream to an fz_output stream. |
| 817 | |
| 818 | out: The output stream to which operators will be sent. |
| 819 | |
| 820 | ahxencode: If 0, then image streams will be send as binary, |
| 821 | otherwise they will be asciihexencoded. |
| 822 | */ |
| 823 | pdf_processor * |
| 824 | pdf_new_output_processor(fz_context *ctx, fz_output *out, int ahxencode) |
| 825 | { |
| 826 | pdf_output_processor *proc = pdf_new_processor(ctx, sizeof *proc); |
| 827 | { |
| 828 | proc->super.close_processor = pdf_close_output_processor; |
| 829 | proc->super.drop_processor = pdf_drop_output_processor; |
| 830 | |
| 831 | /* general graphics state */ |
| 832 | proc->super.op_w = pdf_out_w; |
| 833 | proc->super.op_j = pdf_out_j; |
| 834 | proc->super.op_J = pdf_out_J; |
| 835 | proc->super.op_M = pdf_out_M; |
| 836 | proc->super.op_d = pdf_out_d; |
| 837 | proc->super.op_ri = pdf_out_ri; |
| 838 | proc->super.op_i = pdf_out_i; |
| 839 | proc->super.op_gs_begin = pdf_out_gs_begin; |
| 840 | proc->super.op_gs_end = pdf_out_gs_end; |
| 841 | |
| 842 | /* transparency graphics state */ |
| 843 | proc->super.op_gs_BM = NULL; |
| 844 | proc->super.op_gs_CA = NULL; |
| 845 | proc->super.op_gs_ca = NULL; |
| 846 | proc->super.op_gs_SMask = NULL; |
| 847 | |
| 848 | /* special graphics state */ |
| 849 | proc->super.op_q = pdf_out_q; |
| 850 | proc->super.op_Q = pdf_out_Q; |
| 851 | proc->super.op_cm = pdf_out_cm; |
| 852 | |
| 853 | /* path construction */ |
| 854 | proc->super.op_m = pdf_out_m; |
| 855 | proc->super.op_l = pdf_out_l; |
| 856 | proc->super.op_c = pdf_out_c; |
| 857 | proc->super.op_v = pdf_out_v; |
| 858 | proc->super.op_y = pdf_out_y; |
| 859 | proc->super.op_h = pdf_out_h; |
| 860 | proc->super.op_re = pdf_out_re; |
| 861 | |
| 862 | /* path painting */ |
| 863 | proc->super.op_S = pdf_out_S; |
| 864 | proc->super.op_s = pdf_out_s; |
| 865 | proc->super.op_F = pdf_out_F; |
| 866 | proc->super.op_f = pdf_out_f; |
| 867 | proc->super.op_fstar = pdf_out_fstar; |
| 868 | proc->super.op_B = pdf_out_B; |
| 869 | proc->super.op_Bstar = pdf_out_Bstar; |
| 870 | proc->super.op_b = pdf_out_b; |
| 871 | proc->super.op_bstar = pdf_out_bstar; |
| 872 | proc->super.op_n = pdf_out_n; |
| 873 | |
| 874 | /* clipping paths */ |
| 875 | proc->super.op_W = pdf_out_W; |
| 876 | proc->super.op_Wstar = pdf_out_Wstar; |
| 877 | |
| 878 | /* text objects */ |
| 879 | proc->super.op_BT = pdf_out_BT; |
| 880 | proc->super.op_ET = pdf_out_ET; |
| 881 | |
| 882 | /* text state */ |
| 883 | proc->super.op_Tc = pdf_out_Tc; |
| 884 | proc->super.op_Tw = pdf_out_Tw; |
| 885 | proc->super.op_Tz = pdf_out_Tz; |
| 886 | proc->super.op_TL = pdf_out_TL; |
| 887 | proc->super.op_Tf = pdf_out_Tf; |
| 888 | proc->super.op_Tr = pdf_out_Tr; |
| 889 | proc->super.op_Ts = pdf_out_Ts; |
| 890 | |
| 891 | /* text positioning */ |
| 892 | proc->super.op_Td = pdf_out_Td; |
| 893 | proc->super.op_TD = pdf_out_TD; |
| 894 | proc->super.op_Tm = pdf_out_Tm; |
| 895 | proc->super.op_Tstar = pdf_out_Tstar; |
| 896 | |
| 897 | /* text showing */ |
| 898 | proc->super.op_TJ = pdf_out_TJ; |
| 899 | proc->super.op_Tj = pdf_out_Tj; |
| 900 | proc->super.op_squote = pdf_out_squote; |
| 901 | proc->super.op_dquote = pdf_out_dquote; |
| 902 | |
| 903 | /* type 3 fonts */ |
| 904 | proc->super.op_d0 = pdf_out_d0; |
| 905 | proc->super.op_d1 = pdf_out_d1; |
| 906 | |
| 907 | /* color */ |
| 908 | proc->super.op_CS = pdf_out_CS; |
| 909 | proc->super.op_cs = pdf_out_cs; |
| 910 | proc->super.op_SC_color = pdf_out_SC_color; |
| 911 | proc->super.op_sc_color = pdf_out_sc_color; |
| 912 | proc->super.op_SC_pattern = pdf_out_SC_pattern; |
| 913 | proc->super.op_sc_pattern = pdf_out_sc_pattern; |
| 914 | proc->super.op_SC_shade = pdf_out_SC_shade; |
| 915 | proc->super.op_sc_shade = pdf_out_sc_shade; |
| 916 | |
| 917 | proc->super.op_G = pdf_out_G; |
| 918 | proc->super.op_g = pdf_out_g; |
| 919 | proc->super.op_RG = pdf_out_RG; |
| 920 | proc->super.op_rg = pdf_out_rg; |
| 921 | proc->super.op_K = pdf_out_K; |
| 922 | proc->super.op_k = pdf_out_k; |
| 923 | |
| 924 | /* shadings, images, xobjects */ |
| 925 | proc->super.op_BI = pdf_out_BI; |
| 926 | proc->super.op_sh = pdf_out_sh; |
| 927 | proc->super.op_Do_image = pdf_out_Do_image; |
| 928 | proc->super.op_Do_form = pdf_out_Do_form; |
| 929 | |
| 930 | /* marked content */ |
| 931 | proc->super.op_MP = pdf_out_MP; |
| 932 | proc->super.op_DP = pdf_out_DP; |
| 933 | proc->super.op_BMC = pdf_out_BMC; |
| 934 | proc->super.op_BDC = pdf_out_BDC; |
| 935 | proc->super.op_EMC = pdf_out_EMC; |
| 936 | |
| 937 | /* compatibility */ |
| 938 | proc->super.op_BX = pdf_out_BX; |
| 939 | proc->super.op_EX = pdf_out_EX; |
| 940 | |
| 941 | /* extgstate */ |
| 942 | proc->super.op_gs_OP = pdf_out_gs_OP; |
| 943 | proc->super.op_gs_op = pdf_out_gs_op; |
| 944 | proc->super.op_gs_OPM = pdf_out_gs_OPM; |
| 945 | proc->super.op_gs_UseBlackPtComp = pdf_out_gs_UseBlackPtComp; |
| 946 | } |
| 947 | |
| 948 | proc->out = out; |
| 949 | proc->ahxencode = ahxencode; |
| 950 | |
| 951 | return (pdf_processor*)proc; |
| 952 | } |
| 953 | |
| 954 | /* |
| 955 | Create a buffer processor. This |
| 956 | collects the incoming PDF operator stream into an fz_buffer. |
| 957 | |
| 958 | buffer: The (possibly empty) buffer to which operators will be |
| 959 | appended. |
| 960 | |
| 961 | ahxencode: If 0, then image streams will be send as binary, |
| 962 | otherwise they will be asciihexencoded. |
| 963 | */ |
| 964 | pdf_processor * |
| 965 | pdf_new_buffer_processor(fz_context *ctx, fz_buffer *buffer, int ahxencode) |
| 966 | { |
| 967 | pdf_processor *proc = NULL; |
| 968 | fz_output *out = fz_new_output_with_buffer(ctx, buffer); |
| 969 | fz_try(ctx) |
| 970 | { |
| 971 | proc = pdf_new_output_processor(ctx, out, ahxencode); |
| 972 | } |
| 973 | fz_catch(ctx) |
| 974 | { |
| 975 | fz_drop_output(ctx, out); |
| 976 | fz_rethrow(ctx); |
| 977 | } |
| 978 | return proc; |
| 979 | } |
| 980 | |