#include <pdflib.h>
#include <math.h>
#include "../os.h"
+#include "../q.h"
#include "../jpeg.h"
#include "../types.h"
#include "../mem.h"
+#include "../log.h"
#include "../gfxdevice.h"
#include "../gfxtools.h"
+#include "../gfximage.h"
typedef struct _internal {
PDF* p;
+
+ const char*config_pdfx;
+ char config_addblankpages;
+ double config_xpad;
+ double config_ypad;
+ int config_maxdpi;
+
+ int width,height;
+ int num_pages;
+
char*tempfile;
+ char*page_opts;
+ double lastx,lasty;
gfxfontlist_t*fontlist;
} internal_t;
PDF_set_parameter(i->p, "fillrule", "evenodd");
}
-static int mkline(gfxline_t*line, PDF*p)
+static int mkline(gfxline_t*line, PDF*p, char fill)
{
- int ret = 0;
double x=0,y=0;
+ char first = 1;
+ int ret = 0;
+ gfxline_t*free_line = 0;
+ if(fill) {
+ line = gfxline_restitch(gfxline_clone(line));
+ free_line = line;
+ }
while(line) {
- if(line->type == gfx_moveTo) {
+ if(line->type == gfx_moveTo && (x!=line->x || y!=line->y || first)) {
+ first = 0;
PDF_moveto(p, line->x, line->y);
} else if(line->type == gfx_lineTo) {
PDF_lineto(p, line->x, line->y);
y = line->y;
line = line->next;
}
+ if(free_line)
+ gfxline_free(free_line);
return ret;
}
{
internal_t*i = (internal_t*)dev->internal;
PDF_save(i->p);
- if(mkline(line, i->p))
+ if(mkline(line, i->p, 1))
PDF_clip(i->p);
else
; // TODO: strictly speaking, an empty clip clears everything
void pdf_stroke(gfxdevice_t*dev, gfxline_t*line, gfxcoord_t width, gfxcolor_t*color, gfx_capType cap_style, gfx_joinType joint_style, gfxcoord_t miterLimit)
{
internal_t*i = (internal_t*)dev->internal;
+ if(width<1e-6)
+ return;
PDF_setlinewidth(i->p, width);
PDF_setlinecap(i->p, cap_style==gfx_capButt?0:(cap_style==gfx_capRound?1:2));
PDF_setlinejoin(i->p, joint_style==gfx_joinMiter?0:(joint_style==gfx_joinRound?1:2));
PDF_setrgbcolor_stroke(i->p, color->r/255.0, color->g/255.0, color->b/255.0);
if(joint_style==gfx_joinMiter)
PDF_setmiterlimit(i->p, miterLimit);
- if(mkline(line, i->p))
+ if(mkline(line, i->p, 0))
PDF_stroke(i->p);
}
{
internal_t*i = (internal_t*)dev->internal;
PDF_setrgbcolor_fill(i->p, color->r/255.0, color->g/255.0, color->b/255.0);
+ if(color->a!=255) {
+ char opacityfill[80];
+ sprintf(opacityfill, "opacityfill %f", color->a/256.0);
+ int gstate = PDF_create_gstate(i->p, opacityfill);
+ PDF_set_gstate(i->p, gstate);
+ }
- if(mkline(line, i->p)) {
+ if(mkline(line, i->p, 1)) {
PDF_fill(i->p);
}
}
{
internal_t*i = (internal_t*)dev->internal;
- double l1 = sqrt(matrix->m00*matrix->m00+matrix->m01*matrix->m01)*img->width;
- double l2 = sqrt(matrix->m10*matrix->m10+matrix->m11*matrix->m11)*img->height;
+ int t,size=img->width*img->height;
+ int has_alpha=0;
+ for(t=0;t<size;t++) {
+ if(img->data[t].a!=255) {
+ has_alpha=1;
+ break;
+ }
+ }
+
+ double w = sqrt(matrix->m00*matrix->m00+matrix->m01*matrix->m01);
+ double h = sqrt(matrix->m10*matrix->m10+matrix->m11*matrix->m11);
+ double l1 = w*img->width;
+ double l2 = h*img->height;
double r = atan2(matrix->m01, matrix->m00);
/* fit_image needs the lower left corner of the image */
double x = matrix->tx + matrix->m10*img->height;
double y = matrix->ty + matrix->m11*img->height;
- char*tempfile = mktempname(0);
+ double dpi_x = 72.0 / w;
+ double dpi_y = 72.0 / h;
+ double dpi = dpi_x>dpi_y?dpi_x:dpi_y;
+ gfximage_t*rescaled_image = 0;
+ if(i->config_maxdpi && dpi > i->config_maxdpi) {
+ int newwidth = img->width*i->config_maxdpi/dpi;
+ int newheight = img->height*i->config_maxdpi/dpi;
+ rescaled_image = gfximage_rescale(img, newwidth, newheight);
+ msg("<notice> Downscaling %dx%d image (dpi %f, %.0fx%.0f on page) to %dx%d (dpi %d)",
+ img->width, img->height, dpi, l1, l2, newwidth, newheight, i->config_maxdpi);
+ img = rescaled_image;
+ }
+
+ char tempfile[128];
+ mktempname(tempfile);
+
+ gfximage_save_jpeg(img, tempfile, 96);
+
+ int imgid=-1;
+ if(has_alpha) {
+ char tempfile2[128];
+ mktempname(tempfile2);
+ int t;
+ int size = img->width*img->height;
+ unsigned char*alpha = malloc(size);
+ for(t=0;t<size;t++) {
+ alpha[t] = img->data[t].a;
+ }
+ jpeg_save_gray(alpha, img->width, img->height, 97, tempfile2);
+ free(alpha);
+ int maskid = PDF_load_image(i->p, "jpeg", tempfile2, 0, "mask");
+ unlink(tempfile2);
+ char masked[80];
+ if(maskid<0) {
+ msg("<error> Couldn't process mask jpeg of size %dx%d: error code %d", img->width, img->height, maskid);
+ return;
+ }
+ sprintf(masked, "masked %d", maskid);
+ imgid = PDF_load_image(i->p, "jpeg", tempfile, 0, masked);
+ } else {
+ imgid = PDF_load_image(i->p, "jpeg", tempfile, 0, "");
+ }
+
+ if(imgid<0) {
+ msg("<error> Couldn't process jpeg of size %dx%d: error code %d, file %s", img->width, img->height, imgid, tempfile);
+ return;
+ }
+ unlink(tempfile);
+
char options[80];
sprintf(options, "boxsize {%f %f} fitmethod meet rotate %f", l1, l2, r*180/M_PI);
- gfximage_save_jpeg(img, tempfile, 99);
- int imgid = PDF_load_image(i->p, "jpeg", tempfile, 0, "");
PDF_fit_image(i->p, imgid, x, y, options);
+ PDF_close_image(i->p, imgid);
+
+ if(rescaled_image)
+ gfximage_free(rescaled_image);
}
void pdf_fillgradient(gfxdevice_t*dev, gfxline_t*line, gfxgradient_t*gradient, gfxgradienttype_t type, gfxmatrix_t*matrix)
sprintf(name, "chr%d", t+32);
PDF_encoding_set_char(i->p, fontname, t+32, name, 0);
PDF_begin_glyph(i->p, name, g->advance, bbox.xmin, bbox.ymin, bbox.xmax, bbox.ymax);
- if(mkline(g->line, i->p))
+ if(mkline(g->line, i->p, 1))
PDF_fill(i->p);
PDF_end_glyph(i->p);
}
if(glyphnr>256-32) as_shape=1;
if(fabs(matrix->m00 + matrix->m11) > 0.01) as_shape=1;
if(fabs(fabs(matrix->m01) + fabs(matrix->m10)) > 0.01) as_shape=1;
- if(fabs(matrix->m00) < 0.01) as_shape=1;
+ if(fabs(matrix->m00) < 1e-6) as_shape=1;
if(as_shape) {
gfxline_t*line2 = gfxline_clone(glyph->line);
gfxline_transform(line2, matrix);
- if(mkline(line2, i->p)) {
+ if(mkline(line2, i->p, 1)) {
PDF_fill(i->p);
}
gfxline_free(line2);
int fontid = (int)(ptroff_t)gfxfontlist_getuserdata(i->fontlist, font->id);
PDF_setfont(i->p, fontid, matrix->m00);
char name[32];
- sprintf(name, "%c\0", glyphnr+32);
- PDF_show_xy2(i->p, name, strlen(name), matrix->tx, matrix->ty);
+ sprintf(name, "%c", glyphnr+32);
+
+ if(fabs(matrix->tx - i->lastx) > 0.001 || matrix->ty != i->lasty) {
+ PDF_show_xy2(i->p, name, strlen(name), matrix->tx, matrix->ty);
+ } else {
+ PDF_show2(i->p, name, strlen(name));
+ }
+
+ i->lastx = matrix->tx + glyph->advance*matrix->m00;
+ i->lasty = matrix->ty;
}
return;
}
void pdfresult_destroy(gfxresult_t*gfx)
{
pdfresult_internal_t*i = (pdfresult_internal_t*)gfx->internal;
+ unlink(i->tempfile);
free(i->tempfile);
free(gfx->internal);gfx->internal = 0;
free(gfx);
dev->endpage = pdf_endpage;
dev->finish = pdf_finish;
+ i->lastx = -1e38;
+ i->lasty = -1e38;
i->p = PDF_new();
}