Import Export for pbm, pgm, ppm files (PNM family)

Hi all,

I’ve been working on a Lua script to import and export files in the PNM family. The script is aimed at Aseprite version 1.2.40 or later. The code can be downloaded at the following Github repo:

PNM includes the extensions pbm, pgm and ppm. In summary:

  • pbm is a black-or-white, one-bit file. 1 is black, 0 is white. Like many other pbm readers, this inverts to match the more common convention.
  • pgm is grayscale.
  • ppm supports red, green and blue (RGB).

All three formats can be either ASCII or binary. None of the three support alpha. Grayscale (pgm) and RGB (ppm) allow the maximum channel value to be set up to 255.

None support multiple layers or multiple frames. For that reason, the script exports a flattened version of the active sprite at the active frame. (I recently added some CLI options for more flexibility).

The dialog UI looks like this in the default light theme, 200% screen scale, 100% UI scale.

dialogUi2

Below is an example ppm file (upscaled 10x as a png):

example1Binary

In a text editor, the ASCII version looks like this:

P3
9 16
255
220 058 058 182 037 079 151 028 090 137 036 105 132 038 109 137 036 105 151 028 090 182 037 079 220 058 058
142 033 100 104 047 120 081 064 143 057 078 153 045 082 155 057 078 153 081 064 143 104 047 120 142 033 100
081 064 143 000 094 156 000 109 156 000 118 156 000 122 155 000 118 156 000 109 156 000 094 156 081 064 143
000 103 156 000 126 155 000 143 149 000 152 133 000 154 126 000 152 133 000 143 149 000 126 155 000 103 156
000 129 154 000 152 133 042 171 096 115 190 069 138 196 059 115 190 069 042 171 096 000 152 133 000 129 154
000 149 140 065 178 089 166 207 048 213 219 027 227 220 025 213 219 027 166 207 048 065 178 089 000 149 140
000 157 107 151 201 054 227 220 025 255 199 017 255 179 018 255 199 017 227 220 025 151 201 054 000 157 107
042 171 096 181 212 041 254 217 023 252 151 028 238 103 044 252 151 028 254 217 023 181 212 041 042 171 096
042 171 096 181 212 041 254 217 023 252 151 028 238 103 044 252 151 028 254 217 023 181 212 041 042 171 096
000 157 107 151 201 054 227 220 025 255 199 017 255 179 018 255 199 017 227 220 025 151 201 054 000 157 107
000 149 140 065 178 089 166 207 048 213 219 027 227 220 025 213 219 027 166 207 048 065 178 089 000 149 140
000 129 154 000 152 133 042 171 096 115 190 069 138 196 059 115 190 069 042 171 096 000 152 133 000 129 154
000 103 156 000 126 155 000 143 149 000 152 133 000 154 126 000 152 133 000 143 149 000 126 155 000 103 156
081 064 143 000 094 156 000 109 156 000 118 156 000 122 155 000 118 156 000 109 156 000 094 156 081 064 143
142 033 100 104 047 120 081 064 143 057 078 153 045 082 155 057 078 153 081 064 143 104 047 120 142 033 100
220 058 058 182 037 079 151 028 090 137 036 105 132 038 109 137 036 105 151 028 090 182 037 079 220 058 058

The P3 header indicates the RGB format. The image’s size is 9 x 16. Its maximum channel is 255. The first color, in the top left corner, is 220 red, 58 green, 58 blue.

Viewed in a hex editor, the binary version looks like this:

The first color, in the top left corner, is 0xdc red, 0x3a green, 0x3a blue.

I’ve done some testing with imports from and exports to GIMP, Krita and XnView MP. There are a few things this script may do differently from other graphics editors.

  • It does not dither the image on export to a one-bit file (pbm). For XnView converting to 1-bit is a separate step.

pbmCompare

  • It does not try to correct colors with zero alpha. For example transparent red (0x000000ff) does not become opaque black (0xff000000).
  • Both grayscale (pgm) and one-bit (pbm) rely on Aseprite’s definition of luma.
  • Values are rounded, not floored, so for example 50% would be 128 (0x80), not 127 (0x7f).
  • Color quantization to a reduced level is signed, not unsigned.

  • The script expects line breaks to separate the main elements of the file header, so one-liner files will probably not work.

I first heard of these file formats from a feature request on the Aseprite Github repo:

Thanks for your interest. Happy Halloween! :jack_o_lantern:
Jeremy

2 Likes