• jan@cosmigo.com

Pmotion2svg: Plug-in to Export to SVG

I’m glad to announce the release of pmotion2svg, a plug-in that allows exporting to the SVG format without losing the “Pixel Art look and feel”:

Example 1

Download

pmotion2svg is an open source plug-in, released under MIT License, and available on GitHub:

Precompiled binaries can be downloaded from the repository releases section:

Features

At export time, the user is presented with and options dialog where he/she can choose:

  • Scale Factor — how many SVG pixels will be used to represent each original pixel when drawing it as a filled square.
  • Padding — the amount of SVG pixels used as padding around the generated image.
  • Draw Pixels Grid — if checked, the generated image will display a 1px grid (black) between the original pixels and around the image.
  • Preserve Transparency — if an indexed image has a transparency color defined, you can choose whether to preserve its transparency or paint its original color as an SVG rectangle representing the image background.

Examples

Here are some examples of the same sprite exported with different settings:

Example 1

  • Scale factor: 5
  • Padding: none
  • Grid: none
  • Transparent color: preserve

Example 2

  • Scale factor: 5
  • Padding: none
  • Grid: draw
  • Transparent color: preserve

Example 3

  • Scale factor: 10
  • Padding: 10
  • Grid: draw
  • Transparent color: paint

Example 4

  • Scale factor: 2
  • Padding: none
  • Grid: draw
  • Transparent color: paint
1 Like

Nice! In the past I’d looked for a way to do exactly this back when I used Adobe Illustrator all the time - convert a raster image into vector, perfectly pixel for pixel. Never really found a good solution, though.

Did you think about supporting animation? SVGs support not only animation but even live filters, as you probably know. SVG is a pretty interesting file format.

Tried out your plugin and it worked just fine except for one problem - color. The resulting SVG’s color differ quite a bit from the PMNG project.

Resulting SVG (viewed in Chrome) on left, original sprite (viewed in PMNG) on right:



(image used: )

Is the native ‘Export Settings’ dialogue supposed to come up prior to the pmotion2svg setting dialogue? There’s a pixel scale setting in both dialogues. One must override the other, right?

I like the nice clean SVG code in the resulting SVGs if opened in notepad.

Yes and no.

Yes, in the sense that if and when I find some spare free time I wanted to allow exporting multi-frame animations as single SVG images. Unfortunately, the current file i/o interface doesn’t provide a DLL call dedicate to a user options dialog, so I’ll have to work around it in the call to each frame export to ensure that the user dialog is shown only once per task (it wouldn’t make sense to ask for settings at each frame).

No, in the sense that I haven’t looked into the possibility of creating an actual SVG animation. To achieve this I’d have to study more the SVG standards, and how they are actually supported by browsers and applications.

SVG animations are being mostly developed in the newer SVG standard, which is still a WIP and not stable (not mention that it’s poorly supported by most browsers), so chances are that this feature might be best postponed to a time when the standard is stable and browsers support it better.

I think this happens because most browsers don’t support color profiles — PM doesn’t either, though, but Windows 10 does fill in the gap by handling some color profiles on a per-app basis. See my post below on color profiles issues and tests:

Also, in the screenshot you’re using a white bg on the left and a black bg on the right, which further falsifies the colors perception in the human eye. A better comparison would have to use the same background color, but I’m sure that (unless you have a monitor color calibrator) colors will look different in every application, since PMNG, Gif/PNG and SVG don’t support color profiles.

The problem is that different applications will use different color profile fall-back defaults when dealing with image formats that don’t include color profile information (i.e. if the application does manage color profiles at all). Win 10 further complicates the problem because of its new way of handling color profiles, which allows you to specify which color profile to use for specific applications, and offers it’s own defaults if you don’t specify any.

I’ve carried out many tests and didn’t encounter any color discrepancies so far, but I have a color calibration tool and software which fixes the colors by correctly applying color profiles to all applications. Anyhow, I’ll do more tests on the color issues, but since we’re dealing with standard RGB color definitions there isn’t much that could have gone wrong on the plugin side really (it boils down to reading each color index from the bitmap to the corresponding RGB triplet in the palette bitmap).

@mathias, I’ve copied the sprite you’ve used for you tests and run them through the plugin and can confirm that some colors are in effect getting corrupted (at least, they look so in Chrome).

For some reason, it’s only the light blues, and I can’t understand why some colors are affected by not others.

The problem show up also on InkView (InkScape’s bundled viewer), so it’s definitely a problem with the actual palette.

The plugin couldn’t possibly get some colors right and others wrong, for it uses the same function to extract colors, so I suspect that it’s something to do with the export process itself. For example, if you tweak the project’s options and uncheck some palette depth options you get slightly different color results).

At this point, I’m not sure what’s affecting the palette entries. The plugin can only work based on the information it’s being passed by PM’s file I/O interface, so if colors are being reduced in the process there’s little that I can do.

The plugin doesn’t support True Color (because this part of the interface was never documented), so I wonder if this might be affecting the export process.

I’m quite confident that by rearranging the palette and getting rid of unused colors it should be possible to export the sprite with all its colors correct, but I’d like to understand where things are going wrong in the process.

I’ll do some more tests — what else can I do?

Bare in mind that I’ve created the plugin with the goal to be able to export sprites as vector illustrations to be used in eBooks, magazines articles, etc. So, if some settings and palette fiddling are required is still fine to this end, but surely it should work as expected with any 256 colors indexed image.

If I find a solution I will update the plugin, but it might take some time because free time is scarce right now. Thanks for reporting this!

EDITED — I was wrong, it was a bug, see my next post!


Ok @mathias, I do confirm that the problem is on PM side. I’ve selected the unused colors in the palette, set them to black and then optimized the palette so I’d get a linear color ramp, and when I export the modified image it looks just like the original.

Here’s a screenshot of the two SVGs in Chrome:

On the left is the SVG generated from your original Gif, on the right is the same image (as PMNG project) exported after optimizing the palette as mentioned above. As you can see, now the light blues are rendered correctly, no longer as greys.

Somehow, PMNG is exporting an out-of-synch palette via the file i/o interface — or at least, that’s the impression I get. Remapping the palette puts things right again. Probably it has something to do with the Gif image being imported into PMNG, maybe some internal palette values are not being updated before exporting.

These are only guesses on my side, but since the interface is a black-box I can’t do much more than speculate. Anyhow, allowing PMNG to optimize the palette seems to fix the internal problem.

Still, don’t underestimate how color profiles can always affect color quality when previewing the same image in different applications (and even screenshots might alter the original colors).

It Was a Bug! Fixed in v1.1.0

So @mathias, you were right about the colors being stray. Now the issue was fixed in version 1.1.0, which you can download here:

Please let me know if now everything is working fine.

As it turned out, it was a bug due to a quirk in the language I’ve used: pointers are actually signed integers, and when calculating the offset in the palette buffer it was casting the unsigned byte as a signed byte (hence, converting to negative values any palette entry above 128).

Unsigned types have always been a cause of hard to trace bugs — especially in languages which claim to be highly standardized and portable, like C:

Additionally, the casting quirks of the language I’ve used are not documented, and I didn’t imagine that pointers would be signed integers (a bad idea, especially if you have to do pointers math).

I eventually came to the conclusion of where the bug was while playing on the PS4 — in the back of my mind I kept thinking of the sample image you posted, and how some light blue colors where rendered as grays, while others as brown, and other colors. So I started to think that something was wrong with index offsets … and then it hit me! I remembered the pitfalls of mixed-signs operations, and how the language handled poorly type casting, and vaguely remembered reading a post where someone mentioned out that pointers were signed integers in the language. From there, it only took a single retouch of code and the problem was fixed — the original sprite you posted converted fine at first go!

So, mea culpa — nothing wrong with the PM interface. The reason why remapping the palette seemed to fix the problem was simply because it reduced colors to less than 127 (the max positive value the unsigned byte would allow, once cast to twos-complement, before being a negative integer).

Thanks for pointing this bug out, it would have been hard to catch and could have been creeping in the background for ages, hadn’t you spotted it.

I’ve credited you in the release 1.1.0 notes!