Hi all, I'm getting very confused about a Zope product I'm working on, and I'm hoping somebody can share a clue on this. I've already figured out that I can load an image included with my product into PIL, with a line like this (which took a long time to figure out, any better solutions to this would be appreciated, too): im = PIL.Image.open( Globals.ImageFile('www/myimg.png', globals()).path) and then, I can load a PIL image into a contained Zope Image object (I was actually figuring that Globals.ImageFile would load a Zope image, but it seems not -- weird. Instead it's some kind of file access object, hence the "path" attribute used above). imf = StringIO() im.save(imf, "PNG") imf.seek(0) self.result_image.data = imf.read() self.result_image.width = 32 self.result_image.height = 32 self.result_image.content_type='image/png' self.result_image.size = len(self.result_image.data) ("im" is the PIL image, "self.result_image" is the Zope image, and "imf" is a StringIO object containing the image). Now the part that stumps me -- how do I return this image back to the caller? Specifically: * I want to return the PNG Image (i.e. a block of data * * with mime type 'image/png'), NOT an HTML image tag * * containing a reference to result_image . * I've tried: return self.result_image which returns a serialized image tag (i.e. just like return self.result_image.tag() which I've also tried). return self.result_image.data returns the PNG image alright, but the mime type is set to 'text/plain'! The kicker is, I have a related module which does do this successfully, by simply using: return self.result_image But I can't figure out why this one doesn't do it. So I need to have a better understanding of what makes this happen in order to figure out what the deal is. There are a lot of (apparently) trivial differences between the two, but each time I come across something that looks like the critical difference, it turns out not to change anything, so it's pretty darned tedious to do the experimental approach. So I figure I could use some theoretical predictions to guide me. :) Some of the differences I've already tried: Changing the base class from SimpleItem to Image (this is the class of the containing object, not the zope image object which is initialized within it -- i.e.: class myspecial_image_maker(Image): <-- this is the superclass that I changed from SimpleItem this class is not viewable as an image, so has no particular reason to be one. def __init__(self, id, title): self.id = id self.title = title self.result_image = OFS.Image.Image( 'result_image', 'Result Image', '', content_type='image/png') Also, on my earlier class, I want to use a URL interface for caching reasons, so I overloaded __getattr__, like this: def __getattr__(self, keystr): try: # omitted lengthy code to catch my coded URLs # code like that quoted above to load/make a PIL # image and pack into the Zope result_image image. return self.result_image except: Image.__getattr__(self, keystr) (So if anything goes wrong, or my code doesn't catch the attribute, it falls through to the superclass's __getattr__ -- this is pretty nice, but also tedious to debug, I have to warn you -- if you snare up standard attributes with your __getattr__, Zope gets very confused!). I remind you that this code does what I wanted -- i.e when you point your browser at the desired "coded" URL, you get the PNG image itself, with correct 'image/png' mime type. So you can do something like this: <img src="<dtml-var expr="Avatars.anonymous_png">/s32" width="32" height="32" border="0"/> where "anonymous_png" is an object of my earlier class. The coded URL "s32" asks for a version of the image resized to 32x32, which PIL takes care of. This code *works*. Now I'm trying to do it again, calling another function to generate an image from scratch (i.e. not contained in the class), based on some rules and PIL code, generated from the coded URL. But for some reason this *doesn't* work, and I'm trying to figure out what determines this, so I can see if I can find the difference (not to mention that this sounds like I will learn something significant about Zope). As you can see, I also changed the __getattr__ to use Image and not SimpleItem. Some of my test code, in order to avoid the complexity of interacting with the __getattr__ code, returns the image from a normal python method, like this: class ... def testimg(self): "Need this docstring or zope complains ;)" # omitted code (as above) to load a PIL image and convert # to a zope image return self.result_image This returns the image *tag* every time I've tried it. Is it possible that it matters whether I'm using __getattr__ or a python method to return this? Is there some hidden difference that I just haven't found yet (perhaps completely unrelated to what I've shown). The whole module is a bit long to post on the list, and it includes a lot of trivial details that would probably hinder more than help. I'm hoping I've already included the relevant parts above. I think I've tried returning the image from the __getattr__ method (to no avail), but I've been through so many variations, I really can't remember now! BTW, the actual module size is: % wc NaryaImage.py 385 1284 11050 NaryaImage.py Thanks for any ideas! Terry -- ------------------------------------------------------ Terry Hancock hancock@anansispaceworks.com Anansi Spaceworks http://www.anansispaceworks.com P.O. Box 60583 Pasadena, CA 91116-6583 ------------------------------------------------------