PNG erroring when loading to frame buffer

I have a black and white PNG with a width of 400px and height of 240px
400px * 240px

I'm trying to load it by file path directly into the frame buffer with display.loadImage("images/title") (the image is at source/images/title.png.

However, when running I get the following error dialogue:

[Window Title]
Loading Failed

[Main Instruction]
The file could not be loaded.

main.lua:13: loaded file properties don't match framebuffer's
stack traceback:
    [C]: in field 'loadImage'
    main.lua:13: in main chunk

[Retry] [Launcher] [Cancel]

The bit depth is set to 8, should this be 1?

Here are the file properties.

Hmm. I think you're trying to load a PNG rather than a compiled PDI?

PNG files (doesn't matter what bit depth, etc) are converted to PDI (Playdate image format) at compile time, when using pdc.
For this to happen they need to be in your Source folder.

And you should refer to them by filename without an extension in your code, but I think you know that judging by your code.

See Inside Playdate sections 3.2 and 3.3

1 Like

Thanks Matt,

I think the structure is correct though:


Sorry I was making a bunch of edits as this has me a bit puzzled.

What is the contents of your compiled pdx?

│   main.pdz
│   pdxinfo
│   SplashScreen.pdz
1 Like

That looks like it should.

I have no idea, it feels like a bug. I'll assign to Dan.

But, meanwhile you can swap this line:

...for this one, that works:"images/title"):draw(0,0)

project download: (1.8 KB)

1 Like

That displays the image correctly.

1 Like


Let's see what Dan says.

I'm not sure what is going on yet, but it does look like this may be a bug in the current release of the SDK. I was able to reproduce the problem with another image I created, so I don't think it is an issue with this particular image.

Thanks for letting us know about this!


Good to know. I'll quit trying to debug it myself then.

Thanks both.

Yikes. Turns out I broke that in May of 21 when I removed the 4-byte row alignment for images in order to make font storage more efficient. The framebuffer still has 52-byte rows, but a 400-pixel wide will use 50-byte rows, hence the mismatch. Using image:draw(0,0) will always work, but if you want to test how much faster display.loadImage() is you could pad the image out to 416x240 pixels--but then if I decide to change the framebuffer to 50-byte rows it'll break that.

There's probably a good reason I didn't do that? :thinking: Well, at the very least we should note this in the docs.

Padding the image manually is quite unintuitive.
Could the load function pad it automatically at runtime?

Sorry for the confusion, I didn't mean to imply that was a reasonable long-term solution, it's just a quick workaround if you wanted to test timing. Unfortunately I think adding the padding on the fly will lose the gain we get from decompressing the image data directly into the frame buffer--we'd have to load to temp storage first then copy row-by-row, which is pretty much what you're doing when you draw it with image:draw(0,0).

I think we'll probably drop that function. It's been broken for two years, so obviously nobody's using it.


Sorry, this is off topic but are you using IntelliJ IDEA for Playdate development? If is, how is that working out? What plugins are you using? How is the debugger? Thanks.


I was using it because JetBrains is my standard goto (albeit usually WebStorm and Rider), with the EmmyLua plugin, however I moved to VS Code.

With the correct setup, VSCode is a better UX than IntelliJ for Lua.

Thanks David. I'm also a big fan of Jetbrains IDEs but was surprised to see you using it for Playdate.

It's 2024-02-25, using PlayDate Simulator Version 2.3.1 (165008), Nova 11.8 (Build 573039), and Section 6.16 Display documents the loadImage function. The problem still persists.

And the workaround,"images/foobar"):draw(0,0) does as well.

I'd really like to see this function fixed, rather than deprecated or removed.

I'm also curious about the bug details, as it seems like that function could, at least for the time being, be aliased to the one-liner above. Is it trying to do a high-speed copy to the frame buffer?