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:
parent
85e803f5f6
commit
eb85361c7e
@ -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
|
||||||
|
@ -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):
|
||||||
|
Loading…
Reference in New Issue
Block a user