Previously, calling `.right()` on a `Gfx::Rect` would return the last
column's coordinate still inside the rectangle, or `left + width - 1`.
This is called 'endpoint inclusive' and does not make a lot of sense for
`Gfx::Rect<float>` where a rectangle of width 5 at position (0, 0) would
return 4 as its right side. This same problem exists for `.bottom()`.
This changes `Gfx::Rect` to be endpoint exclusive, which gives us the
nice property that `width = right - left` and `height = bottom - top`.
It enables us to treat `Gfx::Rect<int>` and `Gfx::Rect<float>` exactly
the same.
All users of `Gfx::Rect` have been updated accordingly.
This commit adds a "Apply Mask" action which merges the active layer
mask with the layer bitmap. The option is only displayed if the active
layer is masked.
This makes undoing actions performed on layer masks work as
expected.
did_modify_bitmap() is now also called on redo, to ensure the layer
mask is displayed correctly.
This commit expands the functionality of the "Crop Image to Content"
and "Crop Layer to Content" features by allowing them to detect and
crop the background color of an image instead of just cropping
transparent pixels.
The background color is determined by looking at the corner pixels of
the image. If no background color is found, the old behavior of
cropping transparent pixels is retained.
We now propagate errors when using the {Layer,Image}::flip(),
{Layer,Image}::crop(), {Layer,Image}::rotate() and
{Layer,Image}::resize() functions.
We handle these errors by show an error DialogBox with the error's
message.
This removes 8 FIXMEs:))
We have a new, improved string type coming up in AK (OOM aware, no null
state), and while it's going to use UTF-8, the name UTF8String is a
mouthful - so let's free up the String name by renaming the existing
class.
Making the old one have an annoying name will hopefully also help with
quick adoption :^)
This PR adds resize ability to PixelPaint as per issue 11862.
The previous behaviour was to always rescale the canvas when
resizing an image. This adds a checkbox to toggle between
rescaling, and resizing which blits the existing canvas to
the top left of the new, resized canvas.
As part of this, a new ScalingMode is added to
LibGfx - None.
This effectively creates a double-buffer for tools to use when modifying
the layer's bitmap (content or mask). Once the changes have been made
the tool reports to the layer that it has made changes along with a Rect
of the changed region. The layer will then merge the changes from the
scratch image to the real bitmap. This merge is done as follows: If a
given pixel is inside the selected region, the pixel from the scratch
bitmap is copied to the real bitmap. If the pixel is not inside the
selected region, the pixel from the real bitmap is copied to the scratch
bitmap.
As an optimization, when there is no selection active, the new method
for getting the scratch bitmap will return the real bitmap and no
merging will need to take place.
This fixes a bug which shows up when a layer is offset and the selection
range includes pixels that are outside the current layer bitmap rect. We
would still try to delete that pixel from the bitmap since there was no
contains() check.
Layer::erase_selection used to erase the entire bounding box of the
selection. With the add/subtract merge modes for the selection tool it
is possible to create selections which are not rectangular. This leads
to deleting pixels that were not selected.
This change adjusts the erase behavior to walk the selection rect and
check if a pixel is selected or not before deleting.
This command finds the smallest non-empty content bounding rect
by looking for the outermost non-transparent pixels in the image,
and then crops the image to that rect.
It's implemented in a pretty naive way, but it's a start. :^)
Error::from_string_literal now takes direct char const*s, while
Error::from_string_view does what Error::from_string_literal used to do:
taking StringViews. This change will remove the need to insert `sv`
after error strings when returning string literal errors once
StringView(char const*) is removed.
No functional changes.
-Layer now has methods for flip/rotate/crop, which are responsible
for handling the alpha mask.
-Fixed crash when the display image size is out of sync with
the content image size.
-Changed API for setting content and mask image in Layer. Now, both
must be set at the same time, and it can result in an error if
you provide mismatched dimensions.
This is in preparation to support masking of Layers. We now distinguish
between the "display_bitmap" which will be the whole Layer with every
effect applied and the "content_bitmap" which contains the actual
unmodified pixels in the Layer.
Let's give ourselves the tools needed to update less than the entire
image every time we paint.
This patch adds plumbing so that Layer invalidations have a modified
rect that gets passed on to Image, and then on to ImageEditor.
This replaces the naive copy algorithm that only supported rectangular
and 100% opaque selections with a more general approach that supports
any shape and alpha value.
Note that we now make a brand new bitmap with a hardcoded format instead
of just cropping the layer's existing bitmap. This is done to ensure
that the final clipboard image will have an alpha channel.
This patch adds a GUI::TabWidget to the main UI and allows having
multiple images open at the same time.
Some of the changes here are a bit hackish and mechanical and there's
still code around that needs more work to fit better in the new world.
One nice side-effect of this change is that ImageEditor now always
has one Image associated with it, and it never changes.
SPDX License Identifiers are a more compact / standardized
way of representing file license information.
See: https://spdx.dev/resources/use/#identifiers
This was done with the `ambr` search and replace tool.
ambr --no-parent-ignore --key-from-file --rep-from-file key.txt rep.txt *
This fixes a bug where the application would crash if the user
changed the default values for opacity or visibility of a layer
and then tried to draw on it.
The previous names (RGBA32 and RGB32) were misleading since that's not
the actual byte order in memory. The new names reflect exactly how the
color values get laid out in bitmap data.