From eb85361c7ee584becba59d07d8e5d619360ad81e Mon Sep 17 00:00:00 2001 From: Brian Matherly Date: Fri, 2 Sep 2011 01:32:03 +0000 Subject: [PATCH] Patch by Adam Stein - Continued work on "0002513: Using section/region on media_ref as thumbnail on reports" - add image cropping to Cairo documents svn: r18097 --- src/ImgManip.py | 39 ++++++++++++++++++++++ src/plugins/lib/libcairodoc.py | 59 +++++++++++++++++++++++++++------- 2 files changed, 87 insertions(+), 11 deletions(-) diff --git a/src/ImgManip.py b/src/ImgManip.py index cc7369f99..2987f5f80 100644 --- a/src/ImgManip.py +++ b/src/ImgManip.py @@ -180,6 +180,45 @@ def image_actual_size(x_cm, y_cm, x, y): return (act_width, act_height) +#------------------------------------------------------------------------- +# +# resize_to_buffer +# +#------------------------------------------------------------------------- +def resize_to_buffer(source, size, crop=None): + """ + Loads the image and resizes it. Instead of saving the file, the data + is returned in a buffer. + + :param source: source image file, in any format that gtk recognizes + :type source: unicode + :param size: desired size of the destination image ([width, height]) + :type size: list + :param crop: cropping coordinates + :type crop: array of integers ([start_x, start_y, end_x, end_y]) + :rtype: buffer of data + :returns: raw data + """ + import gtk + img = gtk.gdk.pixbuf_new_from_file(source) + + if crop: + # Gramps cropping coorinates are [0, 100], so we need to convert to pixels + start_x = int((crop[0]/100.0)*img.get_width()) + start_y = int((crop[1]/100.0)*img.get_height()) + end_x = int((crop[2]/100.0)*img.get_width()) + end_y = int((crop[3]/100.0)*img.get_height()) + + img = img.subpixbuf(start_x, start_y, end_x-start_x, end_y-start_y) + + # Need to keep the ratio intact, otherwise scaled images look stretched + # if the dimensions aren't close in size + (size[0], size[1]) = image_actual_size(size[0], size[1], img.get_width(), img.get_height()) + + scaled = img.scale_simple(int(size[0]), int(size[1]), gtk.gdk.INTERP_BILINEAR) + + return scaled + #------------------------------------------------------------------------- # # resize_to_jpeg_buffer diff --git a/src/plugins/lib/libcairodoc.py b/src/plugins/lib/libcairodoc.py index 734749ebe..106a94b76 100644 --- a/src/plugins/lib/libcairodoc.py +++ b/src/plugins/lib/libcairodoc.py @@ -46,6 +46,7 @@ from gen.plug.docgen import (BaseDoc, TextDoc, DrawDoc, ParagraphStyle, from gen.plug.report import utils as ReportUtils from Errors import PluginError from gen.plug.docbackend import CairoBackend +import ImgManip #------------------------------------------------------------------------ # @@ -894,11 +895,12 @@ class GtkDocPicture(GtkDocBaseElement): _type = 'IMAGE' _allowed_children = [] - def __init__(self, style, filename, width, height): + def __init__(self, style, filename, width, height, crop=None): GtkDocBaseElement.__init__(self, style) self._filename = filename self._width = width self._height = height + self._crop = crop def divide(self, layout, width, height, dpi_x, dpi_y): img_width = self._width * dpi_x / 2.54 @@ -923,7 +925,7 @@ class GtkDocPicture(GtkDocBaseElement): l_margin = 0 # load the image and get its extents - pixbuf = gtk.gdk.pixbuf_new_from_file(self._filename) + pixbuf = ImgManip.resize_to_buffer(self._filename, [img_width, img_height], self._crop) pixbuf_width = pixbuf.get_width() pixbuf_height = pixbuf.get_height() @@ -1227,6 +1229,7 @@ class CairoDoc(BaseDoc, TextDoc, DrawDoc): self._active_element = self._doc self._pages = [] self._elements_to_paginate = [] + self._links_error = False def close(self): self.run() @@ -1300,11 +1303,12 @@ class CairoDoc(BaseDoc, TextDoc, DrawDoc): Convenience function to write a styledtext to the cairo doc. styledtext : assumed a StyledText object to write format : = 0 : Flowed, = 1 : Preformatted - style_name : name of the style to use for default presentation - contains_html: bool, the backend should not check if html is present. - If contains_html=True, then the textdoc is free to handle that in - some way. Eg, a textdoc could remove all tags, or could make sure + style_name : name of the style to use for default presentation + contains_html: bool, the backend should not check if html is present. + If contains_html=True, then the textdoc is free to handle that in + some way. Eg, a textdoc could remove all tags, or could make sure a link is clickable. CairoDoc does nothing different for html notes + links: bool, true if URLs should be made clickable """ text = str(styledtext) @@ -1319,7 +1323,7 @@ class CairoDoc(BaseDoc, TextDoc, DrawDoc): #FIXME: following split should be regex to match \n\s*\n instead? for line in markuptext.split('\n\n'): self.start_paragraph(style_name) - self.__write_text(line, markup=True) + self.__write_text(line, markup=True, links=links) self.end_paragraph() elif format == 0: #flowed @@ -1331,16 +1335,34 @@ class CairoDoc(BaseDoc, TextDoc, DrawDoc): newlines = [] for singleline in lines: newlines.append(' '.join(singleline.split())) - self.__write_text('\n'.join(newlines), markup=True) + self.__write_text('\n'.join(newlines), markup=True, links=links) self.end_paragraph() - def __write_text(self, text, mark=None, markup=False): + def __write_text(self, text, mark=None, markup=False, links=False): """ @param text: text to write. @param mark: IndexMark to use for indexing (if supported) @param markup: True if text already contains markup info. Then text will no longer be escaped + @param links: True if URLs should be made clickable """ + if links == True: + import cairo + + if cairo.cairo_version() < 11210 and self._links_error == False: + # Cairo v1.12 is suppose to be the first version + # that supports clickable links + print """ +WARNING: This version of cairo (%s) does NOT support clickable links. +The first version that is suppose to is v1.12. See the roadmap: + + http://www.cairographics.org/roadmap/ + +The work around is to save to another format that supports clickable +links (like ODF) and write PDF from that format. + """ % cairo.version + self._links_error = True + if not markup: # We need to escape the text here for later pango.Layout.set_markup # calls. This way we save the markup created by the report @@ -1354,8 +1376,9 @@ class CairoDoc(BaseDoc, TextDoc, DrawDoc): present style @param text: text to write. @param mark: IndexMark to use for indexing (if supported) + @param links: True if URLs should be made clickable """ - self.__write_text(text, mark) + self.__write_text(text, mark, links=links) def write_markup(self, text, s_tags): """ @@ -1371,9 +1394,23 @@ class CairoDoc(BaseDoc, TextDoc, DrawDoc): def add_media_object(self, name, pos, x_cm, y_cm, alt='', style_name=None, crop=None): - new_image = GtkDocPicture(pos, name, x_cm, y_cm) + new_image = GtkDocPicture(pos, name, x_cm, y_cm, crop=crop) self._active_element.add_child(new_image) + if len(alt): + style_sheet = self.get_style_sheet() + + style = style_sheet.get_paragraph_style(style_name) + style.set_alignment(PARA_ALIGN_CENTER) + # Center the caption under the image + if pos == "right": + style.set_left_margin(self.get_usable_width() - new_image._width) + else: + style.set_right_margin(self.get_usable_width() - new_image._width) + new_paragraph = GtkDocParagraph(style) + new_paragraph.add_text(alt) + self._active_element.add_child(new_paragraph) + # DrawDoc implementation def start_page(self):