From cgw@pgt.com Sat Jul 4 16:42:31 1998
From: cgw@pgt.com (Charles G Waldman)
Date: Sat, 4 Jul 1998 11:42:31 -0400 (EDT)
Subject: [Image-SIG] Inter-converting images and Numeric arrays
Message-ID: <13726.19815.27733.767077@sirius>
I'm working on some image analysis software. For what I'm doing it's
much more efficient to have the pixel data in a Numeric array, rather
than a PIL Image, to avoid the overhead of lots of getpixel/setpixel
calls.
I've found it's pretty straightforward to inter-convert images and
arrays using fromstring/tostring.... but I have a few questions:
1: Shouldn't PIL support conversion directly to/from arrays? Using
the intermediate string works, but seems like a hack...
2: Seems that if I start with an Array, make an Image, then convert
back, the y-axis is inverted. Is this a feature or a bug?
Example program:
#!/usr/local/bin/python
import Image,ImagePalette
from Numeric import *
a = zeros((4,4),'b')
for y in range(0,4):
for x in range(0,4):
a[x,y]=x*10+y
print "before:"
print a
i1 = Image.fromstring("P",(4,4),a.tostring())
a1 = fromstring(i1.tostring(),'b')
a1.shape=(4,4)
print "after:"
print a1
And its output
>>>
before:
[[ 0 1 2 3]
[10 11 12 13]
[20 21 22 23]
[30 31 32 33]]
after:
[[30 31 32 33]
[20 21 22 23]
[10 11 12 13]
[ 0 1 2 3]]
>>>
From fredrik@pythonware.com Sat Jul 4 18:24:47 1998
From: fredrik@pythonware.com (Fredrik Lundh)
Date: Sat, 4 Jul 1998 18:24:47 +0100
Subject: [Image-SIG] Inter-converting images and Numeric arrays
Message-ID: <04e901bda770$a6051a90$f29b12c2@pythonware.com>
>1: Shouldn't PIL support conversion directly to/from arrays? Using
>the intermediate string works, but seems like a hack...
Recent versions provide getdata and putdata methods (getdata is
even documented):
data = im1.getdata()
im2 = Image.new(im1.mode, im2.size)
im3.putdata(data)
The sequence object returned by getdata is a bit fragile, at
least under 1.4. If you get problems, explicitly convert it to
a list or tuple:
data = list(im1.getdata())
>2: Seems that if I start with an Array, make an Image, then convert
>back, the y-axis is inverted. Is this a feature or a bug?
To be compatible with old versions of PIL, the fromstring/tostring
methods by default assumes that the data has the bottom-most line
first, and RGB data has an extra pad byte after each pixel. To get
other behaviour, you need to specify codec arguments.
However, the recent fromstring *function* doesn't provide the same
default behaviour -- instead, it defaults to more reasonable top-most
line first, RGB data without padding settings. The problem is that if
you pass the result from tostring directly to the fromstring *function*,
the image is turned upside down. Again, you can modify this behaviour
using codec arguments. See:
http://www.pythonware.com/library/pil/handbook/decoder.htm
...
We're about to release a new version of PIL; I'm tempted to change
the method's default settings so that it matches the fromstring function.
If this would break a huge amount of code for anyone on this list, please
speak up!
Cheers /F
From esr@snark.thyrsus.com Wed Jul 8 23:41:04 1998
From: esr@snark.thyrsus.com (Eric S. Raymond)
Date: Wed, 8 Jul 1998 18:41:04 -0400
Subject: [Image-SIG] PIL
Message-ID: <199807082241.SAA00186@snark.thyrsus.com>
For some years I have maintained GIFLIB, a C library and utility
toolkit for performing various slice and dice operations on raster
images. See http://www.tuxedo.org/~esr/giflib for details. Recently,
however, it became clear that Unisys's position on the LZW patent
makes continued distribution of this library too risky for me and for
its users.
I want to drop supporting it, but I don't want to do so without
leaving GIFLIB users some alternative supporting the toolkit
capabilities. My original thought was to try to rescue the C code by
teaching it to speak PNG.
I announced this to a group that included Guido. He steered me to
PIL. PIL is very impressive -- so much so that I think it will enable
me to officially declare the utilities in GIFLIB obsolete (but not the
library; that's a separate issue to which I'll return below).
A couple of documentation bugs:
On the index page, `Enhance' is spelled `Enchance'.
The `ImageFont' page is missing (File Not Found).
On the page describing the `Image' class, the `fromstring',
`tostring', and `putdata' methods are listed but not described.
The description of the resize method gave me pause until I guessed
that the size argument is a tuple. Don't make the reader guess;
specify the argument semantics there.
You should specify the angular units in the `rotate' method.
Degrees, radians, or grads? :-)
I think the PIL documentation's use of the term `band' is rather
unfortunate. To a native English speaker, the term `band' applied to
a graphic has a strong primary meaning which is different from PIL's;
that of a stripe or region (especially a horizontal one) extending the
full width of the image.
I recommend that you substitute the for `band' the term `channel',
which is well-established in exactly this sense for RGB images. It is
also the term used by the PNG folks and others in the graphics
community (notably the author of the "Graphics File Formats"
dictionary).
Functional suggestions:
Allow an optional argument in show() specifying the viewer command
to use.
There are aome places where PIL falls short of being a complete
replacement for the GIFLIB utilities:
1. No ability to display images using (a) the Borland BGI driver,
(b) an Epson printer, (c) a Hercules graphics card. I think we
can safely write these off as obsolete, however.
2. No ability to handle RLE (Utah raster toolkit) images. I'm not
too worried about this, either. Is anybody still using it?
3. No equivalent of the gifbg, gifwedge, and gifcolor test pattern
generators. These would probably be trivial to write.
4. (Serious) I see no way to overlay text on an image. I can supply a
clean 8x8 font and code for ImageDraw to overlay messages on an image
using it. Later this method could be extended to support fonts from
an X font server. Is this sort of thing what the missing ImageFont
module is about?
5. (Serious) There's no equivalent of the `clip complement' feature in
giflclip. Here's the GIF description:
-c
Complement. This removes horizontal and/or vertical bands of the
image. For example `-c -i 638 3 658 13' would remove a horizontal
band 11 pixels deep beginning at raster line 3, and a vertical
band 21 pixels right beginning at pixel 658.
This is useful more often than you'd think....
6. I see no standard function or method for composing multiple images into a
multi-file image in formats like GIF. (The gifovly utility in GIFLIB
does this.)
7. (Serious) There doesn't seem to be any way to specify interlacing or the
screen size on GIF output (GIFLIB's gifinter and gifpos utilities).
8. No utility to section an image into tiles (gifburst).
9. No equivalent of my icon2gif utility (see
http://www.tuxedo.org/~esr/giflib/doc/icon2gif.html
). Never mind, this is very GIF-specific.
If I hack in some of these things, can I stimulate a PIL release to
replace GIFLIB?
--
Eric S. Raymond
.. a government and its agents are under no general duty to
provide public services, such as police protection, to any
particular individual citizen...
-- Warren v. District of Columbia, 444 A.2d 1 (D.C. App.181)
From da@skivs.ski.org Thu Jul 9 03:47:28 1998
From: da@skivs.ski.org (David Ascher)
Date: Wed, 8 Jul 1998 19:47:28 -0700 (PDT)
Subject: [Image-SIG] PIL
In-Reply-To: <199807082241.SAA00186@snark.thyrsus.com>
Message-ID:
F/ (Fredrik) claimed he was on vacation a couple of days ago, so he may
not see this for a little while. I'll let him answer most of your
comments, but I thought I'd mention one thing re: fonts -- there is a
'pilfont' package at pythonware which is an improved version of ImageFont
and friends, which works just fine w/ BDF and PCF fonts (and stores them
in a bitmap as masks). Fredrik and I have also talked about adding
Freetype support, which I use on the OpenGL side of things. Apparently an
ex-colleague of F/'s has done a lot of that already but hasn't released
the code yet. Anyway, font support in PIL is not a real issue.
Also, FYI, a new release is promised for tomorrow (Friday), which makes me
doubt F/'s claim of a vacation =).
--david
From Fred L. Drake, Jr."
References: <199807082241.SAA00186@snark.thyrsus.com>
Message-ID: <13732.47499.455957.523783@weyr.cnri.reston.va.us>
David Ascher writes:
> F/ (Fredrik) claimed he was on vacation a couple of days ago, so he may
> not see this for a little while. I'll let him answer most of your
> comments, but I thought I'd mention one thing re: fonts -- there is a
...
> in a bitmap as masks). Fredrik and I have also talked about adding
> Freetype support, which I use on the OpenGL side of things. Apparently an
Perhaps this is a good chance to mention the t1lib library; this is
a rasterizer for Adobe Type1 fonts. A Python interface (which I
wrote) already exists and is bundled with the main t1lib package.
See http://www.python.org/sigs/image-sig/t1lib/ for more information.
-Fred
--
Fred L. Drake, Jr.
Corporation for National Research Initiatives
1895 Preston White Dr. Reston, VA 20191
From akuchlin@cnri.reston.va.us Thu Jul 9 19:10:56 1998
From: akuchlin@cnri.reston.va.us (Andrew Kuchling)
Date: Thu, 9 Jul 1998 14:10:56 -0400 (EDT)
Subject: [Image-SIG] PIL Wishlist
Message-ID: <13733.1106.92053.321533@newcnri.cnri.reston.va.us>
Distilling a wish list from the recent postings, I come up with this:
* RLE format support
* Test pattern generators
* Complement: cutting out strips of an image
* Support for multiple-frame images should be documented;
there are some demo scripts in Scripts/ (gifmaker.py, explode.py) but
they're not very well-known.
* There are other font rendering solutions such as t1lib and
pilfont. t1lib seems too large to add to PIL, but maybe pilfont can
be added.
* Freetype support
* t1lib
* Clean up and document the SANE interface (my job).
Other suggestions?
--
A.M. Kuchling http://starship.skyport.net/crew/amk/
Well, there was this doggy. He was a very clever doggy. He said things like...
like... "I would feel infinitely more comfortable in your presence if you
would agree to treat gravity as a law, rather than one of a number of
suggested options."
-- Delirium describes her dog Barnabas, in SANDMAN #63: "The Kindly Ones:7"
From Kevin Hilman Thu Jul 9 19:20:33 1998
From: Kevin Hilman (Kevin Hilman)
Date: 09 Jul 1998 11:20:33 -0700
Subject: [Image-SIG] PIL Wishlist
In-Reply-To: Andrew Kuchling's message of "Thu, 9 Jul 1998 14:10:56 -0400 (EDT)"
References: <13733.1106.92053.321533@newcnri.cnri.reston.va.us>
Message-ID:
How about additional file formats like YUV, UYVY. Or using
ImageMagick to convert to formats PIL can understand.
-kev-
Andrew Kuchling writes:
> Distilling a wish list from the recent postings, I come up with this:
>
> * RLE format support
>
> * Test pattern generators
>
> * Complement: cutting out strips of an image
>
> * Support for multiple-frame images should be documented;
> there are some demo scripts in Scripts/ (gifmaker.py, explode.py) but
> they're not very well-known.
>
> * There are other font rendering solutions such as t1lib and
> pilfont. t1lib seems too large to add to PIL, but maybe pilfont can
> be added.
>
> * Freetype support
>
> * t1lib
>
> * Clean up and document the SANE interface (my job).
>
> Other suggestions?
>
> --
> A.M. Kuchling http://starship.skyport.net/crew/amk/
> Well, there was this doggy. He was a very clever doggy. He said things like...
> like... "I would feel infinitely more comfortable in your presence if you
> would agree to treat gravity as a law, rather than one of a number of
> suggested options."
> -- Delirium describes her dog Barnabas, in SANDMAN #63: "The Kindly Ones:7"
>
>
> _______________________________________________
> Image-SIG maillist - Image-SIG@python.org
> http://www.python.org/mailman/listinfo/image-sig
From hannu@trust.ee Thu Jul 9 19:46:21 1998
From: hannu@trust.ee (Hannu Krosing)
Date: Thu, 09 Jul 1998 21:46:21 +0300
Subject: [Image-SIG] PIL Wishlist
References: <13733.1106.92053.321533@newcnri.cnri.reston.va.us>
Message-ID: <35A50FFD.EE83874C@trust.ee>
Andrew Kuchling wrote:
>
> Distilling a wish list from the recent postings, I come up with this:
>
...
>
> Other suggestions?
Could we have compressed GIF's as well ?
To circumvent the Unisys LZW patent, we could do as xpdf does:
unix command compress + some converion code ?
It would be a little slower, but probably fast enough for most uses.
Hannu
From richard.jones@BoM.GOV.AU Thu Jul 9 23:57:02 1998
From: richard.jones@BoM.GOV.AU (Richard Jones)
Date: Thu, 09 Jul 1998 22:57:02 +0000
Subject: [Image-SIG] PIL Wishlist
In-Reply-To: Message from Hannu Krosing of 1998-Jul-9 21:46:21,
<35A50FFD.EE83874C@trust.ee>
Message-ID: <199807092257.WAA28006@mage.ho.bom.gov.au>
Hannu Krosing wrote:
> Could we have compressed GIF's as well ?
Some correspondence with /F I had once covered this topic. He
approached Unisys about it. He did not come away with warm fuzzies. In
fact, there were going to be serious problems licensing a _free_ package
like PIL. So it's not in there.
> To circumvent the Unisys LZW patent, we could do as xpdf does:
> unix command compress + some converion code ?
>
> It would be a little slower, but probably fast enough for most uses.
I've simply stopped using GIF now in favour of PNG. Unfortunately, the
PNG implementation in PIL is bare-bones, and I'd remedy that if I had the
time (which I will do soon, but it's just one thing on a list...). Also,
the PNG support in WWW browsers is a little bare-bones also --- though it
_is_ there.
And with PNG you have license-free compression and a _bundle_ of other
features GIF probably never even thought of :)
Richard
From Dirk.Engelmann@IWR.Uni-Heidelberg.De Fri Jul 10 09:52:10 1998
From: Dirk.Engelmann@IWR.Uni-Heidelberg.De (Dirk Engelmann)
Date: Fri, 10 Jul 1998 10:52:10 +0200 (CEST)
Subject: [Image-SIG] PIL Wishlist
In-Reply-To: <13733.1106.92053.321533@newcnri.cnri.reston.va.us>
Message-ID:
Hi!
Just to add a point on the wish list:
Once there was a discussion about replacing the fromstring and tostring
method. I would like to have a method which doesn't convert the image
to/from strings, but passes a pointer (or pointer list). The NumPy
library (don't know how it is done exactely) has methods to do this, and
it would be nice to have an efficient access to image data from other
python modules like NumPy.
Cheers,
Dirk
On Thu, 9 Jul 1998, Andrew Kuchling wrote:
> Distilling a wish list from the recent postings, I come up with this:
>
> * RLE format support
>
> * Test pattern generators
>
> * Complement: cutting out strips of an image
>
> * Support for multiple-frame images should be documented;
> there are some demo scripts in Scripts/ (gifmaker.py, explode.py) but
> they're not very well-known.
>
> * There are other font rendering solutions such as t1lib and
> pilfont. t1lib seems too large to add to PIL, but maybe pilfont can
> be added.
>
> * Freetype support
>
> * t1lib
>
> * Clean up and document the SANE interface (my job).
>
> Other suggestions?
>
> --
> A.M. Kuchling http://starship.skyport.net/crew/amk/
> Well, there was this doggy. He was a very clever doggy. He said things like...
> like... "I would feel infinitely more comfortable in your presence if you
> would agree to treat gravity as a law, rather than one of a number of
> suggested options."
> -- Delirium describes her dog Barnabas, in SANDMAN #63: "The Kindly Ones:7"
>
>
> _______________________________________________
> Image-SIG maillist - Image-SIG@python.org
> http://www.python.org/mailman/listinfo/image-sig
>
From fredrik@pythonware.com Fri Jul 10 18:01:03 1998
From: fredrik@pythonware.com (Fredrik Lundh)
Date: Fri, 10 Jul 1998 18:01:03 +0100
Subject: [Image-SIG] Your wish is my command (long)
Message-ID: <025901bdac24$56c43020$f29b12c2@pythonware.com>
lot's of traffic on the image sig...
david> Also, FYI, a new release is promised for tomorrow (Friday),
david> which makes me doubt F/'s claim of a vacation =).
Well, I was away from work yesterday (almost). but the PIL
release might be somewhat delayed -- our local internet provider
messed up their DNS servers, and our website host has messed up
their NFS servers, so I cannot upload the new PIL just yet. they've
promised me that everything will work again later tonight. sigh.
...
in the meantime, here are some comments...
eric> A couple of documentation bugs
Interesting. The PIL docs has been unchanged for about a year,
and suddently three people reports the "Enchance" typo within
two days!
I've changed that; the rest will be taken care of in the next
documentation update.
eric> I think the PIL documentation's use of the term `band' is rather
eric> unfortunate. To a native English speaker, the term `band' applied to
eric> a graphic has a strong primary meaning which is different from PIL's;
eric> that of a stripe or region (especially a horizontal one) extending the
eric> full width of the image.
Well, the term "band" is actually take from an ISO 12087, which AFAIK is
the only international standard discussing image processing libraries...
there's a few other historical things in PIL, including the name "mode" for
the pixel format, the string "L" for greyscale images, etc. All these might
be debatable, but I think changing it would cause as much confusion as
keeping it as it is.
eric> I announced this to a group that included Guido. He steered me to
eric> PIL. PIL is very impressive
We're pretty impressed ourselves -- people have built some really
awesome applications on top of PIL... (if my old bosses had known
how many commercial applications people have built on PIL, they
wouldn't have allowed me to give it away... on the other hand,
they've using it themselves, so they shouldn't complain ;-)
eric> so much so that I think it will enable
eric> me to officially declare the utilities in GIFLIB obsolete (but not the
eric> library; that's a separate issue to which I'll return below).
Are you going to write a new set of utilities based on PIL, or will
you abandon GIFLIB completely? The reason I'm asking is that some of
the missing stuff should probably be implemented on top of the existing
functionality, rather than added to the core library (I don't mind shipping
such utilities with PIL, of course).
eric> Allow an optional argument in show() specifying the viewer
eric> command to use.
I'll do something about this in the next release (not 0.3b1).
eric> 1. No ability to display images using (a) the Borland BGI driver,
eric> (b) an Epson printer, (c) a Hercules graphics card. I think we
eric> can safely write these off as obsolete, however.
Last time I wrote a Hercules driver was ten years ago. We had
trouble finding a card testing it on...
eric> 2. No ability to handle RLE (Utah raster toolkit) images. I'm not
eric> too worried about this, either. Is anybody still using it?
andrew> * RLE format support
Well, show me anyone using the Utah RLE format (or the Utah
raster toolkit, for that matter). If you find anyone, tell him/her
to send me some samples and a spec, and I'll see what I can do...
(afaik, the Utah stuff is about as obsolete as the Hercules mono-
chrome graphics adapter).
(PIL already supports a few other RLE formats, btw).
eric> 3. No equivalent of the gifbg, gifwedge, and gifcolor test pattern
eric> generators. These would probably be trivial to write.
andrew> * Test pattern generators
There's one undocumented generator available in the Image module:
im = Image._wedge()
This generates a 256x256 greyscale wedge. Use convert, resize,
and rotate/transpose to process it anyway you want.
There's in fact a few more generators in the libImaging code; see
the Fill.c and Effects.c sources for details. Still haven't made up
my mind on how/if those should be exposed...
The other patterns provided by GIFLIB should be pretty straight-
forward to implement using the ImageDraw module. Best done
in a utility.
eric> 4. (Serious) I see no way to overlay text on an image. I can supply a
eric> clean 8x8 font and code for ImageDraw to overlay messages on an image
eric> using it. Later this method could be extended to support fonts from
eric> an X font server. Is this sort of thing what the missing ImageFont
eric> module is about?
Yep. Todays 0.3b1 release includes the "pilfont" package which contains
converters for PCF and BDF raster fonts. See the sources for details.
More font info below.
eric> 5. (Serious) There's no equivalent of the `clip complement' feature in
eric> giflclip. Here's the GIF description:
andrew> * Complement: cutting out strips of an image
Well, it takes about five lines of code to implement this (one new,
followed by four crop/paste operations). So again, I don't think PIL
needs to be modified. Better done in a utility.
eric> 6. I see no standard function or method for composing multiple images into a
eric> multi-file image in formats like GIF. (The gifovly utility in GIFLIB
eric> does this.)
andrew> * Support for multiple-frame images should be documented;
andrew>there are some demo scripts in Scripts/ (gifmaker.py, explode.py) but
andrew>they're not very well-known.
The seek/tell methods that can be used to read multiple-frame formats
are documented (they work for at least GIF, FLI/FLC, and TIFF, plus the
lesser known ARG and IM formats). Also see the ImageSequence module.
To write GIF animations, you can import "gifmaker" and use the
"makedelta" method on a list of images. See the source for details.
Adding a general mechanism that works with more formats is harder;
the best way is to redesign the save plugin interface (there's other
reasons for this), but there's no way to do that in time for 0.3 final.
Maybe in 0.4 (aka 1.0).
eric> 7. (Serious) There doesn't seem to be any way to specify interlacing or the
eric> screen size on GIF output (GIFLIB's gifinter and gifpos utilities).
I just added interlace write support; it's in the 0.3b1 release. If you
have the time, patches for screen size (and other relevant options)
would be welcome.
eric> 8. No utility to section an image into tiles (gifburst).
eric> 9. No equivalent of my icon2gif utility (see
eric> http://www.tuxedo.org/~esr/giflib/doc/icon2gif.html
eric>). Never mind, this is very GIF-specific.
Shouldn't be hard to write utilities for these (crop/paste are your
best friends).
eric> If I hack in some of these things, can I stimulate a PIL release to
eric> replace GIFLIB?
If you do it as a set of utilities, I'll ship them with the next release.
If there's anything you want to change in the core library, let's discuss
that case for case.
...
Now to the remaining points on Andrew's wishlist:
andrew> * There are other font rendering solutions such as t1lib and
andrew>pilfont. t1lib seems too large to add to PIL, but maybe pilfont can
andrew>be added.
the pilfont stuff is included in 0.3b1. This includes the pilfont "compiler",
and the upgraded ImageFont module.
andrew> * Freetype support
andrew> * t1lib
Fred's written a t1lib interface, and I'm waiting for someone (you know
who you are!) to release his freetype interface... when that's out, and
I find some spare time, I'll try to come up with a unified raster font
interface. It would include:
-- a font registry
-- a font selection mechanism (something similar to tkFont,
most likely)
-- some optimizations in PIL (the current ImageFont implementation
is pretty gross...)
andrew> * Clean up and document the SANE interface (my job).
The current release is shipped with 0.3b1; it would be great to have
the updated interface in time for the final 0.3 release (nudge, nudge)
...
More wishes:
kevin> How about additional file formats like YUV, UYVY.
Is this the SGI flavour? There appears to be no shortage of formats
calling themselves YUV -- and they all use different resampling and
colour weights...
PIL 0.3b1 adds direct support for YCrCb (the JFIF flavour: CCIR 601-1
without chroma headroom). It can also read PhotoYCC via the PCD
decoder. Other YUV versions can be read as RGB, and converted via
the matrix option to the convert method (see the manual for details).
Anyway, if you have specs and samples for the SGI version, just
send them to me, and I'll add support if I can.
kevin> Or using ImageMagick to convert to formats PIL can understand.
Zach Roadhouse has written an ImageMagick interface for Python,
which includes a PIL interface.
http://starship.skyport.net/crew/zack/pymagick/
http://starship.skyport.net/crew/zack/pymagick/#pil
hannu> Could we have compressed GIF's as well ?
hannu> To circumvent the Unisys LZW patent, we could do as xpdf
hannu> does: unix command compress + some converion code ?
PIL reads compressed GIF files. The Ghostscript folks have researched
this, and all the experts they consulted claimed that Unisys' LZW patent
cannot prevent you from doing this (on the other hand, most experts
claim that Unisys' patent is moot anyway since IBM also happens to have
a patent on the same thing... and on the third hand, Unisys' LZW patent
isn't valid in Sweden anyway ;-). Also note that you can disable all kinds
of LZW support via the WITH_LZW option in _imaging.c.
When writing GIF files, PIL uses a simpleminded encoding that, by some
odd reason, LZW decoders have no trouble reading. To write compressed
GIF files, there are a number of options:
-- install NETPBM, and hack GifImagePlugin so it uses _save_ppm instead
of _save (just remove "_ppm" from the latter).
-- write an _imaging_gif module that takes a PIL image and writes
a GIF version of it. how you implement that is up to you...
Unfortunately, I don't think you can use compress to write GIF files; most
compress implementations use something called "deferred clear codes" to
get better compression. This is explicitly allowed by the GIF specification,
but nobody seems to get that right. For example, Navigator 2 and 3 bombs
if you give them such files (don't know if it's fixed in version 4). FWIW,
Internet Explorer has always handled them just fine, though...
richard> Unfortunately, the PNG implementation in PIL is bare-bones,
richard> and I'd remedy that if I had the time (which I will do soon,
richard> but it's just one thing on a list...).
What do you have in mind here? The only thing I can think of is that the
current implementation doesn't support interlaced PNG's (patches are wel-
come). What else have I missed?
dirk> Once there was a discussion about replacing the fromstring and
dirk> tostring method. I would like to have a method which doesn't
dirk> convert the image to/from strings, but passes a pointer (or pointer
dirk> list). The NumPy library (don't know how it is done exactely) has
dirk> methods to do this, and it would be nice to have an efficient
dirk> access to image data from other python modules like NumPy.
Hey, I didn't know that Python had support for pointers ;-)
I don't use NumPy myself (I have colleagues that do, but they haven't
told me about that feature -- maybe they haven't looked close enough).
Can any NumPy guru explain this? For example, it would be trivial
to add a method that returns a list of long integers, each pointing
to the beginning of a line. For small images, there's actually a way
to do this today:
im.load()
ptr = im.im.isblock()
If ptr is non-zero, it's a pointer to the first byte in the image memory.
...
that's all for today. now I'm off to see armageddon. the PIL sources
might make it to our site later tonight. stay tuned.
Cheers /F
From Fred L. Drake, Jr."
References: <025901bdac24$56c43020$f29b12c2@pythonware.com>
Message-ID: <13734.15205.788715.987342@weyr.cnri.reston.va.us>
Fredrik Lundh writes:
> richard> Unfortunately, the PNG implementation in PIL is bare-bones,
> richard> and I'd remedy that if I had the time (which I will do soon,
> richard> but it's just one thing on a list...).
>
> What do you have in mind here? The only thing I can think of is that the
> current implementation doesn't support interlaced PNG's (patches are wel-
> come). What else have I missed?
I have some patches for the PNG support that I'll send in as soon as
I have a chance to clean it up a little. It adds support for some
additional chunk types and changes the handling of tEXt chunks a
little. I'll describe it in more detail when I post the patch.
(Probably next week sometime.)
-Fred
--
Fred L. Drake, Jr.
Corporation for National Research Initiatives
1895 Preston White Dr. Reston, VA 20191
From esr@snark.thyrsus.com Fri Jul 10 18:54:07 1998
From: esr@snark.thyrsus.com (Eric S. Raymond)
Date: Fri, 10 Jul 1998 13:54:07 -0400
Subject: [Image-SIG] Re: Your wish is my command (long)
In-Reply-To: <025901bdac24$56c43020$f29b12c2@pythonware.com>; from Fredrik Lundh on Fri, Jul 10, 1998 at 06:01:03PM +0100
References: <025901bdac24$56c43020$f29b12c2@pythonware.com>
Message-ID: <19980710135407.A6888@snark.thyrsus.com>
Fredrik Lundh :
> eric> I think the PIL documentation's use of the term `band' is rather
> eric> unfortunate. To a native English speaker, the term `band' applied to
> eric> a graphic has a strong primary meaning which is different from PIL's;
> eric> that of a stripe or region (especially a horizontal one) extending the
> eric> full width of the image.
>
> Well, the term "band" is actually take from an ISO 12087, which AFAIK is
> the only international standard discussing image processing libraries...
> there's a few other historical things in PIL, including the name "mode" for
> the pixel format, the string "L" for greyscale images, etc.
That explains it. ISO 12087 was probably composed in French. I bet you
that `band' is a literal translation of a French word by someone who didn't
know what a connotative mess he was making. Please don't propagate this
error.
> All these might
> be debatable, but I think changing it would cause as much confusion as
> keeping it as it is.
Depends on whether you think your "market" is mostly English-speaking.
If so, I would strongly recommend "band" -> "channel".
> Are you going to write a new set of utilities based on PIL, or will
> you abandon GIFLIB completely? The reason I'm asking is that some of
> the missing stuff should probably be implemented on top of the existing
> functionality, rather than added to the core library (I don't mind shipping
> such utilities with PIL, of course).
What I'm planning (and have in fact already started writing) is a Python script
called `pildriver' which allows the user to specify a pipeline of PIL image
transformations by specifying command-line switches.
The intention is that it should take an image stream on stdin and emit an
image stream on stdout. Usage like this:
pildriver eric> Allow an optional argument in show() specifying the viewer
> eric> command to use.
>
> I'll do something about this in the next release (not 0.3b1).
Actually I have another show method change for you. For pipeline-construction
purposes, automatically backgrounding the image display is not the right
thing. So:
--- Image.py 1998/07/10 05:25:57 1.1
+++ Image.py 1998/07/10 16:34:05
@@ -823,7 +823,7 @@
# --------------------------------------------------------------------
# Unix display support
-def _showxv(self, title = None):
+def _showxv(self, background=0, title=None):
if self.mode == "P":
file = self.convert("RGB")._dump()
@@ -835,4 +835,7 @@
else:
opt = ""
- os.system("(xv %s %s; rm -f %s)&" % (opt, file, file))
+ command = "xv %s %s && rm -f %s" % (opt, file, file)
+ if background:
+ command = "(%s)&" (command,)
+ os.system(command)
> eric> 1. No ability to display images using (a) the Borland BGI driver,
> eric> (b) an Epson printer, (c) a Hercules graphics card. I think we
> eric> can safely write these off as obsolete, however.
>
> Last time I wrote a Hercules driver was ten years ago. We had
> trouble finding a card testing it on...
OK, we can agree to forget this.
> eric> 2. No ability to handle RLE (Utah raster toolkit) images. I'm not
> eric> too worried about this, either. Is anybody still using it?
>
> andrew> * RLE format support
>
> Well, show me anyone using the Utah RLE format (or the Utah
> raster toolkit, for that matter). If you find anyone, tell him/her
> to send me some samples and a spec, and I'll see what I can do...
>
> (afaik, the Utah stuff is about as obsolete as the Hercules mono-
> chrome graphics adapter).
You're probably right. As I said, I'm not going to worry about it.
GIFLIB dates from '89; I started maintaining it around '91. There's
a lot of stuff in there that's now only of historical interest.
> eric> 3. No equivalent of the gifbg, gifwedge, and gifcolor test pattern
> eric> generators. These would probably be trivial to write.
>
> andrew> * Test pattern generators
>
> There's one undocumented generator available in the Image module:
>
> im = Image._wedge()
>
> This generates a 256x256 greyscale wedge. Use convert, resize,
> and rotate/transpose to process it anyway you want.
>
> There's in fact a few more generators in the libImaging code; see
> the Fill.c and Effects.c sources for details. Still haven't made up
> my mind on how/if those should be exposed...
>
> The other patterns provided by GIFLIB should be pretty straight-
> forward to implement using the ImageDraw module. Best done
> in a utility.
I agree.
> eric> 4. (Serious) I see no way to overlay text on an image. I can supply a
> eric> clean 8x8 font and code for ImageDraw to overlay messages on an image
> eric> using it. Later this method could be extended to support fonts from
> eric> an X font server. Is this sort of thing what the missing ImageFont
> eric> module is about?
>
> Yep. Todays 0.3b1 release includes the "pilfont" package which contains
> converters for PCF and BDF raster fonts. See the sources for details.
Which brings up a question. Why aren't docs included with the PIL
distribution? The only docs I've found are the (incomplete) PIL
web pages.
> eric> 5. (Serious) There's no equivalent of the `clip complement' feature in
> eric> giflclip. Here's the GIF description:
>
> andrew> * Complement: cutting out strips of an image
>
> Well, it takes about five lines of code to implement this (one new,
> followed by four crop/paste operations). So again, I don't think PIL
> needs to be modified. Better done in a utility.
OK, I can live with this.
> eric> 6. I see no standard function or method for composing multiple images
> eric> into a multi-file image in formats like GIF. (The gifovly utility in
> eric> GIFLIB does this.)
>
> andrew> * Support for multiple-frame images should be documented;
> andrew>there are some demo scripts in Scripts/ (gifmaker.py, explode.py) but
> andrew>they're not very well-known.
>
[...]
> Adding a general mechanism that works with more formats is harder;
> the best way is to redesign the save plugin interface (there's other
> reasons for this), but there's no way to do that in time for 0.3 final.
> Maybe in 0.4 (aka 1.0).
Yes, I'd figured this out myself. It's not an immediate issue for me, but
I'm glad to know it's on the to-doi list.
> eric> 7. (Serious) There doesn't seem to be any way to specify interlacing
> eric> or the screen size on GIF output (GIFLIB's gifinter and gifpos
> utilities).
>
> I just added interlace write support; it's in the 0.3b1 release. If you
> have the time, patches for screen size (and other relevant options)
> would be welcome.
I'll look into that once I get the new release.
> eric> 8. No utility to section an image into tiles (gifburst).
>
> eric> 9. No equivalent of my icon2gif utility (see
> eric> http://www.tuxedo.org/~esr/giflib/doc/icon2gif.html
> eric>). Never mind, this is very GIF-specific.
>
> Shouldn't be hard to write utilities for these (crop/paste are your
> best friends).
True.
> eric> If I hack in some of these things, can I stimulate a PIL release to
> eric> replace GIFLIB?
>
> If you do it as a set of utilities, I'll ship them with the next release.
> If there's anything you want to change in the core library, let's discuss
> that case for case.
OK, what I'll do is put together pildriver for the next release.
--
Eric S. Raymond
According to the National Crime Survey administered by the Bureau of
the Census and the National Institute of Justice, it was found that
only 12 percent of those who use a gun to resist assault are injured,
as are 17 percent of those who use a gun to resist robbery. These
percentages are 27 and 25 percent, respectively, if they passively
comply with the felon's demands. Three times as many were injured if
they used other means of resistance.
-- G. Kleck, "Policy Lessons from Recent Gun Control Research,"
From akuchlin@cnri.reston.va.us Fri Jul 10 22:06:56 1998
From: akuchlin@cnri.reston.va.us (Andrew Kuchling)
Date: Fri, 10 Jul 1998 17:06:56 -0400 (EDT)
Subject: [Image-SIG] Re: Your wish is my command (long)
In-Reply-To: <19980710135407.A6888@snark.thyrsus.com>
References: <025901bdac24$56c43020$f29b12c2@pythonware.com>
<19980710135407.A6888@snark.thyrsus.com>
Message-ID: <13734.32935.3371.768238@newcnri.cnri.reston.va.us>
Fredrik Lundh writes:
Eric S. Raymond writes:
>That explains it. ISO 12087 was probably composed in French. I bet you
>that `band' is a literal translation of a French word by someone who didn't
>know what a connotative mess he was making. Please don't propagate this
>error.
If we're taking a vote, I quite agree; the usage of 'band'
seemed strange to me when I read the documentation, and I kept having
to substitute 'channel' for it.
>-def _showxv(self, title = None):
>+def _showxv(self, background=0, title=None):
Better to exchange the two arguments in this patch; that won't
break any code which does X._showxv("foo.gif")
>Which brings up a question. Why aren't docs included with the PIL
>distribution? The only docs I've found are the (incomplete) PIL
>web pages.
Fredrik, I'd be willing to help convert the docs to LaTeX if
that would be helpful.
>OK, what I'll do is put together pildriver for the next release.
Bet that'll be misread as 'piledriver' a lot. :)
--
A.M. Kuchling http://starship.skyport.net/crew/amk/
"They never liked us, did they?"
"Gods don't 'like'. They love and they hate and they ignore."
-- Stheno and Euryale, in SANDMAN #61: "The Kindly Ones:5"
From esr@snark.thyrsus.com Fri Jul 10 22:47:40 1998
From: esr@snark.thyrsus.com (Eric S. Raymond)
Date: Fri, 10 Jul 1998 17:47:40 -0400
Subject: [Image-SIG] Re: Your wish is my command (long)
In-Reply-To: <13734.32935.3371.768238@newcnri.cnri.reston.va.us>; from Andrew Kuchling on Fri, Jul 10, 1998 at 05:06:56PM -0400
References: <025901bdac24$56c43020$f29b12c2@pythonware.com> <19980710135407.A6888@snark.thyrsus.com> <13734.32935.3371.768238@newcnri.cnri.reston.va.us>
Message-ID: <19980710174740.A7170@snark.thyrsus.com>
Andrew Kuchling :
> >-def _showxv(self, title = None):
> >+def _showxv(self, background=0, title=None):
>
> Better to exchange the two arguments in this patch; that won't
> break any code which does X._showxv("foo.gif")
I can live with that.
> >Which brings up a question. Why aren't docs included with the PIL
> >distribution? The only docs I've found are the (incomplete) PIL
> >web pages.
>
> Fredrik, I'd be willing to help convert the docs to LaTeX if
> that would be helpful.
And I'm willing to document what I do, and help edit other peoples'
docs, provided I know what the master format is.
> >OK, what I'll do is put together pildriver for the next release.
>
> Bet that'll be misread as 'piledriver' a lot. :)
The play on words was intentional. It should have occurred to me that
it might be a misfeature...
--
Eric S. Raymond
There's a truism that the road to Hell is often paved with good intentions.
The corollary is that evil is best known not by its motives but by its
*methods*.
From fredrik@pythonware.com Fri Jul 10 23:49:34 1998
From: fredrik@pythonware.com (Fredrik Lundh)
Date: Fri, 10 Jul 1998 23:49:34 +0100
Subject: [Image-SIG] ANN: PIL 0.3b1 is out
Message-ID: <04fc01bdac55$04158a00$f29b12c2@pythonware.com>
This is the first, and hopefully only beta release for PIL 0.3. The
source kit has been built and tested on Windows 95 and NT, as well
as on Linux (Redhat 4.2) and Digital Unix. It should build out of the
box on most mainstream Unix versions.
Get your copy of the sources from:
http://www.pythonware.com
Note: Some minor changes were made to the sources between the
py15 binary release and the source release. A new py15 kit will be
released as soon as our py15 wranglers get back from their vacation.
--the PIL team
special thanks to: the image sig folks and massive attack
no thanks to: algonet, lejonet, and michael bay (who all
worked really hard to ruin our day).
From Anthony Baxter Sat Jul 11 02:09:11 1998
From: Anthony Baxter (Anthony Baxter)
Date: Sat, 11 Jul 1998 11:09:11 +1000
Subject: [Image-SIG] initial PIL 0.3b1 compile notes.
In-Reply-To: Your message of "Fri, 10 Jul 1998 18:01:03 +0100."
<025901bdac24$56c43020$f29b12c2@pythonware.com>
Message-ID: <199807110109.LAA06086@koro.off.connect.com.au>
Following are random notes from building PIL on Solaris 2.5.1.
had some annoyances with libImaging, caused by libz being a shared library,
and configure's stupidity in not adding the library given by --with-zlib
to either a -R option, or LD_LIBRARY_PATH. I'd also like to see the hardcoded:
JPEGINCLUDE= /usr/local/include
removed from Makefile.in, and made an option to configure...
The README file talks about a "test" directory - this doesn't seem to
be in the distribution - neither does the "Lib" directory.
ImageFont still seems to be broken - I'll put more about this in a
seperate message...
Other things I'd like to see added/fixed in PIL [1]
I'd like to see it made a package - right now, you can either rebuild
your python interpreter to set a new sys.path, or dump all the files in
the site directory. ew.
Can the "pilplot" package (which I picked up from Fredrik somewhere along
the line) be added to the standard distribution?
Enough for now,
Anthony
[1] and which, given an infinite supply of round tuits, I'd fix myself
From arb@connect.com.au Sat Jul 11 05:07:26 1998
From: arb@connect.com.au (Anthony Baxter)
Date: Sat, 11 Jul 1998 14:07:26 +1000
Subject: [Image-SIG] more on ImageFont.
Message-ID: <199807110407.OAA17101@koro.off.connect.com.au>
Ok, as of 0.3b1, I canna get ImageFont to do anything but error. I've tried
regenerating the .pil font files, and I've even dug into the C source code
(horrors).
File "test", line 10, in text
m=self.font.getmask(text)
File "/opt/python/lib/python1.5.1/site/ImageFont.py", line 87, in getmask
im.im.paste(self.image.im.crop(tuple(m[6:10])),
SystemError: NULL result without error in call_object
Breaking this down into
tmp2 = tuple(m[6:10]) # tmp2 = (55, 0, 59, 7)
tmp = self.image.im.crop(tmp2)
im.im.paste(tmp, (x0+x, y0, x1+x, y1))
shows the error occurs on the "crop()" line.
The problem appears to be in libImaging/Crop.c, in the ImagingCrop function.
This section of code was added between 0.2b3 and 0.3something. I'm stuffed
if I can figure out what it's meant to do, or how it's meant to work properly.
ifdef'ing this section out at least makes the getmask() calls seem to work.
Anyone know what it's meant to do?
/* Determine which region to copy */
xoff = yoff = 0;
if (x0 < 0)
xsize += x0, xoff = -x0, x0 = 0;
if (x0 + xsize > imOut->xsize)
xsize = imOut->xsize - x0;
if (y0 < 0)
ysize += y0, yoff = -y0, y0 = 0;
if (y0 + ysize > imOut->ysize)
ysize = imOut->ysize - y0;
if (xsize <= 0 || ysize <= 0)
return 0;
Anthony
From lorenzo@argon.roma2.infn.it Sun Jul 12 13:44:38 1998
From: lorenzo@argon.roma2.infn.it (Lorenzo M. Catucci)
Date: Sun, 12 Jul 1998 14:44:38 +0200 (CEST)
Subject: [Image-SIG] Latest PIL and tiff class F
Message-ID:
Now,
I can understand the reason why fredrick prefers a pure python
solution as long as it is feasible, and see there have been added as
supported tags the ones for g3 and g4 fax formats, but still there is no
support for the image format. I tried reading the class F docs, but got to
nowhere, confused by 1d, 2d compression, references to T.4 and T.6, and
the like. Worst of all, I'm unable to capitalise onto pymagick's tiff
reading, since it just ignores the density/resolution tags, which are in
between the most needed for me... Help,
lorenzo
PS How did you manage to have PIL installed just before midnight, /F? It
seems all of that problems you talk about your ISP were simply a way to
warm up our appetite, and put us on hold just until the end of the day!
From arb@connect.com.au Sun Jul 12 13:54:27 1998
From: arb@connect.com.au (Anthony Baxter)
Date: Sun, 12 Jul 1998 22:54:27 +1000
Subject: [Image-SIG] tiny no-brainer patch for pilconvert.py
Message-ID: <199807121254.WAA07697@koro.off.connect.com.au>
This makes the -f flag work.
*** pilconvert.py.orig Sun Jul 12 22:52:48 1998
--- pilconvert.py Sun Jul 12 22:53:00 1998
***************
*** 38,44 ****
usage()
try:
! opt, argv = getopt.getopt(sys.argv[1:], "dc:gopq:r")
except getopt.error, v:
print v
sys.exit(1)
--- 38,44 ----
usage()
try:
! opt, argv = getopt.getopt(sys.argv[1:], "dc:gopq:rf")
except getopt.error, v:
print v
sys.exit(1)
***************
*** 52,57 ****
--- 52,58 ----
if o == "-f":
Image.init()
+ id = Image.ID[:]
id.sort()
print "Supported formats:"
for i in id:
From richard.jones@BoM.GOV.AU Mon Jul 13 02:11:56 1998
From: richard.jones@BoM.GOV.AU (Richard Jones)
Date: Mon, 13 Jul 1998 01:11:56 +0000
Subject: [Image-SIG] initial PIL 0.3b1 compile notes.
In-Reply-To: Message from Anthony Baxter of 1998-Jul-11 11:9:11,
<199807110109.LAA06086@koro.off.connect.com.au>
Message-ID: <199807130111.BAA05067@mage.ho.bom.gov.au>
Anthony Baxter wrote:
> Following are random notes from building PIL on Solaris 2.5.1.
I'm on HPUX 10.20.
> had some annoyances with libImaging, caused by libz being a shared library,
> and configure's stupidity in not adding the library given by --with-zlib
> to either a -R option, or LD_LIBRARY_PATH.
Yeh, I end up linking statically to get around these hassles.
> I'd also like to see the hardcoded:
> JPEGINCLUDE= /usr/local/include
> removed from Makefile.in, and made an option to configure...
Yeh, the configure and make really only seems to work (I assume) if
the jpeg and zlib libraries are in /usr/local or in the system path
somewhere, and therefore aren't reliant upon configure command-line
options. For example, my configure line of:
configure --with-jpeg=/opt/jpeg-6 --with-zlib=/opt/zlib-1.1.2
doesn't work. (Note that I'm on HPUX and the configure line is also
prefixed with CC="cc -Aa -D_HPUX_SOURCE" *blech*).
Anyway, I'm back to editing the Makefile by hand just like The Old
Days :)
Does anyone know the appropriate configure magic to make this work?
Richard
From richard.jones@BoM.GOV.AU Mon Jul 13 02:36:00 1998
From: richard.jones@BoM.GOV.AU (Richard Jones)
Date: Mon, 13 Jul 1998 01:36:00 +0000
Subject: [Image-SIG] initial PIL 0.3b1 compile notes.
In-Reply-To: Message from Richard Jones of 1998-Jul-13 1:11:56,
<199807130111.BAA05067@mage.ho.bom.gov.au>
Message-ID: <199807130136.BAA06171@mage.ho.bom.gov.au>
Richard Jones wrote:
> Anthony Baxter wrote:
> > Following are random notes from building PIL on Solaris 2.5.1.
>
> I'm on HPUX 10.20.
>
> > I'd also like to see the hardcoded:
> > JPEGINCLUDE= /usr/local/include
> > removed from Makefile.in, and made an option to configure...
>
> Yeh, the configure and make really only seems to work (I assume) if
> the jpeg and zlib libraries are in /usr/local or in the system path
> somewhere, and therefore aren't reliant upon configure command-line
> options. For example, my configure line of:
>
> configure --with-jpeg=/opt/jpeg-6 --with-zlib=/opt/zlib-1.1.2
>
> doesn't work. (Note that I'm on HPUX and the configure line is also
> prefixed with CC="cc -Aa -D_HPUX_SOURCE" *blech*).
Make that "cc +z -Aa -D_HPUX_SOURCE" in libImaging to produce PIC
objects.
Is there any way that the configure in there could pick up stuff from
the Python install since it figures most of this platform-specific stuff
out (except of course the library location stuff).
Also, the mmap test fails for reasons unknown to me. config.log
doesn't have any error messages. I tried compiling and running the source
from config.log (I had to remove confdefs.h since I don't know how to
recreate it) and it seemed to work fine...
HPUX 10.20 mmap man page says:
STANDARDS CONFORMANCE
mmap(): AES, SVID3
for whatever that's worth...
Richard
From fredrik@pythonware.com Thu Jul 16 17:56:45 1998
From: fredrik@pythonware.com (Fredrik Lundh)
Date: Thu, 16 Jul 1998 17:56:45 +0100
Subject: [Image-SIG] more on ImageFont.
Message-ID: <024f01bdb0db$17a704b0$f29b12c2@pythonware.com>
Anthony Baxter wrote:
>Ok, as of 0.3b1, I canna get ImageFont to do anything but error. I've tried
>regenerating the .pil font files, and I've even dug into the C source code
>(horrors).
As I've told Anthony in private mail, this is because we missed
a file when we added pilfont to the 0.3b1 release. And by some
odd reason, the ImageDraw text method wasn't covered by PIL's
test suite...
Expect an 0.3b2 release any day soon (friday or saturday, most
likely), with the following changes:
-- working font support
-- YCbCr instead of YCrCb! (to avoid more headaches...)
-- the "offset" method now works for GIF and IM images
-- support for 16-bit PNG files (read/written as mode "I")
Cheers /F
fredrik@pythonware.com
http://www.pythonware.com
From fredrik@pythonware.com Thu Jul 16 17:50:19 1998
From: fredrik@pythonware.com (Fredrik Lundh)
Date: Thu, 16 Jul 1998 17:50:19 +0100
Subject: [Image-SIG] Re: Your wish is my command (long)
Message-ID: <024e01bdb0db$178e9ab0$f29b12c2@pythonware.com>
>> Well, the term "band" is actually take from an ISO 12087, which AFAIK is
>> the only international standard discussing image processing libraries...
>> there's a few other historical things in PIL, including the name "mode" for
>> the pixel format, the string "L" for greyscale images, etc.
>
>That explains it. ISO 12087 was probably composed in French. I bet you
>that `band' is a literal translation of a French word by someone who didn't
>know what a connotative mess he was making. Please don't propagate this
>error.
Nope. This has nothing to do with weird european languages; it's more
of an "image processing" vs. "computer graphics" issue.
Image processing folks (like me) usually get their images from some kind of
sensor (usually an RGB scanner or camera, but there's many other sources).
And most sensors have bandpass characteristics, so the term "band" is more
accurate than "channel"...
If you still think this is a european plot, take a look at XIE (X's Image
Extension, designed by 100% americans), or XIL (Sun's Image Processing
Library). Or look at your nearest remote sensing FAQ; it should explain
acronyms like:
BIP, Band Interleaved by Pixel
BIL, Band Interleaved by Line
BSQ, Band SeQuential
IMHO, the term "band" is much more well-defined in the image processing
universe than words like "object", "instance", "type", and "garbage collection"
are in the programming universe...
Cheers /F
fredrik@pythonware.com
http://www.pythonware.com
From fredrik@pythonware.com Thu Jul 16 18:43:02 1998
From: fredrik@pythonware.com (Fredrik Lundh)
Date: Thu, 16 Jul 1998 18:43:02 +0100
Subject: [Image-SIG] Re: Your wish is my command (long)
Message-ID: <02e601bdb0e1$329508c0$f29b12c2@pythonware.com>
>Implementation problem: I don't see how to read an image from a file stream
>object. ImageFileIO isn't documented and I can't find the code.
(Sigh. I really thought I'd eliminated all traces of ImageFileIO
from the docs...)
This question is a bit trickier than it sounds, since many formats
require random access to the image data. Here's how I would do
it:
-- create a file-like class which wraps a file object, and
provides read, seek, and tell methods. this class should
also keep track of the current file position.
-- the read method calls "read" for the underlying file object,
and updates the current position.
-- the seek method returns immediately if the caller seeked
to the current position.
if the wrapped file object is seekable, call "seek" as usual
and update the current position.
if the wrapped file object is not seekable, skip data if the
caller seeked beyond the current position, and raise a suitable
exception otherwise.
-- the tell method returns the current position.
Then wrap sys.stdin in an object of this kind, and pass it to
Image.open. If PIL can read the image in streaming mode,
it will. Otherwise, you'll get an exception.
Cheers /F
fredrik@pythonware.com
http://www.pythonware.com
From dcs@lems.brown.edu Fri Jul 17 19:14:42 1998
From: dcs@lems.brown.edu (Daniel C. Sokoloff)
Date: Fri, 17 Jul 1998 14:14:42 -0400
Subject: [Image-SIG] PythonMagick on NT
Message-ID: <35AF9492.511@lems.brown.edu>
Hello,
I am wondering if anyone has worked at getting ImageMagick or
PythonMagick running on a Windows NT system. I am trying to port a
graphic manipulation program from unix to NT and the problem has been
with ImageMagick (not directly portable, had to get NT binaries).
Otherwise, are there any other imaging packages for NT that work with
PIL?
thanks,
Dan.
From esr@snark.thyrsus.com Sat Jul 18 17:08:48 1998
From: esr@snark.thyrsus.com (Eric S. Raymond)
Date: Sat, 18 Jul 1998 12:08:48 -0400
Subject: [Image-SIG] Proof-of-concept version of pildriver
Message-ID: <19980718120848.A27192@snark.thyrsus.com>
--ibTvN161/egqYuK8
Content-Type: text/plain; charset=us-ascii
Here's the first alpha version. It's not complete, and there are some
things in it that don't yet work right (either due to underlying PIL
problems or because I don't understand intended usage). It should
demonstrate, however, that pildriver has the potential to replace
several of the ad-hoc scripts in the present distribution with a
single simple utility that serves as an image batch processor, a test
driver, and a tutorial exerciser.
I'd have documented this, but I don't know what the preferred
format for PIL documentation is, or if there is one.
Feedback, comments, and corrections are solicited.
--
Eric S. Raymond
To make inexpensive guns impossible to get is to say that you're
putting a money test on getting a gun. It's racism in its worst form.
-- Roy Innis, president of the Congress of Racial Equality (CORE), 1988
--ibTvN161/egqYuK8
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=pildriver
#!/usr/bin/env python
#
# pildriver -- an image-processing calculator for PIL
#
# by Eric S. Raymond
# $Id: pildriver,v 1.1 1998/07/18 16:08:25 esr Exp $
#
# This is essentially a Polish-notation interpreter for sequencing
# PIL image transformations. All operations consume their arguments
# off the stack (use `dup' to keep copies around). Use `verbose 1`
# to see the stack state before each operation.
#
# PILDriver doesn't catch any exceptions, on the theory that these
# are actually diagnostic information that should be interpreted by
# the calling code.
#
# TO DO:
# 1. Add PILFont capabilities, once that's documented.
# 2. Add PILDraw operations.
# 3. Add support for composing and decomposing multiple-image files.
#
import Image, string
class PILDriver:
verbose = 0
def do_verbose(self):
# Set verbosity flag from top of stack
self.verbose = self.do_pop()
# The evaluation stack (internal only)
stack = [] # Stack of pending operations
def push(self, item):
# Push an argument onto the stack
self.stack = [item] + self.stack
def top(self):
# Return the top-of-stack element
return self.stack[0]
# Stack manipulation (callable)
def do_clear(self):
# Clear the stack
self.stack = []
def do_pop(self):
# Pop (and return) the top element on the stack
top = self.stack[0]
self.stack = self.stack[1:]
return top
def do_dup(self):
# Duplicate the top-of-stack item
if hasattr(self, 'format'): # If it's an image, do a real copy
dup = self.stack[0].copy()
else:
dup = self.stack[0]
self.stack = [dup] + self.stack
def do_swap(self):
# Swap the top-of-stack item with the next one down
self.stack = [self.stack[1], self.stack[0]] + self.stack[2:]
# Image module functions (callable)
def do_new(self):
# Create a greyscale image of given size and color, push on stack
color = int(self.do_pop())
ysize = int(self.do_pop())
xsize = int(self.do_pop())
self.push(Image.new("L", (xsize, ysize), color))
def do_open(self):
# Open the indicated image, read it, push it on the stack
self.push(Image.open(self.do_pop()))
def do_blend(self):
# Replace two images and an alpha with the blended image
alpha = float(self.do_pop())
image2 = self.do_pop()
image1 = self.do_pop()
self.push(Image.blend(image1, image2, alpha))
def do_composite(self):
# Replace two images and a mask with their composite
mask = self.do_pop()
image2 = self.do_pop()
image1 = self.do_pop()
self.push(Image.composite(image1, image2, mask))
def do_merge(self):
# Merge top-of stack images in a way described by the mode
bandlist = []
mode = self.do_pop()
for band in mode:
bandlist.append(self.do_pop())
bandlist.reverse()
self.push(Image.merge(mode, bandlist))
# Image class methods
def do_convert(self):
# Convert the top image to the given mode
mode = self.do_pop()
image = self.do_pop()
self.push(image.convert(mode))
def do_copy(self):
# Make a true copy of the top image, push it on the stack
self.dup()
def do_crop(self):
# Crop a rectangular region from the current image
lower = int(self.do_pop())
right = int(self.do_pop())
upper = int(self.do_pop())
left = int(self.do_pop())
image = self.do_pop()
self.push(image.crop((left, upper, right, lower)))
def do_draft(self):
# Configure the loader for a given mode
ysize = int(self.do_pop())
xsize = int(self.do_pop())
mode = self.do_pop()
self.push(self.draft(mode, (xsize, ysize)))
def do_filter(self):
# Filter the top image with the given filter
import ImageFilter
filter = eval("ImageFilter." + string.upper(self.do_pop()))
image = self.do_pop()
self.push(image.filter(filter))
def do_offset():
# Offset the top image
yoff = int(self.do_pop())
xoff = int(self.do_pop())
image = self.do_pop()
self.push(image.offset(xoff, yoff))
def do_paste(self):
# Interpret top image as figure, next down as ground
yoff = int(self.do_pop())
xoff = int(self.do_pop())
figure = self.do_pop()
ground = self.do_pop()
if figure.mode == "RGBA":
self.push(ground.paste(figure, (xoff, yoff), figure))
else:
self.push(ground.paste(figure, (xoff, yoff)))
def do_resize(self):
# Resize the top image
ysize = int(self.do_pop())
xsize = int(self.do_pop())
image = self.do_pop()
self.push(image.resize(xsize, ysize))
def do_rotate(self):
# Rotate image through a given angle
angle = int(self.do_pop())
image = self.do_pop()
self.push(image.rotate(angle))
def do_save(self):
# Save image with default options
filename = self.do_pop()
image = self.do_pop()
image.save(filename)
def do_save2(self):
# Save image with specified options
filename = self.do_pop()
options = self.do_pop()
image = self.do_pop()
image.save(filename, None, options)
def do_show(self):
# Display the top image in the stack
self.pop().show()
def do_thumbnail(self):
# Modify the top image in the stack to contain a thumbnail of itself
ysize = int(self.do_pop())
xsize = int(self.do_pop())
self.top().thumbnail((xsize, ysize))
def do_transpose(self):
# Transpose the top image
transpose = string.upper(self.do_pop())
image = self.do_pop()
self.push(image.transpose(transpose))
# Image attributes
def do_format(self):
# Push the format of the top image onto the stack
self.push(self.pop().format)
def do_mode(self):
# Push the mode of the top image onto the stack
self.push(self.pop().mode)
def do_size(self):
# Push the image size on the stack as (y, x)
size = self.pop().size
self.push(size[0])
self.push(size[1])
# ImageChops operations
def do_invert(self):
# Invert the top image
import ImageChops
self.push(ImageChops.invert(self.do_pop()))
def do_lighter(self):
# Pop the two top images, push an image of the lighter pixels of both
import ImageChops
image2 = self.do_pop()
image1 = self.do_pop()
self.push(ImageChops.lighter(image1, image2))
def do_darker(self):
# Pop the two top images, push an image of the darker pixels of both
import ImageChops
image2 = self.do_pop()
image1 = self.do_pop()
self.push(ImageChops.darker(image1, image2))
def do_difference(self):
# Pop the two top images, push the difference image
import ImageChops
image2 = self.do_pop()
image1 = self.do_pop()
self.push(ImageChops.difference(image1, image2))
def do_multiply(self):
# Pop the two top images, push the multiplication image
import ImageChops
image2 = self.do_pop()
image1 = self.do_pop()
self.push(ImageChops.multiply(image1, image2))
def do_screen(self):
# Pop the two top images, superimpose their inverted versions
import ImageChops
image2 = self.do_pop()
image1 = self.do_pop()
self.push(ImageChops.screen(image1, image2))
def do_add(self):
# Pop the two top images, produce the scaled sum with offset
import ImageChops
offset = float(self.do_pop())
scale = float(self.do_pop())
image2 = self.do_pop()
image1 = self.do_pop()
self.push(ImageChops.add(image1, image2, scale, offset))
def do_subtract(self):
# Pop the two top images, produce the scaled difference with offset
import ImageChops
offset = float(self.do_pop())
scale = float(self.do_pop())
image2 = self.do_pop()
image1 = self.do_pop()
self.push(ImageChops.subtract(image1, image2, scale, offset))
# ImageEnhance classes
def do_color(self):
# Enhance color in the top image
import ImageEnhance
factor = float(self.do_pop())
image = self.do_pop()
enhancer = ImageEnhance.Color(image)
self.push(enhancer.enhance(factor))
def do_contrast(self):
# Enhance contrast in the top image
import ImageEnhance
factor = float(self.do_pop())
image = self.do_pop()
enhancer = ImageEnhance.Color(image)
self.push(enhancer.enhance(factor))
def do_brightness(self):
# Enhance brightness in the top image
import ImageEnhance
factor = float(self.do_pop())
image = self.do_pop()
enhancer = ImageEnhance.Color(image)
self.push(enhancer.enhance(factor))
def do_sharpness(self):
# Enhance sharpness in the top image
import ImageEnhance
factor = float(self.do_pop())
image = self.do_pop()
enhancer = ImageEnhance.Color(image)
self.push(enhancer.enhance(factor))
# The interpreter loop
def execute(self, list):
# Interpret a list of PILDriver commands
list.reverse()
while len(list) > 0:
self.push(list[0])
list = list[1:]
if self.verbose:
print "Stack: " + `self.stack`
top = self.top()
if type(top) != type(""):
continue;
funcname = "do_" + top
if not hasattr(self, funcname):
continue
else:
self.do_pop()
func = getattr(self, funcname)
func()
if __name__ == '__main__':
import readline, sys
# If we see command-line arguments, interpret them as a stack state
# and execute. Otherwise go interactive.
driver = PILDriver()
if len(sys.argv[1:]) > 0:
driver.execute(sys.argv[1:])
else:
print "PILDriver says hello"
while 1:
try:
line = raw_input('pildriver> ');
except EOFError:
print "\nPILDriver says goodbye"
break
driver.execute(string.split(line))
print driver.stack
# The following sets edit modes for GNU EMACS
# Local Variables:
# mode:python
# End:
--ibTvN161/egqYuK8--
From esr@snark.thyrsus.com Sun Jul 19 04:52:27 1998
From: esr@snark.thyrsus.com (Eric S. Raymond)
Date: Sat, 18 Jul 1998 23:52:27 -0400
Subject: [Image-SIG] pildriver, take 2
Message-ID: <19980718235227.A27526@snark.thyrsus.com>
--zhXaljGHf11kAtnf
Content-Type: text/plain; charset=us-ascii
Here's a better, more fully documented version incorporating Mike McLay's
suggestions. As before, feedback and comments welcome. With a few simple
tweaks I could take this from interpreting Polish or prefix-operator
notation to reverse-Polish or suffix-operator notation. Is there any
general feeling as to which would be more intuitive?
--
Eric S. Raymond
"Are we to understand," asked the judge, "that you hold your own interests
above the interests of the public?"
"I hold that such a question can never arise except in a society of cannibals."
-- Ayn Rand
--zhXaljGHf11kAtnf
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=pildriver
#!/usr/bin/env python
"""PILDdriver, an image-processing calculator using PIL.
An instance of class PILDriver is essentially a software stack machine
(Polish-notation interpreter) for sequencing PIL image
transformations. The state of the instance is the interpreter stack.
The only method one will normally invoke after initialization is the
`execute' method. This takes an argument list of tokens, pushes them
onto the instance's stack, and then tries to clear the stack by
successive evaluation of PILdriver operators. Any part of the stack
not cleaned off persists and is part of the evaluation context for
the next call of the execute method.
PILDriver doesn't catch any exceptions, on the theory that these
are actually diagnostic information that should be interpreted by
the calling code.
When called as a script, the command-line arguments are passed to
a PILDriver instance. If there are no command-line arguments, the
module runs an interactive interpreter, each line of which is split into
space-separated tokens and passed to the execute method.
In the method descriptions below, a first line beginning with the string
`usage:' means this method can be invokeed with the token that follows
it. Following <>-enclosed arguments describe how the method interprets
the entries on the stack. Each argument specification begins with a
type specification: either `int', `float', `string', or `image'.
All operations consume their arguments off the stack (use `dup' to
keep copies around). Use `verbose 1' to see the stack state displayed
before each operation.
Usage examples:
`show crop 0 0 200 300 open test.png' loads test.png, crops out a portion
of its upper-left-hand corner and displays the cropped portion.
`save rotated.png rotate 30 open test.tiff' loads test.tiff, rotates it
30 degrees, and saves the result as rotated.png (in PNG format).
"""
# by Eric S. Raymond
# $Id: pildriver,v 1.6 1998/07/19 03:45:44 esr Exp $
# TO DO:
# 1. Add PILFont capabilities, once that's documented.
# 2. Add PILDraw operations.
# 3. Add support for composing and decomposing multiple-image files.
#
import Image, string
class PILDriver:
verbose = 0
def do_verbose(self):
"""usage: verbose
Set verbosity flag from top of stack.
"""
self.verbose = self.do_pop()
# The evaluation stack (internal only)
stack = [] # Stack of pending operations
def push(self, item):
"Push an argument onto the evaluation stack."
self.stack = [item] + self.stack
def top(self):
"Return the top-of-stack element."
return self.stack[0]
# Stack manipulation (callable)
def do_clear(self):
"""usage: clear
Clear the stack.
"""
self.stack = []
def do_pop(self):
"""usage: pop
Discard the top element on the stack.
"""
top = self.stack[0]
self.stack = self.stack[1:]
return top
def do_dup(self):
"""usage: dup
Duplicate the top-of-stack item.
"""
if hasattr(self, 'format'): # If it's an image, do a real copy
dup = self.stack[0].copy()
else:
dup = self.stack[0]
self.stack = [dup] + self.stack
def do_swap(self):
"""usage: swap
Swap the top-of-stack item with the next one down.
"""
self.stack = [self.stack[1], self.stack[0]] + self.stack[2:]
# Image module functions (callable)
def do_new(self):
"""usage: new :
Create and push a greyscale image of given size and color.
"""
xsize = int(self.do_pop())
ysize = int(self.do_pop())
color = int(self.do_pop())
self.push(Image.new("L", (xsize, ysize), color))
def do_open(self):
"""usage: open
Open the indicated image, read it, push the image on the stack.
"""
self.push(Image.open(self.do_pop()))
def do_blend(self):
"""usage: blend
Replace two images and an alpha with the blended image.
"""
image1 = self.do_pop()
image2 = self.do_pop()
alpha = float(self.do_pop())
self.push(Image.blend(image1, image2, alpha))
def do_composite(self):
"""usage: composite
Replace two images and a mask with their composite.
"""
image1 = self.do_pop()
image2 = self.do_pop()
mask = self.do_pop()
self.push(Image.composite(image1, image2, mask))
def do_merge(self):
"""usage: merge [ [ []]]
Merge top-of stack images in a way described by the mode.
"""
mode = self.do_pop()
bandlist = []
for band in mode:
bandlist.append(self.do_pop())
self.push(Image.merge(mode, bandlist))
# Image class methods
def do_convert(self):
"""usage: convert
Convert the top image to the given mode.
"""
mode = self.do_pop()
image = self.do_pop()
self.push(image.convert(mode))
def do_copy(self):
"""usage: copy
Make and push a true copy of the top image.
"""
self.dup()
def do_crop(self):
"""usage: crop
Crop and push a rectangular region from the current image.
"""
left = int(self.do_pop())
upper = int(self.do_pop())
right = int(self.do_pop())
lower = int(self.do_pop())
image = self.do_pop()
self.push(image.crop((left, upper, right, lower)))
def do_draft(self):
"""usage: draft
Configure the loader for a given mode and size.
"""
mode = self.do_pop()
xsize = int(self.do_pop())
ysize = int(self.do_pop())
self.push(self.draft(mode, (xsize, ysize)))
def do_filter(self):
"""usage: filter
Process the top image with the given filter.
"""
import ImageFilter
filter = eval("ImageFilter." + string.upper(self.do_pop()))
image = self.do_pop()
self.push(image.filter(filter))
def do_offset(self):
"""usage: offset
Offset the pixels in the top image.
"""
xoff = int(self.do_pop())
yoff = int(self.do_pop())
image = self.do_pop()
self.push(image.offset(xoff, yoff))
def do_paste(self):
"""usage: paste
Paste figure image into ground with upper left at given offsets.
"""
figure = self.do_pop()
xoff = int(self.do_pop())
yoff = int(self.do_pop())
ground = self.do_pop()
if figure.mode == "RGBA":
self.push(ground.paste(figure, (xoff, yoff), figure))
else:
self.push(ground.paste(figure, (xoff, yoff)))
def do_resize(self):
"""usage: resize
Resize the top image.
"""
ysize = int(self.do_pop())
xsize = int(self.do_pop())
image = self.do_pop()
self.push(image.resize(xsize, ysize))
def do_rotate(self):
"""usage: rotate
Rotate image through a given angle
"""
angle = int(self.do_pop())
image = self.do_pop()
self.push(image.rotate(angle))
def do_save(self):
"""usage: save
Save image with default options.
"""
filename = self.do_pop()
image = self.do_pop()
image.save(filename)
def do_save2(self):
"""usage: save2
Save image with specified options.
"""
filename = self.do_pop()
options = self.do_pop()
image = self.do_pop()
image.save(filename, None, options)
def do_show(self):
"""usage: show
Display and pop the top image.
"""
self.do_pop().show()
def do_thumbnail(self):
"""usage: thumbnail
Modify the top image in the stack to contain a thumbnail of itself.
"""
ysize = int(self.do_pop())
xsize = int(self.do_pop())
self.top().thumbnail((xsize, ysize))
def do_transpose(self):
"""usage: transpose
Transpose the top image.
"""
transpose = string.upper(self.do_pop())
image = self.do_pop()
self.push(image.transpose(transpose))
# Image attributes
def do_format(self):
"""usage: format
Push the format of the top image onto the stack.
"""
self.push(self.pop().format)
def do_mode(self):
"""usage: mode
Push the mode of the top image onto the stack.
"""
self.push(self.pop().mode)
def do_size(self):
"""usage: size
Push the image size on the stack as (y, x).
"""
size = self.pop().size
self.push(size[0])
self.push(size[1])
# ImageChops operations
def do_invert(self):
"""usage: invert
Invert the top image.
"""
import ImageChops
self.push(ImageChops.invert(self.do_pop()))
def do_lighter(self):
"""usage: lighter
Pop the two top images, push an image of the lighter pixels of both.
"""
import ImageChops
image1 = self.do_pop()
image2 = self.do_pop()
self.push(ImageChops.lighter(image1, image2))
def do_darker(self):
"""usage: darker
Pop the two top images, push an image of the darker pixels of both.
"""
import ImageChops
image1 = self.do_pop()
image2 = self.do_pop()
self.push(ImageChops.darker(image1, image2))
def do_difference(self):
"""usage: difference
Pop the two top images, push the difference image
"""
import ImageChops
image1 = self.do_pop()
image2 = self.do_pop()
self.push(ImageChops.difference(image1, image2))
def do_multiply(self):
"""usage: multiply
Pop the two top images, push the multiplication image.
"""
import ImageChops
image1 = self.do_pop()
image2 = self.do_pop()
self.push(ImageChops.multiply(image1, image2))
def do_screen(self):
"""usage: screen
Pop the two top images, superimpose their inverted versions.
"""
import ImageChops
image2 = self.do_pop()
image1 = self.do_pop()
self.push(ImageChops.screen(image1, image2))
def do_add(self):
"""usage: add
Pop the two top images, produce the scaled sum with offset.
"""
import ImageChops
image1 = self.do_pop()
image2 = self.do_pop()
scale = float(self.do_pop())
offset = int(self.do_pop())
self.push(ImageChops.add(image1, image2, scale, offset))
def do_subtract(self):
"""usage: subtract
Pop the two top images, produce the scaled difference with offset.
"""
import ImageChops
image1 = self.do_pop()
image2 = self.do_pop()
scale = float(self.do_pop())
offset = int(self.do_pop())
self.push(ImageChops.subtract(image1, image2, scale, offset))
# ImageEnhance classes
def do_color(self):
"""usage: color
Enhance color in the top image.
"""
import ImageEnhance
factor = float(self.do_pop())
image = self.do_pop()
enhancer = ImageEnhance.Color(image)
self.push(enhancer.enhance(factor))
def do_contrast(self):
"""usage: contrast
Enhance contrast in the top image.
"""
import ImageEnhance
factor = float(self.do_pop())
image = self.do_pop()
enhancer = ImageEnhance.Color(image)
self.push(enhancer.enhance(factor))
def do_brightness(self):
"""usage: brightness
Enhance brightness in the top image.
"""
import ImageEnhance
factor = float(self.do_pop())
image = self.do_pop()
enhancer = ImageEnhance.Color(image)
self.push(enhancer.enhance(factor))
def do_sharpness(self):
"""usage: sharpness
Enhance sharpness in the top image.
"""
import ImageEnhance
factor = float(self.do_pop())
image = self.do_pop()
enhancer = ImageEnhance.Color(image)
self.push(enhancer.enhance(factor))
# The interpreter loop
def execute(self, list):
"Interpret a list of PILDriver commands."
list.reverse()
while len(list) > 0:
self.push(list[0])
list = list[1:]
if self.verbose:
print "Stack: " + `self.stack`
top = self.top()
if type(top) != type(""):
continue;
funcname = "do_" + top
if not hasattr(self, funcname):
continue
else:
self.do_pop()
func = getattr(self, funcname)
func()
if __name__ == '__main__':
import readline, sys
# If we see command-line arguments, interpret them as a stack state
# and execute. Otherwise go interactive.
driver = PILDriver()
if len(sys.argv[1:]) > 0:
driver.execute(sys.argv[1:])
else:
print "PILDriver says hello."
while 1:
try:
line = raw_input('pildriver> ');
except EOFError:
print "\nPILDriver says goodbye."
break
driver.execute(string.split(line))
print driver.stack
# The following sets edit modes for GNU EMACS
# Local Variables:
# mode:python
# End:
--zhXaljGHf11kAtnf--
From fredrik@pythonware.com Sun Jul 19 16:57:40 1998
From: fredrik@pythonware.com (Fredrik Lundh)
Date: Sun, 19 Jul 1998 16:57:40 +0100
Subject: [Image-SIG] PIL 0.3b2 is now available
Message-ID: <013b01bdb32d$fcec3280$f29b12c2@pythonware.com>
The Python Imaging Library (PIL) adds image processing capabilities
to your Python interpreter. This library provides extensive file format
support, an efficient internal representation, and fairly powerful
image processing capabilities.
This is the second (and hopefully the last) beta release for PIL 0.3.
The source kit has been built and tested on Windows 95 and NT, as
well as on Linux (Redhat 4.2) and Digital Unix. It should build out of
the box on most mainstream Unix versions.
Get your copy of the sources from:
http://www.pythonware.com
Here are the changes from the previous beta:
+ An Image "getbands" method has been added. It returns a tuple
containing the individual band names for this image. To figure
out how many bands an image has, use "len(im.getbands())".
+ An Image "putpixel" method has been added.
+ The Image "point" method can now be used to convert "L" images
to any other format, via a lookup table. That table should
contain 256 values for each band in the output image.
+ Some file drivers (including FLI/FLC, GIF, and IM) accidently
overwrote the offset method with an internal attribute. All
drivers have been updated to use private attributes where
possible.
+ The Image "histogram" method now works for "I" and "F" images.
For these modes, PIL divides the range between the min and
max values used in the image into 256 bins. You can also
pass in your own min and max values via the "extrema" option:
h = im.histogram(extrema=(0, 255))
+ An Image "getextrema" method has been added. It returns the
min and max values used in the image. In this release, this
works for single band images only.
+ Changed the PNG driver to load and save mode "I" images as
16-bit images. When saving, values outside the range 0..65535
are clipped.
+ Fixed ImageFont.py to work with the new "pilfont" compiler.
+ Added JPEG "save" and "draft" support for mode "YCbCr" images.
Note that if you save an "YCbCr" image as a JPEG file and read
it back, it is read as an RGB file. To get around this, you
can use the "draft" method:
im = Image.open("color.jpg")
im.draft("YCbCr", im.size)
+ Read "RGBA" TGA images. Also fixed the orientation bug; all
images should now come out the right way.
+ Changed mode name (and internal representation) from "YCrCb"
to "YCbCr" (!)
--the PIL team
From esr@snark.thyrsus.com Sun Jul 19 17:41:32 1998
From: esr@snark.thyrsus.com (Eric S. Raymond)
Date: Sun, 19 Jul 1998 12:41:32 -0400
Subject: [Image-SIG] New PIL release
Message-ID: <19980719124132.A28724@snark.thyrsus.com>
A few documentation bugs...
You changed the name of the shared library, but the change is not
reflected in the installation instructions.
Still no pilfont docs; the link on the handbook page is broken.
Why isn't the documentation included with the source distribution?
--
Eric S. Raymond
The danger (where there is any) from armed citizens, is only to the
*government*, not to *society*; and as long as they have nothing to
revenge in the government (which they cannot have while it is in their
own hands) there are many advantages in their being accustomed to the
use of arms, and no possible disadvantage.
-- Joel Barlow, "Advice to the Privileged Orders", 1792-93
From fredrik@pythonware.com Sun Jul 19 19:03:47 1998
From: fredrik@pythonware.com (Fredrik Lundh)
Date: Sun, 19 Jul 1998 19:03:47 +0100
Subject: [Image-SIG] New PIL release
Message-ID: <003a01bdb342$27d07bf0$f29b12c2@pythonware.com>
>A few documentation bugs...
>
>You changed the name of the shared library, but the change is not
>reflected in the installation instructions.
Did you grab the 0.3b2 release just after you received the
announcement? If you were unlucky, you might have gotten
a file called "Imaging-0.3b1.tgz"...
If you try again, you should get the right file...
>Still no pilfont docs; the link on the handbook page is broken.
>
>Why isn't the documentation included with the source distribution?
It will be in the final release, once it's up to date.
Cheers /F
From esr@snark.thyrsus.com Sun Jul 19 18:53:40 1998
From: esr@snark.thyrsus.com (Eric S. Raymond)
Date: Sun, 19 Jul 1998 13:53:40 -0400
Subject: [Image-SIG] New PIL release
In-Reply-To: <003a01bdb342$27d07bf0$f29b12c2@pythonware.com>; from Fredrik Lundh on Sun, Jul 19, 1998 at 07:03:47PM +0100
References: <003a01bdb342$27d07bf0$f29b12c2@pythonware.com>
Message-ID: <19980719135340.A28847@snark.thyrsus.com>
Fredrik Lundh :
> Did you grab the 0.3b2 release just after you received the
> announcement? If you were unlucky, you might have gotten
> a file called "Imaging-0.3b1.tgz"...
That's what happened.
> If you try again, you should get the right file...
Will do.
> >Still no pilfont docs; the link on the handbook page is broken.
> >
> >Why isn't the documentation included with the source distribution?
>
> It will be in the final release, once it's up to date.
Please push the docs higher on your priority list. The pildriver
script is getting mature enough that the gaps in the documentation
are now a serious impediment to its further development.
Also, I have observed in the past that when the documentation is left
until last, it tends to get left unfinished and be of poor quality.
Even very good developers (which it's clear you are) often fall into
this trap under pressure to dive into the next project.
For this reason, I often document my projects *before* coding, as I
design them in my head. (For an example, see the Trove design document
at .) This is a practice I recommend
to you.
I think you would be doing everyone greater service by concentrating
on documentation for a while rather than just coding. Please, at least
catch the documentation up with the current state of things and include
an editable master form in the distribution.
That way the rest of us can help you improve the documentation as well
as the code.
--
Eric S. Raymond
The people cannot delegate to government the power to do anything
which would be unlawful for them to do themselves.
-- John Locke, "A Treatise Concerning Civil Government"
From esr@snark.thyrsus.com Sun Jul 19 20:46:32 1998
From: esr@snark.thyrsus.com (Eric S. Raymond)
Date: Sun, 19 Jul 1998 15:46:32 -0400
Subject: [Image-SIG] Core dump in 0.3b2 offset method
Message-ID: <19980719154632.A29670@snark.thyrsus.com>
--ew6BAiZeqk4r7MaW
Content-Type: text/plain; charset=us-ascii
Enclosed: a simple Python script that core-dumps PIL, and the image
to do it with. Seems to work with any image, I just picked a small one.
--
Eric S. Raymond
& what country can preserve its liberties, if its rulers are not
warned from time to time that his people preserve the spirit of
resistance? Let them take arms...The tree of liberty must be
refreshed from time to time, with the blood of patriots and tyrants.
-- Thomas Jefferson, letter to Col. William S. Smith, 1787
--ew6BAiZeqk4r7MaW
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="offsetcore.py"
#!/usr/bin/python
import Image
image = Image.open("arrow.gif")
image = image.offset(50, 60)
--ew6BAiZeqk4r7MaW
Content-Type: image/gif
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="arrow.gif"
R0lGODdhEAAJAPAAAP///wAAACwAAAAAEAAJAAACFoSPEcitDc0Dqtq7sN58xeR9UihORgEA
Ow==
--ew6BAiZeqk4r7MaW--
From Fred L. Drake, Jr."
--5ydeQFjoGe
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
I've attached a patch to PngImagePlugin.py which adds support for
the zTXt, bKGD, and gIFg chunks. The tEXt and zTXt chunks contain
text information; this is now stored in the "text" element of the info
dictionary; the value is another dictionary of key/value pairs. Each
value is a list of (string, ) pairs, where is
a boolean indicating whether the string was compressed (a zTXt chunk)
or uncompressed (a tEXt chunk). The bKGD chunk is used to add a
"background" field to the info dictionary, and the gIFg chunk is used
to determine a "duration" field.
-Fred
--
Fred L. Drake, Jr.
Corporation for National Research Initiatives
1895 Preston White Dr. Reston, VA 20191
--5ydeQFjoGe
Content-Type: text/plain
Content-Description: improve PNG support for PIL
Content-Disposition: inline;
filename="PngImagePlugin.patch"
Content-Transfer-Encoding: 7bit
*** PIL/PngImagePlugin.py Sun Jul 19 10:25:14 1998
--- /home/fdrake/lib/python/PngImagePlugin.py Mon Jul 20 10:40:38 1998
***************
*** 88,93 ****
--- 88,96 ----
def close(self):
del self.queue
self.fp = None
+ if self.__dict__.has_key("crc"):
+ # using crc_skip(); remove circular reference
+ del self.__dict__["crc"]
def push(self, cid, pos, len):
***************
*** 167,172 ****
--- 170,178 ----
# image data
self.im_tile = [("zip", (0,0)+self.im_size, pos, self.im_rawmode)]
self.im_idat = len
+
+ # This error is to separate the "header" chunks from the remaining
+ # chunks; see PngImageFile.__init__().
raise EOFError
def chunk_IEND(self, pos, len):
***************
*** 193,202 ****
# text
s = self.fp.read(len)
! [k, v] = string.split(s, "\0")
! self.im_info[k] = v
return s
# --------------------------------------------------------------------
# PNG reader
--- 199,266 ----
# text
s = self.fp.read(len)
! [k, v] = string.split(s, "\0", 1)
! self.add_text(k, v)
return s
+ def chunk_zTXt(self, pos, len):
+ s = self.fp.read(len)
+ [k, d] = string.split(s, "\0", 1)
+ if not d:
+ raise SyntaxError, "zTXt chunk missing compression method"
+ m, z = d[0], d[1:]
+ v = _inflate(z)
+ self.add_text(k, v, 1)
+ return s
+
+ def add_text(self, keyword, value, compressed=0):
+ # If there is already a chunk with this keyword, the value of
+ # info[k] will become a list containing all values, otherwise (if
+ # there is no value already), only a single string will be used.
+ value = (value, compressed)
+ try:
+ text = self.im_info["text"]
+ except KeyError:
+ text = self.im_info["text"] = {}
+ if text.has_key(keyword):
+ text[keyword].append(value)
+ else:
+ text[keyword] = [value]
+
+ def chunk_bKGD(self, pos, len):
+ s = self.fp.read(len)
+ if len == 1:
+ self.im_info["background"] = ord(s)
+ elif len == 2:
+ self.im_info["background"] = ord(s[0]) << 8 | ord(s[1])
+ elif len == 6:
+ # tuple (R, G, B)
+ self.im_info["background"] = ((ord(s[0]) << 8 | ord(s[1])),
+ (ord(s[2]) << 8 | ord(s[3])),
+ (ord(s[4]) << 8 | ord(s[5])))
+ elif Image.DEBUG:
+ print "unsupported background chunk in mode", self.im_mode
+ return s
+
+ def chunk_gIFg(self, pos, len):
+ s = self.fp.read(len)
+ if len != 4:
+ raise SyntaxError, "invalid gIFg chunk length"
+ import struct
+ disp, input, delay = struct.unpack(">BBH", s)
+ self.im_info["duration"] = int(delay)
+ return s
+
+
+ def _deflate(data):
+ import zlib
+ co = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED,
+ -zlib.MAX_WBITS)
+ return co.compress(data) + co.flush()
+
+ def _inflate(data):
+ import zlib
+ return zlib.decompress(data, -zlib.MAX_WBITS)
# --------------------------------------------------------------------
# PNG reader
***************
*** 232,237 ****
--- 296,302 ----
break
except AttributeError:
+ # presumably an unknown chunk type
if Image.DEBUG:
print cid, pos, len, "(unknown)"
s = self.fp.read(len)
***************
*** 311,317 ****
"L;2": ("L;2", chr(2)+chr(0)),
"L;4": ("L;4", chr(4)+chr(0)),
"L": ("L", chr(8)+chr(0)),
- "I": ("I;16B", chr(16)+chr(0)),
"P;1": ("P;1", chr(1)+chr(3)),
"P;2": ("P;2", chr(2)+chr(3)),
"P;4": ("P;4", chr(4)+chr(3)),
--- 376,381 ----
***************
*** 386,392 ****
raise IOError, "cannot write mode %s as PNG" % mode
if check:
! return check
#
# write minimal PNG file
--- 450,456 ----
raise IOError, "cannot write mode %s as PNG" % mode
if check:
! return check
#
# write minimal PNG file
***************
*** 400,413 ****
chr(0), # 11: filter category
chr(0)) # 12: interlace flag
if im.mode == "P":
! chunk(fp, "PLTE", im.im.getpalette("RGB"))
if 0:
# FIXME: to be supported some day
chunk(fp, "gAMA", o32(int(gamma * 100000.0)))
ImageFile._save(im, _idat(fp, chunk), [("zip", (0,0)+im.size, 0, rawmode)])
chunk(fp, "IEND", "")
--- 464,512 ----
chr(0), # 11: filter category
chr(0)) # 12: interlace flag
+ colortype = ord(mode[-1]) # "color type" from the spec.
+ info = im.info.copy()
if im.mode == "P":
! pal = im.im.getpalette("RGB")
! chunk(fp, "PLTE", pal)
! if im.info.has_key("transparency"):
! tRNS_data = None
! if colortype == 3:
! v = [0] * (len(pal) / 3)
! v[im.info["transparency"]] = 1
! tRNS_data = string.join(map(chr, v), '')
! elif colortype in (4, 6):
! # prohibited
! pass
! elif colortype in (0, 2):
! # not yet implemented
! pass
! else:
! raise RuntimeError, "bad colortype value -- internal error"
! if tRNS_data:
! chunk(fp, "tRNS", tRNS_data)
! if im.info.has_key("background") and colortype == 3:
! bKGD_data = chr(im.info["background"])
! chunk(fp, "bKGD", bKGD_data)
! if im.info.has_key("duration"):
! import struct
! disp, input, delay = 0, 0, im.info["duration"]
! gIFg_data = struct.pack(">BBH", disp, input, delay)
! chunk(fp, "gIFg", gIFg_data)
if 0:
# FIXME: to be supported some day
chunk(fp, "gAMA", o32(int(gamma * 100000.0)))
ImageFile._save(im, _idat(fp, chunk), [("zip", (0,0)+im.size, 0, rawmode)])
+
+ if im.info.has_key("text"):
+ for k, v in info["text"].items():
+ if type(v) is type(()) and len(v) == 2:
+ v, c = v
+ if c:
+ v = _deflate(v)
+ chunk(fp, c and "zTXt" or "tEXt", v)
chunk(fp, "IEND", "")
--5ydeQFjoGe--
From edcjones@erols.com Fri Jul 24 06:40:41 1998
From: edcjones@erols.com (Edward C. Jones)
Date: Fri, 24 Jul 1998 01:40:41 -0400
Subject: [Image-SIG] Newbie bug
Message-ID: <35B81E59.7A3824AA@erols.com>
I am new at PIL. The following program gave an error. What to do?
--------
Traceback (innermost last):
File "./thresh.py", line 17, in ?
outim = im.point(lut, im.mode)
File "/usr/lib/python1.5/site-packages/PIL/Image.py", line 525,
in point
im = self.im.point(lut, mode)
ValueError: Images do not match
--------
#! /usr/bin/python
import Image, sys, string
if len(sys.argv) != 4:
raise 'must have exactly three parameters'
t = string.atoi(sys.argv[1])
im = Image.open(sys.argv[2])
lut = (3*256) * [0]
for i in range(t,256):
lut[i] = 1
lut[i+256] = 1
lut[i+512] = 1
outim = im.point(lut, im.mode)
outim.save(sys.argv[3])
From fredrik@pythonware.com Fri Jul 24 15:23:10 1998
From: fredrik@pythonware.com (Fredrik Lundh)
Date: Fri, 24 Jul 1998 15:23:10 +0100
Subject: [Image-SIG] Newbie bug
Message-ID: <005901bdb70e$9a4b6760$f29b12c2@pythonware.com>
>I am new at PIL. The following program gave an error. What to do?
What are you trying to do? What data did you use as input?
What's the value of "im.mode"? Does it work as expected
if you just drop the second argument to "im.point"?
Cheers /F
fredrik@pythonware.com
http://www.pythonware.com
From fredrik@pythonware.com Fri Jul 24 15:29:34 1998
From: fredrik@pythonware.com (Fredrik Lundh)
Date: Fri, 24 Jul 1998 15:29:34 +0100
Subject: [Image-SIG] creating palettes on the fly
Message-ID: <009501bdb70f$7da1a560$f29b12c2@pythonware.com>
This is a multi-part message in MIME format.
------=_NextPart_000_0090_01BDB717.DC3DCB50
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
I've attached a small class that makes it much easier to
generate palette images via the ImageDraw module. See
the test code at the end for details.
Something similar to this will be shipped with the next
PIL release.
Cheers /F
fredrik@pythonware.com
http://www.pythonware.com
------=_NextPart_000_0090_01BDB717.DC3DCB50
Content-Type: application/octet-stream;
name="palette.py"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="palette.py"
#
# a simple palette wrapper class
#
# fredrik lundh, july 1998
#
import string
_inks = {
# HTML 3.2 colour names
"aqua": (0x00,0xFF,0xFF),
"black": (0x00,0x00,0x00),
"blue": (0x00,0x00,0xFF),
"fuchsia": (0xFF,0x00,0xFF),
"gray": (0x80,0x80,0x80),
"green": (0x00,0x80,0x00),
"lime": (0x00,0xFF,0x00),
"maroon": (0x80,0x00,0x00),
"navy": (0x00,0x00,0x80),
"olive": (0x80,0x80,0x00),
"purple": (0x80,0x00,0x80),
"red": (0xFF,0x00,0x00),
"silver": (0xC0,0xC0,0xC0),
"teal": (0x00,0x80,0x80),
"white": (0xFF,0xFF,0xFF),
"yellow": (0xFF,0xFF,0x00),
}
class Palette:
def __init__(self):
self.palette = {}
def __getitem__(self, rgb):
# lookup colour in current palette
try:
# tuple
r, g, b = rgb
except ValueError:
try:
# named colour
r, g, b = _inks[string.lower(rgb)]
except KeyError:
# hex string
if rgb[0] == "#" and len(rgb) == 7:
rgb = string.atoi(rgb[1:], 16)
r = rgb >> 16
g = rgb >> 8 & 255
b = rgb & 255
rgb = chr(r) + chr(g) + chr(b)
try:
return self.palette[rgb]
except KeyError:
# allocate new entry
ink = len(self.palette)
if ink == 256:
raise RuntimeError, "palette can hold only 256 entries"
self.palette[rgb] = ink
return ink
def attach(self, image):
# attach palette to an image memory
palette = ["\0\0\0"] * 256
for rgb, i in self.palette.items():
if i < 256:
palette[i] = rgb
image.putpalette(string.join(palette, ""), "RGB")
if __name__ == "__main__":
import Image, ImageDraw
ink = Palette()
im = Image.new("P", (400, 400), ink["#99ccff"])
d = ImageDraw.ImageDraw(im)
d.setink(ink["white"])
for i in range(0, 400, 10):
d.line((i,0,200,200))
d.line((0,i,200,200))
d.setink(ink[(0,0,128)])
d.setfill(1)
d.rectangle((150,150,250,250))
ink.attach(im)
im.save("out.png")
------=_NextPart_000_0090_01BDB717.DC3DCB50--