Skip to content

Add drawing bitmap images to Canvas - #4047

Merged
HalfWhitt merged 32 commits into
beeware:mainfrom
corranwebster:canvas-draw-image
Jan 12, 2026
Merged

Add drawing bitmap images to Canvas#4047
HalfWhitt merged 32 commits into
beeware:mainfrom
corranwebster:canvas-draw-image

Conversation

@corranwebster

@corranwebster corranwebster commented Jan 2, 2026

Copy link
Copy Markdown
Contributor

This adds a draw_image method to the Canvas class, along with a DrawImage subclass of DrawingObject that adds the ability to render an Image into Canvas with the current transforms applied. It currently supports the ability to draw an image at a point, or to draw an image into a destination rectangle, but doesn't currently support the ability to draw a slice out of the source image.

Has tests, and have added image drawing as one of the options in the Canvas example.

image

Fixes #955.

To Do:

  • Finish all the backends:
    • Android
    • cocoa
    • dummy
    • Gtk
    • iOS
    • Qt
    • Winforms
  • Documentation

PR Checklist:

  • All new features have been tested
  • All new features have been documented
  • I have read the CONTRIBUTING.md file
  • I will abide by the code of conduct

Not sure if I need to apply the matrix myself.

@corranwebster corranwebster left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some notes on the implementation.

I think this is ready for review.

Comment thread cocoa/src/toga_cocoa/libs/core_graphics.py
Comment thread iOS/src/toga_iOS/libs/core_graphics.py
Comment thread core/src/toga/widgets/canvas/context.py
@corranwebster
corranwebster marked this pull request as ready for review January 3, 2026 11:50

@HalfWhitt HalfWhitt left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HECK YES. I am excited about this!

I haven't had a chance to look at this yet as thoroughly as it deserves, but I have a couple of preliminary questions / comments.

Comment thread core/src/toga/widgets/canvas/context.py
Comment thread cocoa/src/toga_cocoa/widgets/canvas.py
# Have an UIImage, need a CGImage
cg_image = ui_image.CGImage

# Quartz is flipped relative to data, so we:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this true on iOS as well? I was under the impression that, unlike macOS, iOS always counts from the top left:

The default coordinate system for views in iOS and OS X differ in the orientation of the vertical axis:

  • OS X. The default coordinate system has its origin at the lower left of the drawing area; positive values extend up and to the right from it. You can programmatically “flip” a view’s coordinate system in OS X.
  • iOS. The default coordinate system has its origin at the upper left of the drawing area, and positive values extend down and to the right from it. You cannot change the default orientation of a view’s coordinate system in iOS—that is, you cannot “flip” it.

That said, I suppose I can't argue with test results, if this is working...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it has to be, given how it's working. I was a bit surprised on Cocoa that I had to flip the image and that the flipped coordinates flag didn't fix that automatically. I expect that something similar is happening on iOS. I think when you did down deep enough you get to Quartz which is very much a bottom-left origin system (which I think comes from PostScript originally!), no matter what you layer on top.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That does make sense... seems safe to file this under "Might be interesting to dig deeper on someday, but it works as intended."

@johnzhou721 johnzhou721 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 small notes here, from a quick look at this it seems that this is great, however I'm not very familiar with this part of the code.

Comment thread changes/995.feature.md Outdated
Comment thread cocoa/src/toga_cocoa/libs/core_graphics.py

@johnzhou721 johnzhou721 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked through this PR, and nothing's too concerning. But I'm not sufficiently familiar with Canvas -- let's wait for @HalfWhitt's opinion on this.

Comment thread cocoa/src/toga_cocoa/libs/core_graphics.py

@HalfWhitt HalfWhitt left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having sat down and looked through this, it looks perfect to me (with the exception of one minor copy-paste error, which I can fix). This is very thorough, thank you!

# Have an UIImage, need a CGImage
cg_image = ui_image.CGImage

# Quartz is flipped relative to data, so we:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That does make sense... seems safe to file this under "Might be interesting to dig deeper on someday, but it works as intended."

Comment thread core/tests/widgets/canvas/test_draw_operations.py Outdated
@HalfWhitt
HalfWhitt merged commit 3a4a810 into beeware:main Jan 12, 2026
41 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Raster image support in Canvas

3 participants