Closed ghiewa closed 9 years ago
Hello!
Thanks for your proporsal. But I don't quite understand how it works. Does the template need a placeholder image? How are they loaded?
In the lastest lines I see: render.set_image_path('logo', 'images/new_logo.png'
. I end up mixing view and controller, which is something we have to avoid.
Please see PR #9.
Last but not the least, thank for your contribution to Secretary.
Yes there is a image placehold in odt template. Aim is provide template designer the ability of image size setting. Say -add a image in that odt tamplate, give it name odda.xxx -make sure xxx.png exists in path what you will config in your code render.set_image_path('logo', 'images/new_logo.png' )
A preview of image support is now on development branch. https://github.com/christopher-ramirez/secretary/tree/development
I will be glad to know your comments and suggestions about the intended functionality and API.
Frankly, it is great! Only one concern, without set_image_data func, I can not save/store images that generated on fly, but save them as file first and then import it using your 'image_filter'
@ghiewa actually the image filter does not make any loading. It just mark a Picture node to be later replaced by replace_images
method. The last method get the actual image through a media loader. Is in the media loader where you can generate images on the fly.
e.g:
from secretary import Renderer
engine = Renderer()
@engine.media_loader
def img_generator(value, *args, **kwargs):
# Generate an image
image = my_internal_function_to_generate_imgs(value)
# Return to replace_images a tuple whose first element is the recently
# generated image as a file object (must at least implement read method)
# and as second element the mimetype of image
return (image_as_file_object, img_mimetype)
As you can see, the only requirement is that the image object returned by a media loader implements a read
method. It is not really necessary to store it on a file. It could be a memory stream.
note, but it is not workable with {{barcode('887766666876', 'UPCA')|image}} where barcode('887766666876', 'UPCA') generates barcodes on the fly.
How are you generating the bar codes?
Here is my code,
from elaphe import barcode
import uuid
def barcode(self, codetype=None, codestring=None, options=dict(includetext=True), **kwargs):
id = uuid.uuid1().hex
if not codetype and not codestring:
return id
b = barcode(codetype, codestring, options, **kwargs) # scale=2, margin=1,
output = io.BytesIO()
b.save(output, 'PNG')
data = output.getvalue()
self.set_image_data(id, data)
return id
I wrote the following code. But really I do not know how elaphe.barcode
methods works. Specially what it returns.
from secretary import Renderer
engine = Renderer()
@engine.media_loader
def barcode_generator(value, codetype=None, codestring=None,
options=dict(includetext=True), **kwargs):
# Generate a barcode
id = uuid.uuid1().hex
if not codetype and not codestring:
return id
# Supossing `barcode` returns an SVG image casted as a file object,
# or at least having a `read()` method.
bc = barcode(codetype, codestring, options, **kwargs)
return (bc, 'image/svg+xml')
Have you tried implemented your barcode
method as a media loader?
UPDATE
It was after posting the above comment that I tried playing with elaphe
library. Now you code it's cleaver to me. The elaphe.barcode
method returns a EPS image and it's not in a file like object. You have to save the image in a file like object before passing it to Secretary.
So after some changes the above code would look like this:
from io import BytesIO
from secretary import Renderer
from elaphe import barcode
engine = Renderer()
@engine.media_loader
def barcode_generator(value, codetype=None, codestring=None,
options=dict(includetext=True), **kwargs):
# Generate a barcode
id = uuid.uuid1().hex
if not codetype and not codestring:
return None
# Generate barcode image
bc = barcode(codetype, codestring, options, **kwargs)
# Save image in a memory stream of file type (BytesIO)
stream = BytesIO()
bc.save(stream, 'eps')
# Set current pos os stream at BoF
stream.seek(0)
# Return the generated barcode.
return (stream, 'application/postscript')
DISCLAIMER: It tried elaphe.barcode
using qrcode
codes. When trying to use UPCA
codes PIL gave me strange errors.
can you help to update you template file here, sorry, I do not know how you setup image holder. or what you set in picture > option
Please see template at samples/images
in development branch.
Hi Christopher,
Yes, indeed it worked and I met same issue when using 'UPCA'.
more, can you consider the possibility of mulitiple media loader in one template?
additon, do you success on 'application/postscript'? than I do with 'application/image'
return (stream, 'application/postscript')
Hello @ghiewa,
First, why do you believe an multiple media loader solution would be useful? What use cases will it cover that are not possible or are very, very hard to accomplish with a single loader?
Lastly, I could not understand the idea on your last paragraph.
Hi Christopher,
Say, I am using your library on a price ticket layout generation, there are shose logo and barcode. Then I have to use code you suggested for barcode generation and the same time file loader (it is default media loader) used for shose logo load.
ok, I think I get the solution already, thank you.
there is no necessity of multiple media loader.
Hey, how can I set size of replaced image? Currently it gets the same size as placeholder image and becomes unproportional.
Hello!
If you have a media loader function, it should receive frame_attrs
and image_attrs
as keyword arguments [1]. This variables are passed by reference to the media loader and they contain the dimensions of the image frame and the actual image respectively. Update the attributes in this variables and Secretary should update the respective element on the document.
[1] https://github.com/christopher-ramirez/secretary#image-support
I have a draft for you reference.