Open GoogleCodeExporter opened 8 years ago
Also, checked the contents of the image data, it's there..
data = MapToString(data) # modified data, added green line
for i in range(0,20):
print(ord(data[i])) # Print some pixels, data verified
self.texture.format = 'RGBA' # Just to ensure a correct format
self.texture.set_data('RGBA', tmp.width * 4, data) #Works, renders fine
self.texture.format = 'RGBA' # Again, ensurance
self.texture.save('kitten.png') # fully transparent image, no green
for i in range(0,20): # Verifies data again, yepp still there
print(ord(self.texture.get_data()[i])) # Note: not 'data' but pixeldata
self.texture.set_data('RGBA', tmp.width * 4, data) # Now it renders when .draw() EXCEPT for the green line, but the gray square is there.. why?
Original comment by Anton.Do...@gmail.com
on 26 Feb 2014 at 8:26
[deleted comment]
Here's the entire code (can be run as is, nothing specific to my machine):
https://gist.github.com/Torxed/a39b6d348757e633f739
Run it with (to generate green line): python3 gen_graph.py 1,5, 11,7 21,15
31,12 41,1
Original comment by Anton.Do...@gmail.com
on 26 Feb 2014 at 8:40
I tried your example and I got an error: in gen_solid_img, alpha is a float. I
converted in an integer and I get a kitten.png that I've attached to the but
report.
Can you tell me if it's the expected result?
I'm using the latest repo code with Python 2.7 in Linux.
Have you look at this?
http://pyglet.org/doc-current/programming_guide/image.html#saving-an-image
Just to confirm that you have PIL installed :)
Thanks for your report!
Original comment by useboxnet
on 26 Feb 2014 at 7:41
Attachments:
Oh sorry, I didn't run the script correctly. I'm, attaching the result (that I
think looks OK!).
I have pyllow installed (a PIL-compatible library; python-pillow in Fedora,
possibly the same name in other distros).
Original comment by useboxnet
on 26 Feb 2014 at 7:44
Attachments:
Ah, I do not have PIL/pillow installed as i was told this was optional. Your
graph looks perfect, just the way i want it to look like.
Also, yes i used that exact documentation as reference for my code.
I'll install PIL (pillow) tomorrow and rerun the code, but if that fixes
things.. it shouldn't be to hard to narrow down the issue within the native
code?
Original comment by Anton.Do...@gmail.com
on 26 Feb 2014 at 10:28
The fallback mechanism is pypng and it doesn't support all type of PNGs when
saving. The problem here is that it didn't reported an error for you instead of
generating the wrong image.
Original comment by useboxnet
on 27 Feb 2014 at 6:42
1: Deinstalled everything
2: Installed Python2, code works fine
3: Installed PIL for Python2, code works fine.
4: Deinstalled everything
5: Installed Python3, code does not work.. well it does as long as i don't use
.save(..) (see the video clip below)
6: Installed Pillow (PIL), still doesn't work.
Here's what happens on my end: https://www.youtube.com/watch?v=I_NwDnkzOhM
Do i need to pass an argument to Pyglet in order for it to choose PIL or is
that a default override whenever it finds it installed?
Here's what the Python2 output of 'graph.png' looks like both with and without
PIL.
Original comment by Anton.Do...@gmail.com
on 27 Feb 2014 at 10:44
Attachments:
Great tests, thanks a lot!
Pyglet will automatically use PIL if it's available (I assume you installed PIL
for Python 3).
Looks to me like this could be an issue with pypng library when working with
Python 3.
Original comment by useboxnet
on 27 Feb 2014 at 10:48
You're welcome and thank you for taking note of this issue!
I assumed as much since there's no need to use pypng if a superior library is
present for certain formats. And yepp, python-pillow ("Python Imaging Library
(PIL) fork. Python3 version.") was installed.
I would assume that pypng ignores PIL in this particular case, but that's just
my assumption. You have better understanding of the internal mechanics than I
do so i'll let you work on this on your own :)
Again, thank you for taking a look at this issue!
Original comment by Anton.Do...@gmail.com
on 27 Feb 2014 at 10:51
Thanks for the follow up!
I knew pillow supports Python 3 (PIL doesn't); it was worth double-checking
that for you.
The truth is that pypng *actually* supports some encoding cases (not all of
them though, and I think that's why the docs recommend using PIL).
`save` method has an `encoder` parameter that you can use to specify the exact
encoder want to use. For example:
from pyglet.image.codecs.png import PNGImageEncoder
encoder = PNGImageEncoder()
And you can use that encoder.
In *.codecs you also have `pil` to test:
from pyglet.image.codecs.pil import PILImageEncoder
encoder = PILImageEncoder()
It would be useful if you could try the encoders in that way so we can identify
which encoder is not working for you in Python 3.
(I'm writing the code examples here without testing them, you may need to tweak
them -- sorry abut that!)
Original comment by useboxnet
on 27 Feb 2014 at 11:07
Both encoders were defect. They both produced the same output as shown in the
video-clip.
Also i tried to do: "from pyglet.image.codecs.pypng import ..." but since i
didn't know (or find) what to import from it and pass to `encoder=` i had very
little luck.
I thought of overriding the PIL and `png` libraries with pypng and see if that
helped.
Here's the code i used:
self.texture.save('graph.png', encoder=PILImageEncoder())
self.texture.save('graph.png', encoder=PNGImageEncoder())
with respective imports ofc.
Original comment by Anton.Do...@gmail.com
on 27 Feb 2014 at 12:18
OK, I finally had time to look at your issue and I think the difference is in
the behaviour of python 3 regarding the Sprite class. Unfortunately I don't
have enough knowledge to explain why it happens.
If you save the picture AFTER calling the Sprite __init__ with super, the
behaviour is exactly like in python 2. My guess is that something needs to be
initialised in python 3 and not in python 2.
Calling save before the Sprite instance is initialised was the problem. So I
concur this is not a bug :)
Original comment by useboxnet
on 6 Mar 2014 at 8:48
[deleted comment]
Almost, i've modified the code so both the `class GUI(pyglet.window.Window)`
and `class Graph(pyglet.sprite.Sprite)` is initialized properly at the
rendering function of pyglet.window.Window (`app.run()`) i try to save the
image, the image is still blank.
Tried with both PIL and without it, and using the latest alpha from Pyglet,
both compiled on my own so no package manager was used.
Code looks like this:
# GUI() class in the above example
def render(self, *args):
pyglet.gl.glClearColor(1,1,1,1)
self.clear()
self.graphics['Graph'].texture.save('output.png')
It renders beautifully now in Python3, so even tho i try this (which broke
before), it renders:
# again, GUI() class function
def render(self, *args):
pyglet.gl.glClearColor(1,1,1,1)
self.clear()
test = self.graphics['Graph'].get_image_data()
test.save('output.png')
Before that would cause a black screen, not it renders at least.. I'm currently
doing a screen-grab via pyglets internal screen-capture function and that works
but with the down-side of not being able to set alpha channels (since, the
background will "block" the transparancy of an object when saving a screenshot).
What code did you use to test this? Because I've moved around `.save()` quite a
lot and try to figure out where you placed it in order to achieve good results :
Also note that i did try both with and without:
.save('output.png', encoder=PILImageEncoder|PNGImageEncoder)
Same result. The result is a semi-transparent gray box without any lines in it
(on disk, on the screen.. it's the same gray box but with lines as well..)
Original comment by Anton.Do...@gmail.com
on 7 Mar 2014 at 9:38
I used the script you linked:
https://gist.github.com/Torxed/a39b6d348757e633f739
I only had to move the save *after* the super call in Graph __init__ (oh, and
add a int wrapping 0.2*255 in gen_solid_img).
If I don't change that save to be after the __init__, it won't render even on
the screen.
Original comment by useboxnet
on 7 Mar 2014 at 9:40
[deleted comment]
[deleted comment]
This is the most bizzar phenomenon i've encountered in a few years.
I'm so greatful for all the help you put in to this and i must be annoying as
hell by now.. But could you explain this for me:
https://www.youtube.com/watch?v=TPgtT3sQnCk
Python3, PIL (and not, tried both), Pyglet-hg from the repo (not sure how to
get out the exact rev).. :/
I did try this on two separate machines just to be on the safe side, both gave
the same result. Debian and ArchLinux respecitvely renders the image+modified
data perfectly but the saved file doesn't contain the modified data still.
I used the packagemanager on Arch to install Pyglet alpha (from the AUR, called
pyglet-hg) and compiled it manually on the Debian machine (Python3,
Python3-dev, pyglet-be521fae6f29, Pillow-2.3.0, gcc Debian 4.7.2-5)
Original comment by Anton.Do...@gmail.com
on 7 Mar 2014 at 10:10
You're welcome, and I'm sorry I can't help you more :)
I think here are two different things: saving before initializing the Sprite
subclass, that will affect the on screen rendering, and the save itself that I
must confess got me completely lost (because it works in my system!).
If you got the render working, let's focus on getting the screen saved. This is
my preferred way of getting a screenshot:
https://github.com/reidrac/pyglet-template/blob/master/game/__init__.py#L147
Basically: pyglet.image.get_buffer_manager().get_color_buffer().save(filename)
I don't know if that's what you're using at the moment.
Also I got to reproduce the "transparent image" issue with python 3.2.3 and
pypng :) Well, it actually crashes before that because of a different problem
(not happening with python 3.3!):
Traceback (most recent call last):
File "t.py", line 198, in <module>
x.run()
File "t.py", line 191, in run
self.render()
File "t.py", line 166, in render
self.graphics['Graph'].image.save("output.png")
File ".../pyglet/_build/lib/pyglet/image/__init__.py", line 453, in save
encoder.encode(self, file, filename)
File ".../pyglet/_build/lib/pyglet/image/codecs/png.py", line 103, in encode
data.fromstring(image.data)
File ".../pyglet/_build/lib/pyglet/image/__init__.py", line 1149, in _get_data
rows = re.findall('.' * abs(self._current_pitch), data, re.DOTALL)
File "/usr/lib/python3.2/re.py", line 193, in findall
return _compile(pattern, flags).findall(string)
TypeError: can't use a string pattern on a bytes-like object
I'll look at this later because that could be related (I used a cast to string
in that findall and then I got the transparent image).
Original comment by useboxnet
on 7 Mar 2014 at 10:43
Yea it got me kinda lost when you sad it's working for you.. Spent a few hours
just fiddling around with different combinations (because to be honest, moving
.save() after initializing a sprite makes sense sort of so i was thinkin there
might be some other stuff that i did in "the wrong order".. but out of luck).
I'm using
`pyglet.image.get_buffer_manager().get_color_buffer().save('graph.png')` as
well, i digg it and it does 99% of the job at the moment so the people i'm
generating graphs for are satisfied as long as they don't come up with the
genious idea that "transparent images are the new", in which case i'm screwed
unless this issue is resolved :)
That aside, I'm on board that these are two separate issues.
I'll just list the different version of everything (some are repeated from
above):
Debian:
- Python 3.2.3 (default, Feb 20 2013, 14:44:27) built with GCC 4.7.2 on Linux2
- GCC Debian 4.7.2-5
- Pyglet via http://pyglet.googlecode.com/archive/tip.zip
- Pillow-2.3.0
- Python3-dev package for the header files (assuming 3.2.3 is the linkage)
Arch:
- Python 3.3.4 (default, Feb 11 2014, 15:56:08) built with GCC 4.8.2 20140206 (prerelease) on Linux.
- GCC 4.8.2 20140206 (prerelease)
- Pyglet 1.2alpha1.2774.f8da1dcafc85-1 (via hg clone https://pyglet.googlecode.com/hg)
- Pillow 2.3.0-3 (Patches: https://projects.archlinux.org/svntogit/community.git/log/trunk?h=packages/python-pillow)
It's strange because i did not recieve that error when running on my debian box
(3.2.3), and i think i'm using pypng sinde i didn't have pillow installed at
first :/
Original comment by Anton.Do...@gmail.com
on 7 Mar 2014 at 10:59
Well, it works for me with python 3.3.2, but not with python 3.2.3. Not all
python 3 versions are the same! :)
I'll investigate further now that I have a clue! Thanks again for your report.
Original comment by useboxnet
on 7 Mar 2014 at 11:15
[deleted comment]
Thank you, I really hope you find something.
I'll do a stack-trace of the 3 different python versions and see if i find
anything.. Should be able to figure out something by doing: python -m trace
--trace test.py
Anyway, i installed Python3.2.3-2 as well just for the kicks, same issue.
But i'll let you figure out what's wrong without me putting ideas in your head,
but if you need more info just poke and i'll do what i can..
Thank you in advance! :)
Original comment by Anton.Do...@gmail.com
on 7 Mar 2014 at 11:35
I updated the gist with a print('---- BEGIN') and a print('END ----'), i then
ran a trace:
python -m trace --trace test.py
I know it's hughe, but you could run the same and do a diff on my attached file.
Note that the file will be hughe, so i cropped it down to just right before
'---- BEGIN' and cropped the *hughe* repetative pattern that looked like:
compat.py(75): return bytes(ord(c) for c in s)
--- modulename: compat, funcname: <genexpr>
Think it repeated a few million times.. So i cropped it down to 3 times + the 2
initial compat.py and a trailing one without the ---- stuff.:
compat.py(72): if isinstance(s, bytes):
compat.py(74): elif isinstance(s, str):
compat.py(75): return bytes(ord(c) for c in s)
--- modulename: compat, funcname: <genexpr>
compat.py(75): return bytes(ord(c) for c in s)
--- modulename: compat, funcname: <genexpr>
compat.py(75): return bytes(ord(c) for c in s)
--- modulename: compat, funcname: <genexpr>
compat.py(75): return bytes(ord(c) for c in s)
Original comment by Anton.Do...@gmail.com
on 7 Mar 2014 at 11:46
Attachments:
Crap, full command when traced was:
python -m trace --trace test.py 10,20, 20,30 > debug.log
You'll need that in order to simulate the exact number of operations for
certain calculations i guess. So use that.
do a:
diff debug.log py334-debug.log
You should be able to figure out what is happening in your machine which
differs from mine when executing the same code on the same python version and
on different..
I'll throw in a 3.2.3 trace as well in this post, because they should be 100%
similar.
And yes pypng is used :)
pypng.py(243): outfile.write(struct.pack("!I", len(data)))
pypng.py(244): outfile.write(tag)
pypng.py(245): outfile.write(data)
pypng.py(246): checksum = zlib.crc32(tag)
pypng.py(247): checksum = zlib.crc32(data, checksum)
etc..
Original comment by Anton.Do...@gmail.com
on 7 Mar 2014 at 11:55
Attachments:
On a side note: In Py3, poking around with *ANY* value inherited from pyglet
before __init__ has been called on the pyglet object will break the appliction.
Tried setting `self.x = ...` before initializing pyglet.sprite.Sprite and i got:
File "/usr/lib/python3.3/site-packages/pyglet/sprite.py", line 459, in _set_x
self._update_position()
File "/usr/lib/python3.3/site-packages/pyglet/sprite.py", line 393, in _update_position
img = self._texture
AttributeError: 'Grass' object has no attribute '_texture'
This must have something to do with how Python3 vs Python2 initializes classes
because for instance, in Python3 i can do:
class Grass(BasicObject):
def __init__(*args, **dictWars):
## If we are inherited from another class,
## the arguments will be passed only into *args and we
## need to unpack them outselves if 4 conditions are met
## that can only happen if we are inherited.
if type(args) == tuple and len(args) == 2 and len(dictWars) == 0 and type(args[1]) == dict:
args, dictWars = args
self = args[0]
BasicObject.__init__(args, dictWars)
While in Python2 this would give me:
BasicObject.__init__(args, dictWars)
TypeError: unbound method __init__() must be called with BasicObject instance as first argument (got tuple instance instead)
I know this is a weird fucking thing to do when initializing classes, but it
works like a swizz clockwork in Py3 and gives me insane control over the
structure of a class and passing arguments can be done transparently throughout
multiple inherits in such a dynamic way i'm sold on this method :P
Anyway, in Python2 I get the feeling that something is pre-initialized compared
to Python3..
as if this is the model and it fucks things up:
class x():
test = 1
def __init__(self):
pass
vs
class x():
def __init__(self):
self.test = 1
They produce the same outcome but in different execution orders when inheriting
objects.. or at least that's the feeling i get :/
A small side-note to the original problem of why the rendering issue makes
sense.. still doesn't solve my .save() issue :)
Original comment by Anton.Do...@gmail.com
on 8 Mar 2014 at 10:48
Original issue reported on code.google.com by
Anton.Do...@gmail.com
on 26 Feb 2014 at 8:13