Rotation and scaling tool: rotpixels

A place for your artistic side. Discuss techniques and tools for pixel art on the NES, GBC, or similar platforms.

Moderator: Moderators

Post Reply
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Rotation and scaling tool: rotpixels

Post by tepples »

Out of the Sonic hacking community came RotSprite, a program for rotating and scaling pixel art without the blurring of bilinear filtering or the jaggedness of naive point sampling. But it was closed-source and Windows-only. So I decided to reimplement the algorithm in Python.

The result: Rotpixels.

I reimplemented the algorithm without some of the optional steps. I provided for rotation, scaling, and even pixel aspect ratio correction (so that your graphics drawn in the 1.143 PAR of NES can be correctly rotated within 1.143 PAR). It's very slow because Scale2x and edge detection are written in pure Python, and PIL's majority filtering is slow as well. But now that I have a working reference implementation as source code, I may rewrite it in C if there is interest.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

This is my first time trying to run Python code... I have no idea if there's some kind of "standard" version of Python to use, but after failing with versions 3.2.1 and 2.7.2, I finally got it working on 2.6.1. Kinda. I got this error:
Python wrote:File "rotpixels.py", line 347, in main
out.save(outfilename)
NameError: global name 'outfilename' is not defined
Not knowing enough Python to actually look for the error I simply hardcoded a string with the name of the output file, and I finally got to see the output of the program. What I'm I doing wrong?

BTW, I'm using portable versions of Python (and I'm really glad I made that choice, I'd be pretty pissed if I had installed 2 useless versions into my system).

Anyway, this program looks very similar to the one that inspired it. The possibility to mess with aspect ratios is very welcome, and should make a huge difference in the end. I'll have to play with this a bit more to see what it can really do!
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Post by koitsu »

It's because Python has to live up to its name: the serpent coil, or as I like to call it (and have for 5-6 years now), "The Coiler".

Not here to argue over languages, which sucks vs. which is better, blah blah, just sayin'... The Coiler is always coiled and ready to strike at any moment. You got bitten.
User avatar
thefox
Posts: 3134
Joined: Mon Jan 03, 2005 10:36 am
Location: 🇫🇮
Contact:

Post by thefox »

tokumaru wrote:This is my first time trying to run Python code... I have no idea if there's some kind of "standard" version of Python to use, but after failing with versions 3.2.1 and 2.7.2, I finally got it working on 2.6.1. Kinda. I got this error:
Python wrote:File "rotpixels.py", line 347, in main
out.save(outfilename)
NameError: global name 'outfilename' is not defined
Not knowing enough Python to actually look for the error I simply hardcoded a string with the name of the output file, and I finally got to see the output of the program. What I'm I doing wrong?
IDK how it could've possibly worked for tepples, you need to replace outfilename with opt.outfilename.
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

tokumaru wrote:I have no idea if there's some kind of "standard" version of Python to use
A lot of native code libraries on which programs rely haven't been ported to Python 3.x. The latest in the 2.7 series is probably the best, along with the corresponding version of PIL.
Kinda. I got this error:
Python wrote:File "rotpixels.py", line 347, in main
out.save(outfilename)
NameError: global name 'outfilename' is not defined
NameError means the program is trying to use an uninitialized variable, which means the program has a bug. :oops: The solution reported by thefox is correct.
thefox wrote:IDK how it could've possibly worked for tepples
Any Python program can import any other Python program as a module and use its functions. A program designed to run as a module will test whether it's being run stand-alone or as a module (the if __name__=='__main__' near the end). I try to make my programs usable as libraries, where the command-line tool just calls the library. In a last-minute refactoring toward this end, I forgot to test file output. I was relying on the fact that an output filename is optional; it'll appear in the system's registered image viewer (out.show()) if no filename is available. I've applied thefox's fix and reuploaded.
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Post by koitsu »

Thank the Gods! The Coiler has slithered away, soon to re-coil itself to strike the next passerby.
3gengames
Formerly 65024U
Posts: 2284
Joined: Sat Mar 27, 2010 12:57 pm

Post by 3gengames »

This may be the most useful tool ever for one of my ideas, thanks! Can't wait to try it out.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

tepples wrote:The latest in the 2.7 series is probably the best, along with the corresponding version of PIL.
Any idea why the program failed in version 2.7.2 (PIL 1.1.7) for me then? Here's what I get:
File "D:\(long path)\App\lib\site-packages\PIL\
Image.py", line 1755, in new
return Image()._new(core.new(mode, size))
TypeError: integer argument expected, got float
I kinda like the idea of coding tools in Python, but I need to understand what's happening here before I can give it a try!
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

Thank you for your patience in helping me get various combinations of option flags to work.

On Python 2.7.2 and PIL 1.1.7, I managed to reproduce your problem: later versions don't like it when an image has a fractional size. But as before, my testing didn't have 100% coverage, as it goes away if I use the --pad option to explicitly set the output size. Try replacing this:

Code: Select all

        outsize = (ow, oh)
with this:

Code: Select all

        outsize = (int(round(ow)), int(round(oh)))
Keep in mind that Python is sensitive to the number of spaces before a line of code.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

When I said I needed to understand what was happening I didn't mean the error itself, but rather the reason why it was happening. You said that "the latest in the 2.7 series is probably the best", so I assumed that was what you were using, so I really puzzled when it worked for you and not for me.

I have to admit that I'm a bit worried about using Python to code my own development tools because of these little incompatibilities... I mean, the thing appears to change a lot from version to version. But I guess that if stick to a certain version and tell other people what version this is when sharing programs, things will be OK.
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

I've uploaded what I hope is a fixed version with these two minor bugs taken care of. So is it working any better for you now?
Post Reply