📄 cairo-pdf-surface.c
字号:
* step size to the larger of the image size and the extents of * the destination surface. That way we guarantee the pattern will * not repeat. */ switch (extend) { case CAIRO_EXTEND_NONE: xstep = MAX(image->width, surface_extents.width); ystep = MAX(image->height, surface_extents.height); break; case CAIRO_EXTEND_REPEAT: xstep = image->width; ystep = image->height; break; default: ASSERT_NOT_REACHED; /* all others should be analyzed away */ xstep = 0; ystep = 0; } /* At this point, (that is, within the surface backend interface), * the pattern's matrix maps from cairo's device space to cairo's * pattern space, (both with their origin at the upper-left, and * cairo's pattern space of size width,height). * * Then, we must emit a PDF pattern object that maps from its own * pattern space, (which has a size that we establish in the BBox * dictionary entry), to the PDF page's *initial* space, (which * does not benefit from the Y-axis flipping matrix that we emit * on each page). So the PDF patterns patrix maps from a * (width,height) pattern space to a device space with the origin * in the lower-left corner. * * So to handle all of that, we start with an identity matrix for * the PDF pattern to device matrix. We translate it up by the * image height then flip it in the Y direction, (moving us from * the PDF origin to cairo's origin). We then multiply in the * inverse of the cairo pattern matrix, (since it maps from device * to pattern, while we're setting up pattern to device). Finally, * we translate back down by the image height and flip again to * end up at the lower-left origin that PDF expects. * * Additionally, within the stream that paints the pattern itself, * we are using a PDF image object that has a size of (1,1) so we * have to scale it up by the image width and height to fill our * pattern cell. */ cairo_p2d = pattern->base.matrix; cairo_matrix_invert (&cairo_p2d); cairo_matrix_init_identity (&pdf_p2d); cairo_matrix_translate (&pdf_p2d, 0.0, surface_extents.height); cairo_matrix_scale (&pdf_p2d, 1.0, -1.0); cairo_matrix_multiply (&pdf_p2d, &cairo_p2d, &pdf_p2d); cairo_matrix_translate (&pdf_p2d, 0.0, image->height); cairo_matrix_scale (&pdf_p2d, 1.0, -1.0); stream = _cairo_pdf_surface_open_stream (surface, " /BBox [0 0 %d %d]\r\n" " /XStep %d\r\n" " /YStep %d\r\n" " /PatternType 1\r\n" " /TilingType 1\r\n" " /PaintType 1\r\n" " /Matrix [ %f %f %f %f %f %f ]\r\n" " /Resources << /XObject << /res%d %d 0 R >> >>\r\n", image->width, image->height, xstep, ystep, pdf_p2d.xx, pdf_p2d.yx, pdf_p2d.xy, pdf_p2d.yy, pdf_p2d.x0, pdf_p2d.y0, image_resource.id, image_resource.id); _cairo_output_stream_printf (surface->output, "q %d 0 0 %d 0 0 cm /res%d Do Q\r\n", image->width, image->height, image_resource.id); _cairo_pdf_surface_close_stream (surface); _cairo_pdf_surface_resume_content_stream (surface); _cairo_pdf_surface_add_pattern (surface, stream); alpha = _cairo_pdf_surface_add_alpha (surface, 1.0); /* With some work, we could separate the stroking * or non-stroking pattern here as actually needed. */ _cairo_output_stream_printf (surface->output, "/Pattern CS /res%d SCN " "/Pattern cs /res%d scn " "/a%d gs\r\n", stream.id, stream.id, alpha.id); BAIL: _cairo_surface_release_source_image (pattern->surface, image, image_extra); return status;}typedef struct _cairo_pdf_color_stop { double offset; cairo_pdf_resource_t gradient; unsigned char color_char[4];} cairo_pdf_color_stop_t;static cairo_pdf_resource_temit_linear_colorgradient (cairo_pdf_surface_t *surface, cairo_pdf_color_stop_t *stop1, cairo_pdf_color_stop_t *stop2){ cairo_pdf_resource_t function = _cairo_pdf_surface_new_object (surface); _cairo_output_stream_printf (surface->output, "%d 0 obj\r\n" "<< /FunctionType 0\r\n" " /Domain [ 0 1 ]\r\n" " /Size [ 2 ]\r\n" " /BitsPerSample 8\r\n" " /Range [ 0 1 0 1 0 1 ]\r\n" " /Length 6\r\n" ">>\r\n" "stream\r\n", function.id); _cairo_output_stream_write (surface->output, stop1->color_char, 3); _cairo_output_stream_write (surface->output, stop2->color_char, 3); _cairo_output_stream_printf (surface->output, "\r\n" "endstream\r\n" "endobj\r\n"); return function;}static cairo_pdf_resource_temit_stiched_colorgradient (cairo_pdf_surface_t *surface, unsigned int n_stops, cairo_pdf_color_stop_t stops[]){ cairo_pdf_resource_t function; unsigned int i; /* emit linear gradients between pairs of subsequent stops... */ for (i = 0; i < n_stops-1; i++) { stops[i].gradient = emit_linear_colorgradient (surface, &stops[i], &stops[i+1]); } /* ... and stich them together */ function = _cairo_pdf_surface_new_object (surface); _cairo_output_stream_printf (surface->output, "%d 0 obj\r\n" "<< /FunctionType 3\r\n" " /Domain [ 0 1 ]\r\n", function.id); _cairo_output_stream_printf (surface->output, " /Functions [ "); for (i = 0; i < n_stops-1; i++) { _cairo_output_stream_printf (surface->output, "%d 0 R ", stops[i].gradient.id); } _cairo_output_stream_printf (surface->output, "]\r\n"); _cairo_output_stream_printf (surface->output, " /Bounds [ "); for (i = 1; i < n_stops-1; i++) { _cairo_output_stream_printf (surface->output, "%f ", stops[i].offset); } _cairo_output_stream_printf (surface->output, "]\r\n"); _cairo_output_stream_printf (surface->output, " /Encode [ "); for (i = 1; i < n_stops; i++) { _cairo_output_stream_printf (surface->output, "0 1 "); } _cairo_output_stream_printf (surface->output, "]\r\n"); _cairo_output_stream_printf (surface->output, ">>\r\n" "endobj\r\n"); return function;}#define COLOR_STOP_EPSILLON 1e-6static cairo_pdf_resource_temit_pattern_stops (cairo_pdf_surface_t *surface, cairo_gradient_pattern_t *pattern){ cairo_pdf_resource_t function; cairo_pdf_color_stop_t *allstops, *stops; unsigned int n_stops; unsigned int i; function = _cairo_pdf_surface_new_object (surface); allstops = malloc ((pattern->n_stops + 2) * sizeof (cairo_pdf_color_stop_t)); if (allstops == NULL) { _cairo_error (CAIRO_STATUS_NO_MEMORY); function.id = 0; return function; } stops = &allstops[1]; n_stops = pattern->n_stops; for (i = 0; i < pattern->n_stops; i++) { stops[i].color_char[0] = pattern->stops[i].color.red >> 8; stops[i].color_char[1] = pattern->stops[i].color.green >> 8; stops[i].color_char[2] = pattern->stops[i].color.blue >> 8; stops[i].color_char[3] = pattern->stops[i].color.alpha >> 8; stops[i].offset = _cairo_fixed_to_double (pattern->stops[i].x); } /* make sure first offset is 0.0 and last offset is 1.0. (Otherwise Acrobat * Reader chokes.) */ if (stops[0].offset > COLOR_STOP_EPSILLON) { memcpy (allstops, stops, sizeof (cairo_pdf_color_stop_t)); stops = allstops; stops[0].offset = 0.0; n_stops++; } if (stops[n_stops-1].offset < 1.0 - COLOR_STOP_EPSILLON) { memcpy (&stops[n_stops], &stops[n_stops - 1], sizeof (cairo_pdf_color_stop_t)); stops[n_stops].offset = 1.0; n_stops++; } if (n_stops == 2) { /* no need for stiched function */ function = emit_linear_colorgradient (surface, &stops[0], &stops[1]); } else { /* multiple stops: stich. XXX possible optimization: regulary spaced * stops do not require stiching. XXX */ function = emit_stiched_colorgradient (surface, n_stops, stops); } free (allstops); return function;}static cairo_status_temit_linear_pattern (cairo_pdf_surface_t *surface, cairo_linear_pattern_t *pattern){ cairo_pdf_resource_t function, pattern_resource, alpha; double x0, y0, x1, y1; cairo_matrix_t p2u; _cairo_pdf_surface_pause_content_stream (surface); function = emit_pattern_stops (surface, &pattern->base); if (function.id == 0) return CAIRO_STATUS_NO_MEMORY; p2u = pattern->base.base.matrix; cairo_matrix_invert (&p2u); x0 = _cairo_fixed_to_double (pattern->gradient.p1.x); y0 = _cairo_fixed_to_double (pattern->gradient.p1.y); cairo_matrix_transform_point (&p2u, &x0, &y0); x1 = _cairo_fixed_to_double (pattern->gradient.p2.x); y1 = _cairo_fixed_to_double (pattern->gradient.p2.y); cairo_matrix_transform_point (&p2u, &x1, &y1); pattern_resource = _cairo_pdf_surface_new_object (surface); _cairo_output_stream_printf (surface->output, "%d 0 obj\r\n" "<< /Type /Pattern\r\n" " /PatternType 2\r\n" " /Matrix [ 1 0 0 -1 0 %f ]\r\n" " /Shading\r\n" " << /ShadingType 2\r\n" " /ColorSpace /DeviceRGB\r\n" " /Coords [ %f %f %f %f ]\r\n" " /Function %d 0 R\r\n" " /Extend [ true true ]\r\n" " >>\r\n" ">>\r\n" "endobj\r\n", pattern_resource.id, surface->height, x0, y0, x1, y1, function.id); _cairo_pdf_surface_add_pattern (surface, pattern_resource); alpha = _cairo_pdf_surface_add_alpha (surface, 1.0); /* Use pattern */ /* With some work, we could separate the stroking * or non-stroking pattern here as actually needed. */ _cairo_output_stream_printf (surface->output, "/Pattern CS /res%d SCN " "/Pattern cs /res%d scn " "/a%d gs\r\n", pattern_resource.id, pattern_resource.id, alpha.id); _cairo_pdf_surface_resume_content_stream (surface); return CAIRO_STATUS_SUCCESS;}static cairo_status_temit_radial_pattern (cairo_pdf_surface_t *surface, cairo_radial_pattern_t *pattern){ cairo_pdf_resource_t function, pattern_resource, alpha; double x0, y0, x1, y1, r0, r1; cairo_matrix_t p2u; _cairo_pdf_surface_pause_content_stream (surface); function = emit_pattern_stops (surface, &pattern->base); if (function.id == 0) return CAIRO_STATUS_NO_MEMORY; p2u = pattern->base.base.matrix; cairo_matrix_invert (&p2u); x0 = _cairo_fixed_to_double (pattern->gradient.inner.x); y0 = _cairo_fixed_to_double (pattern->gradient.inner.y); r0 = _cairo_fixed_to_double (pattern->gradient.inner.radius); cairo_matrix_transform_point (&p2u, &x0, &y0); x1 = _cairo_fixed_to_double (pattern->gradient.outer.x); y1 = _cairo_fixed_to_double (pattern->gradient.outer.y); r1 = _cairo_fixed_to_double (pattern->gradient.outer.radius); cairo_matrix_transform_point (&p2u, &x1, &y1); /* FIXME: This is surely crack, but how should you scale a radius * in a non-orthogonal coordinate system? */ cairo_matrix_transform_distance (&p2u, &r0, &r1); /* FIXME: There is a difference between the cairo gradient extend * semantics and PDF extend semantics. PDFs extend=false means * that nothing is painted outside the gradient boundaries, * whereas cairo takes this to mean that the end color is padded * to infinity. Setting extend=true in PDF gives the cairo default * behavoir, not yet sure how to implement the cairo mirror and * repeat behaviour. */ pattern_resource = _cairo_pdf_surface_new_object (surface); _cairo_output_stream_printf (surface->output, "%d 0 obj\r\n" "<< /Type /Pattern\r\n" " /PatternType 2\r\n" " /Matrix [ 1 0 0 -1 0 %f ]\r\n" " /Shading\r\n" " << /ShadingType 3\r\n" " /ColorSpace /DeviceRGB\r\n" " /Coords [ %f %f %f %f %f %f ]\r\n" " /Function %d 0 R\r\n" " /Extend [ true true ]\r\n" " >>\r\n" ">>\r\n" "endobj\r\n", pattern_resource.id, surface->height, x0, y0, r0, x1, y1, r1, function.id); _cairo_pdf_surface_add_pattern (surface, pattern_resource); alpha = _cairo_pdf_surface_add_alpha (surface, 1.0); /* Use pattern */ /* With some work, we could separate the stroking * or non-stroking pattern here as actually needed. */ _cairo_output_stream_printf (surface->output, "/Pattern CS /res%d SCN " "/Pattern cs /res%d scn " "/a%d gs\r\n", pattern_resource.id, pattern_resource.id, alpha.id); _cairo_pdf_surface_resume_content_stream (surface); return CAIRO_STATUS_SUCCESS;}static cairo_status_temit_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern){ switch (pattern->type) { case CAIRO_PATTERN_TYPE_SOLID: return emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern); case CAIRO_PATTERN_TYPE_SURFACE: return emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern); case CAIRO_PATTERN_TYPE_LINEAR: return emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern); case CAIRO_PATTERN_TYPE_RADIAL: return emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern); } ASSERT_NOT_REACHED; return CAIRO_STATUS_PATTERN_TYPE_MISMATCH;}static cairo_int_status_t_cairo_pdf_surface_copy_page (void *abstract_surface){ cairo_pdf_surface_t *surface = abstract_surface; return _cairo_pdf_surface_write_page (surface);}static cairo_int_status_t_cairo_pdf_surface_show_page (void *abstract_surface){ cairo_pdf_surface_t *surface = abstract_surface; cairo_int_status_t status; status = _cairo_pdf_surface_write_page (surface); if (status) return status; _cairo_pdf_surface_clear (surface); return CAIRO_STATUS_SUCCESS;}static cairo_int_status_t_cairo_pdf_surface_get_extents (void *abstract_surface,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -