📄 cairo-pdf-surface.c
字号:
_cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_TYPE_MISMATCH); return; } pdf_surface->width = width_in_points; pdf_surface->height = height_in_points;}static void_cairo_pdf_surface_clear (cairo_pdf_surface_t *surface){ _cairo_array_truncate (&surface->streams, 0);}static cairo_surface_t *_cairo_pdf_surface_create_similar (void *abstract_src, cairo_content_t content, int width, int height){ cairo_format_t format = _cairo_format_from_content (content); /* Just return an image for now, until PDF surface can be used * as source. */ return cairo_image_surface_create (format, width, height);}static cairo_pdf_resource_t_cairo_pdf_surface_open_stream (cairo_pdf_surface_t *surface, const char *fmt, ...){ va_list ap; surface->current_stream.active = TRUE; surface->current_stream.self = _cairo_pdf_surface_new_object (surface); surface->current_stream.length = _cairo_pdf_surface_new_object (surface); _cairo_output_stream_printf (surface->output, "%d 0 obj\r\n" "<< /Length %d 0 R\r\n", surface->current_stream.self.id, surface->current_stream.length.id); if (fmt != NULL) { va_start (ap, fmt); _cairo_output_stream_vprintf (surface->output, fmt, ap); va_end (ap); } _cairo_output_stream_printf (surface->output, ">>\r\n" "stream\r\n"); surface->current_stream.start_offset = _cairo_output_stream_get_position (surface->output); return surface->current_stream.self;}static void_cairo_pdf_surface_close_stream (cairo_pdf_surface_t *surface){ long length; if (! surface->current_stream.active) return; length = _cairo_output_stream_get_position (surface->output) - surface->current_stream.start_offset; _cairo_output_stream_printf (surface->output, "endstream\r\n" "endobj\r\n"); _cairo_pdf_surface_update_object (surface, surface->current_stream.length); _cairo_output_stream_printf (surface->output, "%d 0 obj\r\n" " %ld\r\n" "endobj\r\n", surface->current_stream.length.id, length); surface->current_stream.active = FALSE;}static cairo_status_t_cairo_pdf_surface_finish (void *abstract_surface){ cairo_status_t status; cairo_pdf_surface_t *surface = abstract_surface; long offset; cairo_pdf_resource_t info, catalog; _cairo_pdf_surface_close_stream (surface); _cairo_pdf_surface_emit_font_subsets (surface); _cairo_pdf_surface_write_pages (surface); info = _cairo_pdf_surface_write_info (surface); catalog = _cairo_pdf_surface_write_catalog (surface); offset = _cairo_pdf_surface_write_xref (surface); _cairo_output_stream_printf (surface->output, "trailer\r\n" "<< /Size %d\r\n" " /Root %d 0 R\r\n" " /Info %d 0 R\r\n" ">>\r\n", surface->next_available_resource.id, catalog.id, info.id); _cairo_output_stream_printf (surface->output, "startxref\r\n" "%ld\r\n" "%%%%EOF\r\n", offset); status = _cairo_output_stream_get_status (surface->output); _cairo_output_stream_destroy (surface->output); _cairo_array_fini (&surface->objects); _cairo_array_fini (&surface->pages); _cairo_array_fini (&surface->patterns); _cairo_array_fini (&surface->xobjects); _cairo_array_fini (&surface->streams); _cairo_array_fini (&surface->alphas); if (surface->font_subsets) { _cairo_scaled_font_subsets_destroy (surface->font_subsets); surface->font_subsets = NULL; } _cairo_array_fini (&surface->fonts); return status;}static void_cairo_pdf_surface_pause_content_stream (cairo_pdf_surface_t *surface){ _cairo_pdf_surface_close_stream (surface);}static void_cairo_pdf_surface_resume_content_stream (cairo_pdf_surface_t *surface){ cairo_pdf_resource_t stream; stream = _cairo_pdf_surface_open_stream (surface, " /Type /XObject\r\n" " /Subtype /Form\r\n" " /BBox [ 0 0 %f %f ]\r\n", surface->width, surface->height); _cairo_pdf_surface_add_stream (surface, stream);}static cairo_int_status_t_cairo_pdf_surface_start_page (void *abstract_surface){ cairo_pdf_surface_t *surface = abstract_surface; cairo_pdf_resource_t stream; stream = _cairo_pdf_surface_open_stream (surface, " /Type /XObject\r\n" " /Subtype /Form\r\n" " /BBox [ 0 0 %f %f ]\r\n", surface->width, surface->height); _cairo_pdf_surface_add_stream (surface, stream); _cairo_output_stream_printf (surface->output, "1 0 0 -1 0 %f cm\r\n", surface->height); return CAIRO_STATUS_SUCCESS;}static void *compress_dup (const void *data, unsigned long data_size, unsigned long *compressed_size){ void *compressed; /* Bound calculation taken from zlib. */ *compressed_size = data_size + (data_size >> 12) + (data_size >> 14) + 11; compressed = malloc (*compressed_size); if (compressed == NULL) return NULL; compress (compressed, compressed_size, data, data_size); return compressed;}/* Emit alpha channel from the image into the given data, providing * and id that can be used to reference the resulting SMask object. * * In the case that the alpha channel happens to be all opaque, then * no SMask object will be emitted and *id_ret will be set to 0. */static cairo_status_temit_smask (cairo_pdf_surface_t *surface, cairo_image_surface_t *image, cairo_pdf_resource_t *stream_ret){ cairo_status_t status = CAIRO_STATUS_SUCCESS; char *alpha, *alpha_compressed; unsigned long alpha_size, alpha_compressed_size; pixman_bits_t *pixel; int i, x, y; cairo_bool_t opaque; uint8_t a; /* This is the only image format we support, which simplfies things. */ assert (image->format == CAIRO_FORMAT_ARGB32); alpha_size = image->height * image->width; alpha = malloc (alpha_size); if (alpha == NULL) { status = CAIRO_STATUS_NO_MEMORY; goto CLEANUP; } opaque = TRUE; i = 0; for (y = 0; y < image->height; y++) { pixel = (pixman_bits_t *) (image->data + y * image->stride); for (x = 0; x < image->width; x++, pixel++) { a = (*pixel & 0xff000000) >> 24; alpha[i++] = a; if (a != 0xff) opaque = FALSE; } } /* Bail out without emitting smask if it's all opaque. */ if (opaque) { stream_ret->id = 0; goto CLEANUP_ALPHA; } alpha_compressed = compress_dup (alpha, alpha_size, &alpha_compressed_size); if (alpha_compressed == NULL) { status = CAIRO_STATUS_NO_MEMORY; goto CLEANUP_ALPHA; } *stream_ret = _cairo_pdf_surface_open_stream (surface, " /Type /XObject\r\n" " /Subtype /Image\r\n" " /Width %d\r\n" " /Height %d\r\n" " /ColorSpace /DeviceGray\r\n" " /BitsPerComponent 8\r\n" " /Filter /FlateDecode\r\n", image->width, image->height); _cairo_output_stream_write (surface->output, alpha_compressed, alpha_compressed_size); _cairo_output_stream_printf (surface->output, "\r\n"); _cairo_pdf_surface_close_stream (surface); free (alpha_compressed); CLEANUP_ALPHA: free (alpha); CLEANUP: return status;}/* Emit image data into the given surface, providing a resource that * can be used to reference the data in image_ret. */static cairo_status_temit_image (cairo_pdf_surface_t *surface, cairo_image_surface_t *image, cairo_pdf_resource_t *image_ret){ cairo_status_t status = CAIRO_STATUS_SUCCESS; char *rgb, *compressed; unsigned long rgb_size, compressed_size; pixman_bits_t *pixel; int i, x, y; cairo_pdf_resource_t smask = {0}; /* squelch bogus compiler warning */ cairo_bool_t need_smask; /* XXX: Need to rewrite this as a pdf_surface function with * pause/resume of content_stream, (currently the only caller does * the pause/resume already, but that is expected to change in the * future). */ /* These are the only image formats we currently support, (which * makes things a lot simpler here). This is enforced through * _analyze_operation which only accept source surfaces of * CONTENT_COLOR or CONTENT_COLOR_ALPHA. */ assert (image->format == CAIRO_FORMAT_RGB24 || image->format == CAIRO_FORMAT_ARGB32); rgb_size = image->height * image->width * 3; rgb = malloc (rgb_size); if (rgb == NULL) { status = CAIRO_STATUS_NO_MEMORY; goto CLEANUP; } i = 0; for (y = 0; y < image->height; y++) { pixel = (pixman_bits_t *) (image->data + y * image->stride); for (x = 0; x < image->width; x++, pixel++) { /* XXX: We're un-premultiplying alpha here. My reading of the PDF * specification suggests that we should be able to avoid having * to do this by filling in the SMask's Matte dictionary * appropriately, but my attempts to do that so far have * failed. */ if (image->format == CAIRO_FORMAT_ARGB32) { uint8_t a; a = (*pixel & 0xff000000) >> 24; if (a == 0) { rgb[i++] = 0; rgb[i++] = 0; rgb[i++] = 0; } else { rgb[i++] = (((*pixel & 0xff0000) >> 16) * 255 + a / 2) / a; rgb[i++] = (((*pixel & 0x00ff00) >> 8) * 255 + a / 2) / a; rgb[i++] = (((*pixel & 0x0000ff) >> 0) * 255 + a / 2) / a; } } else { rgb[i++] = (*pixel & 0x00ff0000) >> 16; rgb[i++] = (*pixel & 0x0000ff00) >> 8; rgb[i++] = (*pixel & 0x000000ff) >> 0; } } } compressed = compress_dup (rgb, rgb_size, &compressed_size); if (compressed == NULL) { status = CAIRO_STATUS_NO_MEMORY; goto CLEANUP_RGB; } need_smask = FALSE; if (image->format == CAIRO_FORMAT_ARGB32) { status = emit_smask (surface, image, &smask); if (status) goto CLEANUP_COMPRESSED; if (smask.id) need_smask = TRUE; }#define IMAGE_DICTIONARY " /Type /XObject\r\n" \ " /Subtype /Image\r\n" \ " /Width %d\r\n" \ " /Height %d\r\n" \ " /ColorSpace /DeviceRGB\r\n" \ " /BitsPerComponent 8\r\n" \ " /Filter /FlateDecode\r\n" if (need_smask) *image_ret = _cairo_pdf_surface_open_stream (surface, IMAGE_DICTIONARY " /SMask %d 0 R\r\n", image->width, image->height, smask.id); else *image_ret = _cairo_pdf_surface_open_stream (surface, IMAGE_DICTIONARY, image->width, image->height);#undef IMAGE_DICTIONARY _cairo_output_stream_write (surface->output, compressed, compressed_size); _cairo_output_stream_printf (surface->output, "\r\n"); _cairo_pdf_surface_close_stream (surface); CLEANUP_COMPRESSED: free (compressed); CLEANUP_RGB: free (rgb); CLEANUP: return status;}static cairo_status_temit_solid_pattern (cairo_pdf_surface_t *surface, cairo_solid_pattern_t *pattern){ cairo_pdf_resource_t alpha; alpha = _cairo_pdf_surface_add_alpha (surface, pattern->color.alpha); /* With some work, we could separate the stroking * or non-stroking color here as actually needed. */ _cairo_output_stream_printf (surface->output, "%f %f %f RG " "%f %f %f rg " "/a%d gs\r\n", pattern->color.red, pattern->color.green, pattern->color.blue, pattern->color.red, pattern->color.green, pattern->color.blue, alpha.id); return CAIRO_STATUS_SUCCESS;}static cairo_status_temit_surface_pattern (cairo_pdf_surface_t *surface, cairo_surface_pattern_t *pattern){ cairo_pdf_resource_t stream; cairo_image_surface_t *image; void *image_extra; cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_pdf_resource_t alpha, image_resource = {0}; /* squelch bogus compiler warning */ cairo_matrix_t cairo_p2d, pdf_p2d; cairo_extend_t extend = cairo_pattern_get_extend (&pattern->base); int xstep, ystep; cairo_rectangle_int16_t surface_extents; /* XXX: Should do something clever here for PDF source surfaces ? */ _cairo_pdf_surface_pause_content_stream (surface); status = _cairo_surface_acquire_source_image (pattern->surface, &image, &image_extra); if (status) return status; status = emit_image (surface, image, &image_resource); if (status) goto BAIL; _cairo_surface_get_extents (&surface->base, &surface_extents); /* In PDF, (as far as I can tell), all patterns are repeating. So * we support cairo's EXTEND_NONE semantics by setting the repeat
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -