Patch by Adam Stein <adam@csh.rit.edu > - Continued work on "0002513: Using section/region on media_ref as thumbnail on reports" - add image cropping to Cairo documents

svn: r18097
This commit is contained in:
Brian Matherly 2011-09-02 01:32:03 +00:00
parent 85e803f5f6
commit eb85361c7e
2 changed files with 87 additions and 11 deletions

View File

@ -180,6 +180,45 @@ def image_actual_size(x_cm, y_cm, x, y):
return (act_width, act_height) 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 # resize_to_jpeg_buffer

View File

@ -46,6 +46,7 @@ from gen.plug.docgen import (BaseDoc, TextDoc, DrawDoc, ParagraphStyle,
from gen.plug.report import utils as ReportUtils from gen.plug.report import utils as ReportUtils
from Errors import PluginError from Errors import PluginError
from gen.plug.docbackend import CairoBackend from gen.plug.docbackend import CairoBackend
import ImgManip
#------------------------------------------------------------------------ #------------------------------------------------------------------------
# #
@ -894,11 +895,12 @@ class GtkDocPicture(GtkDocBaseElement):
_type = 'IMAGE' _type = 'IMAGE'
_allowed_children = [] _allowed_children = []
def __init__(self, style, filename, width, height): def __init__(self, style, filename, width, height, crop=None):
GtkDocBaseElement.__init__(self, style) GtkDocBaseElement.__init__(self, style)
self._filename = filename self._filename = filename
self._width = width self._width = width
self._height = height self._height = height
self._crop = crop
def divide(self, layout, width, height, dpi_x, dpi_y): def divide(self, layout, width, height, dpi_x, dpi_y):
img_width = self._width * dpi_x / 2.54 img_width = self._width * dpi_x / 2.54
@ -923,7 +925,7 @@ class GtkDocPicture(GtkDocBaseElement):
l_margin = 0 l_margin = 0
# load the image and get its extents # 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_width = pixbuf.get_width()
pixbuf_height = pixbuf.get_height() pixbuf_height = pixbuf.get_height()
@ -1227,6 +1229,7 @@ class CairoDoc(BaseDoc, TextDoc, DrawDoc):
self._active_element = self._doc self._active_element = self._doc
self._pages = [] self._pages = []
self._elements_to_paginate = [] self._elements_to_paginate = []
self._links_error = False
def close(self): def close(self):
self.run() self.run()
@ -1300,11 +1303,12 @@ class CairoDoc(BaseDoc, TextDoc, DrawDoc):
Convenience function to write a styledtext to the cairo doc. Convenience function to write a styledtext to the cairo doc.
styledtext : assumed a StyledText object to write styledtext : assumed a StyledText object to write
format : = 0 : Flowed, = 1 : Preformatted format : = 0 : Flowed, = 1 : Preformatted
style_name : name of the style to use for default presentation style_name : name of the style to use for default presentation
contains_html: bool, the backend should not check if html is present. 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 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 some way. Eg, a textdoc could remove all tags, or could make sure
a link is clickable. CairoDoc does nothing different for html notes a link is clickable. CairoDoc does nothing different for html notes
links: bool, true if URLs should be made clickable
""" """
text = str(styledtext) text = str(styledtext)
@ -1319,7 +1323,7 @@ class CairoDoc(BaseDoc, TextDoc, DrawDoc):
#FIXME: following split should be regex to match \n\s*\n instead? #FIXME: following split should be regex to match \n\s*\n instead?
for line in markuptext.split('\n\n'): for line in markuptext.split('\n\n'):
self.start_paragraph(style_name) self.start_paragraph(style_name)
self.__write_text(line, markup=True) self.__write_text(line, markup=True, links=links)
self.end_paragraph() self.end_paragraph()
elif format == 0: elif format == 0:
#flowed #flowed
@ -1331,16 +1335,34 @@ class CairoDoc(BaseDoc, TextDoc, DrawDoc):
newlines = [] newlines = []
for singleline in lines: for singleline in lines:
newlines.append(' '.join(singleline.split())) 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() 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 text: text to write.
@param mark: IndexMark to use for indexing (if supported) @param mark: IndexMark to use for indexing (if supported)
@param markup: True if text already contains markup info. @param markup: True if text already contains markup info.
Then text will no longer be escaped 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: if not markup:
# We need to escape the text here for later pango.Layout.set_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 # calls. This way we save the markup created by the report
@ -1354,8 +1376,9 @@ class CairoDoc(BaseDoc, TextDoc, DrawDoc):
present style present style
@param text: text to write. @param text: text to write.
@param mark: IndexMark to use for indexing (if supported) @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): 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='', def add_media_object(self, name, pos, x_cm, y_cm, alt='',
style_name=None, crop=None): 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) 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 # DrawDoc implementation
def start_page(self): def start_page(self):