From c99d91195bfe252271b53a4d3d89fdb417c6fb0e Mon Sep 17 00:00:00 2001 From: Erik Corry Date: Tue, 19 Dec 2023 15:10:24 +0100 Subject: [PATCH 1/8] Allow --text on Labels instead of --label. --- src/element.toit | 41 +++++++++++-------- tests/bitmap-visualized.toit | 2 +- tests/drop-shadow-gray-window-visualized.toit | 2 +- tests/drop-shadow-window-visualized.toit | 2 +- tests/gray-scale-visualized.toit | 6 +-- tests/mixed-text-rotated-visualized.toit | 4 +- tests/mixed-text-visualized.toit | 4 +- tests/rounded-gray-window-visualized.toit | 2 +- tests/rounded-huge-window-visualized.toit | 2 +- tests/rounded-several-window-visualized.toit | 2 +- ...rounded-three-color-window-visualized.toit | 2 +- .../rounded-two-color-window-visualized.toit | 2 +- tests/rounded-window-visualized.toit | 2 +- tests/simple-several-window-visualized.toit | 2 +- .../simple-three-color-window-visualized.toit | 2 +- tests/simple-two-color-window-visualized.toit | 2 +- tests/text-visualized.toit | 6 +-- tests/true-color-portrait-visualized.toit | 6 +-- 18 files changed, 50 insertions(+), 41 deletions(-) diff --git a/src/element.toit b/src/element.toit index 9ec32ca..835692d 100644 --- a/src/element.toit +++ b/src/element.toit @@ -326,7 +326,7 @@ Like other elements it can have a background, but it is not intended to have */ class Label extends Element implements ColoredElement: color_/int := ? - label_/string := ? + text_/string := ? alignment_/int := ? orientation_/int := ? font_/Font? := ? @@ -347,7 +347,9 @@ class Label extends Element implements ColoredElement: else if key == "alignment": alignment = value else if key == "label": - label = value + text = value + else if key == "text": + text = value else if key == "icon": icon = value else: @@ -370,7 +372,7 @@ class Label extends Element implements ColoredElement: icon= value/Icon -> none: font = value.font_ - label = value.stringify + text = value.stringify /** Constructs a Label. @@ -380,9 +382,11 @@ class Label extends Element implements ColoredElement: The $alignment is one of $ALIGN-LEFT, $ALIGN-CENTER, or $ALIGN-RIGHT. The $orientation is one of $ORIENTATION-0, $ORIENTATION-90, $ORIENTATION-180, or $ORIENTATION-270. + The $label argument is equivalent to the $text argument. The $text + argument is preferred. The $color, $font, $orientation, and $alignment can be set using styles - instead of here in the constructor. The label (text) can be set and - changed later with the label setter. Like any change of appearance + instead of here in the constructor. The $text can be set and + changed later with the text setter. Like any change of appearance in an element, it doesn't become visible until the $PixelDisplay.draw method is called. See $Element.constructor for the other arguments. @@ -394,13 +398,15 @@ class Label extends Element implements ColoredElement: --classes/List?=null --id/string?=null --color/int=0 - --label/string="" + --label/string?=null + --text/string?=null --font/Font?=null --icon/Icon?=null --orientation/int=ORIENTATION-0 --alignment/int=ALIGN-LEFT: color_ = color - label_ = label + if label and text: throw "INVALID_ARGUMENT" + text_ = text or label or "" alignment_ = alignment orientation_ = orientation font_ = font @@ -419,10 +425,10 @@ class Label extends Element implements ColoredElement: */ xywh_ [block]: if not left_: - extent/List := font_.text-extent label_ + extent/List := font_.text-extent text_ displacement := 0 if alignment_ != ALIGN-LEFT: - displacement = (font_.pixel-width label_) + displacement = (font_.pixel-width text_) if alignment_ == ALIGN-CENTER: displacement >>= 1 l := extent[2] - displacement r := extent[2] - displacement + extent[0] @@ -462,21 +468,24 @@ class Label extends Element implements ColoredElement: return height_ invalidate: - if change-tracker and x and y and font_ and label_: + if change-tracker and x and y and font_ and text_: xywh_: | x y w h | change-tracker.child-invalidated x y w h label= value/string -> none: - if value == label_: return + text = value + + text= value/string -> none: + if value == text_: return if orientation_ == ORIENTATION-0 and change-tracker and x and y: - text-get-bounding-boxes_ label_ value alignment_ font_: | old/TextExtent_ new/TextExtent_ | + text-get-bounding-boxes_ text_ value alignment_ font_: | old/TextExtent_ new/TextExtent_ | change-tracker.child-invalidated (x_ + old.x) (y_ + old.y) old.w old.h change-tracker.child-invalidated (x_ + new.x) (y_ + new.y) new.w new.h - label_ = value + text_ = value left_ = null // Trigger recalculation. return invalidate - label_ = value + text_ = value left_ = null // Trigger recalculation. invalidate @@ -499,7 +508,7 @@ class Label extends Element implements ColoredElement: y := y_ if not (x and y): return if alignment_ != ALIGN-LEFT: - text-width := font_.pixel-width label_ + text-width := font_.pixel-width text_ if alignment_ == ALIGN-CENTER: text-width >>= 1 if orientation_ == ORIENTATION-0: x -= text-width @@ -510,7 +519,7 @@ class Label extends Element implements ColoredElement: else: assert: orientation_ == ORIENTATION-270 y -= text-width - canvas.text x y --text=label_ --color=color_ --font=font_ --orientation=orientation_ + canvas.text x y --text=text_ --color=color_ --font=font_ --orientation=orientation_ /** A superclass for elements that can draw themselves. Override the diff --git a/tests/bitmap-visualized.toit b/tests/bitmap-visualized.toit index 4b1a6d6..36aa4c3 100644 --- a/tests/bitmap-visualized.toit +++ b/tests/bitmap-visualized.toit @@ -47,7 +47,7 @@ do basename/string w/int h/int: display.draw - label := Label --x=44 --y=44 --label="UP ^" --font=SANS --color=0 + label := Label --x=44 --y=44 --text="UP ^" --font=SANS --color=0 display.add label png-element := Png --x=36 --y=32 --png-file=purifier display.add png-element diff --git a/tests/drop-shadow-gray-window-visualized.toit b/tests/drop-shadow-gray-window-visualized.toit index 9df7175..e4b2688 100644 --- a/tests/drop-shadow-gray-window-visualized.toit +++ b/tests/drop-shadow-gray-window-visualized.toit @@ -37,7 +37,7 @@ main args: gradient-element := Div --x=0 --y=0 --w=180 --h=100 --background=gradient win.add gradient-element - text := Label --x=90 --y=55 --label="Hello, World!" --font=sans10 --color=0x10 + text := Label --x=90 --y=55 --text="Hello, World!" --font=sans10 --color=0x10 win.add text display.draw diff --git a/tests/drop-shadow-window-visualized.toit b/tests/drop-shadow-window-visualized.toit index bee7513..a1fa212 100644 --- a/tests/drop-shadow-window-visualized.toit +++ b/tests/drop-shadow-window-visualized.toit @@ -37,7 +37,7 @@ main args: gradient-element := Div --x=0 --y=0 --w=180 --h=100 --background=gradient win.add gradient-element - text := Label --x=90 --y=55 --label="Hello, World!" --font=sans10 --color=0x101040 + text := Label --x=90 --y=55 --text="Hello, World!" --font=sans10 --color=0x101040 win.add text display.draw diff --git a/tests/gray-scale-visualized.toit b/tests/gray-scale-visualized.toit index 844503f..f18d280 100644 --- a/tests/gray-scale-visualized.toit +++ b/tests/gray-scale-visualized.toit @@ -21,14 +21,14 @@ main args: display.add Div --x=10 --y=20 --w=30 --h=40 --background=0x80 display.add - Label --x=50 --y=20 --label="Testing" --font=sans10 --color=0xc0 + Label --x=50 --y=20 --text="Testing" --font=sans10 --color=0xc0 - middle-line := Label --x=50 --y=40 --label="the display" --font=sans10 --color=0xc0 + middle-line := Label --x=50 --y=40 --text="the display" --font=sans10 --color=0xc0 display.add middle-line display.draw display.add - Label --x=50 --y=60 --label="for the win" --font=sans10 --color=0xc0 + Label --x=50 --y=60 --text="for the win" --font=sans10 --color=0xc0 display.draw diff --git a/tests/mixed-text-rotated-visualized.toit b/tests/mixed-text-rotated-visualized.toit index d793d8e..f689028 100644 --- a/tests/mixed-text-rotated-visualized.toit +++ b/tests/mixed-text-rotated-visualized.toit @@ -22,8 +22,8 @@ main args: sans10 := Font.get "sans10" // Element-based text. - element-text := Label --x=10 --y=30 --color=SEVERAL-GREEN --font=sans10 --label="Element 1" - element-text-2 := Label --x=10 --y=110 --color=SEVERAL-GREEN --font=sans10 --label="Element 2" + element-text := Label --x=10 --y=30 --color=SEVERAL-GREEN --font=sans10 --text="Element 1" + element-text-2 := Label --x=10 --y=110 --color=SEVERAL-GREEN --font=sans10 --text="Element 2" display.add element-text display.add element-text-2 display.draw diff --git a/tests/mixed-text-visualized.toit b/tests/mixed-text-visualized.toit index db50a27..f76acb9 100644 --- a/tests/mixed-text-visualized.toit +++ b/tests/mixed-text-visualized.toit @@ -21,8 +21,8 @@ main args: sans10 := Font.get "sans10" // Element-based rectangles. - element-text := Label --x=30 --y=30 --color=SEVERAL-ORANGE --label="joo%" --font=sans10 - element-text-2 := Label --x=130 --y=20 --color=SEVERAL-ORANGE --label="joo%" --font=sans10 + element-text := Label --x=30 --y=30 --color=SEVERAL-ORANGE --text="joo%" --font=sans10 + element-text-2 := Label --x=130 --y=20 --color=SEVERAL-ORANGE --text="joo%" --font=sans10 display.add element-text display.add element-text-2 display.draw diff --git a/tests/rounded-gray-window-visualized.toit b/tests/rounded-gray-window-visualized.toit index 583b8ea..1e6b8a1 100644 --- a/tests/rounded-gray-window-visualized.toit +++ b/tests/rounded-gray-window-visualized.toit @@ -37,7 +37,7 @@ main args: gradient-element := Div --x=0 --y=0 --w=180 --h=100 --background=gradient win.add gradient-element - text := Label --x=90 --y=55 --label="Hello, World!" --font=sans10 --color=0x10 + text := Label --x=90 --y=55 --text="Hello, World!" --font=sans10 --color=0x10 win.add text display.draw diff --git a/tests/rounded-huge-window-visualized.toit b/tests/rounded-huge-window-visualized.toit index 8ee8509..b7b8729 100644 --- a/tests/rounded-huge-window-visualized.toit +++ b/tests/rounded-huge-window-visualized.toit @@ -39,7 +39,7 @@ main args: gradient-element := Div --x=0 --y=0 --w=180 --h=180 --background=gradient win.add gradient-element - text := Label --x=90 --y=55 --label="Hello, World!" --font=sans10 --color=0x101040 + text := Label --x=90 --y=55 --text="Hello, World!" --font=sans10 --color=0x101040 win.add text display.draw diff --git a/tests/rounded-several-window-visualized.toit b/tests/rounded-several-window-visualized.toit index 1fae3a5..ffb5963 100644 --- a/tests/rounded-several-window-visualized.toit +++ b/tests/rounded-several-window-visualized.toit @@ -20,7 +20,7 @@ main args: win := Div.clipping --x=30 --y=30 --w=180 --h=100 --background=SEVERAL-LIGHT-GRAY --border=(RoundedCornerBorder --radius=15) display.add win - text := Label --x=90 --y=55 --label="Hello, World!" --font=sans10 --color=SEVERAL-BLACK + text := Label --x=90 --y=55 --text="Hello, World!" --font=sans10 --color=SEVERAL-BLACK win.add text display.draw diff --git a/tests/rounded-three-color-window-visualized.toit b/tests/rounded-three-color-window-visualized.toit index 91bf9d1..aeb222b 100644 --- a/tests/rounded-three-color-window-visualized.toit +++ b/tests/rounded-three-color-window-visualized.toit @@ -21,7 +21,7 @@ main args: win := Div.clipping --x=30 --y=30 --w=180 --h=100 --background=RED --border=(RoundedCornerBorder --radius=17) display.add win - text := Label --x=90 --y=55 --label="Hello, World!" --font=sans10 --color=BLACK + text := Label --x=90 --y=55 --text="Hello, World!" --font=sans10 --color=BLACK win.add text display.draw diff --git a/tests/rounded-two-color-window-visualized.toit b/tests/rounded-two-color-window-visualized.toit index 4fd2f97..c2bc079 100644 --- a/tests/rounded-two-color-window-visualized.toit +++ b/tests/rounded-two-color-window-visualized.toit @@ -21,7 +21,7 @@ main args: win := Div.clipping --x=30 --y=30 --w=180 --h=100 --background=WHITE --border=(RoundedCornerBorder --radius=17) display.add win - text := Label --x=90 --y=55 --label="Hello, World!" --font=sans10 --color=BLACK + text := Label --x=90 --y=55 --text="Hello, World!" --font=sans10 --color=BLACK win.add text display.draw diff --git a/tests/rounded-window-visualized.toit b/tests/rounded-window-visualized.toit index fcd2695..1632cef 100644 --- a/tests/rounded-window-visualized.toit +++ b/tests/rounded-window-visualized.toit @@ -37,7 +37,7 @@ main args: gradient-element := Div --x=0 --y=0 --w=180 --h=100 --background=gradient win.add gradient-element - text := Label --x=90 --y=55 --label="Hello, World!" --font=sans10 --color=0x101040 + text := Label --x=90 --y=55 --text="Hello, World!" --font=sans10 --color=0x101040 win.add text display.draw diff --git a/tests/simple-several-window-visualized.toit b/tests/simple-several-window-visualized.toit index 3f10646..31c7d90 100644 --- a/tests/simple-several-window-visualized.toit +++ b/tests/simple-several-window-visualized.toit @@ -20,7 +20,7 @@ main args: win := Div.clipping --x=30 --y=30 --w=180 --h=100 --background=SEVERAL-LIGHT-GRAY display.add win - text := Label --x=90 --y=55 --label="Hello, World!" --font=sans10 --color=SEVERAL-BLACK + text := Label --x=90 --y=55 --text="Hello, World!" --font=sans10 --color=SEVERAL-BLACK win.add text display.draw diff --git a/tests/simple-three-color-window-visualized.toit b/tests/simple-three-color-window-visualized.toit index 7e42410..5e136c5 100644 --- a/tests/simple-three-color-window-visualized.toit +++ b/tests/simple-three-color-window-visualized.toit @@ -21,7 +21,7 @@ main args: win := Div.clipping --x=30 --y=30 --w=180 --h=100 --background=RED display.add win - text := Label --x=90 --y=55 --label="Hello, World!" --font=sans10 --color=BLACK + text := Label --x=90 --y=55 --text="Hello, World!" --font=sans10 --color=BLACK win.add text display.draw diff --git a/tests/simple-two-color-window-visualized.toit b/tests/simple-two-color-window-visualized.toit index f636f1a..33a7c67 100644 --- a/tests/simple-two-color-window-visualized.toit +++ b/tests/simple-two-color-window-visualized.toit @@ -21,7 +21,7 @@ main args: win := Div.clipping --x=30 --y=30 --w=180 --h=100 display.add win - text := Label --x=90 --y=55 --label="Hello, World!" --font=sans10 --color=BLACK + text := Label --x=90 --y=55 --text="Hello, World!" --font=sans10 --color=BLACK win.add text display.draw diff --git a/tests/text-visualized.toit b/tests/text-visualized.toit index 71a2a8c..a46897d 100644 --- a/tests/text-visualized.toit +++ b/tests/text-visualized.toit @@ -21,9 +21,9 @@ main args: sans10 := Font.get "sans10" - element-text := Label --x=30 --y=20 --color=SEVERAL-ORANGE --label="Testing 123" --font=sans10 - element-text-2 := Label --x=180 --y=50 --color=SEVERAL-ORANGE --label="123 Testing" --font=sans10 --alignment=ALIGN-RIGHT - element-text-3 := Label --x=96 --y=80 --color=SEVERAL-ORANGE --label="T 123 For the win" --font=sans10 --alignment=ALIGN-CENTER + element-text := Label --x=30 --y=20 --color=SEVERAL-ORANGE --text="Testing 123" --font=sans10 + element-text-2 := Label --x=180 --y=50 --color=SEVERAL-ORANGE --text="123 Testing" --font=sans10 --alignment=ALIGN-RIGHT + element-text-3 := Label --x=96 --y=80 --color=SEVERAL-ORANGE --text="T 123 For the win" --font=sans10 --alignment=ALIGN-CENTER display.add element-text display.add element-text-2 display.add element-text-3 diff --git a/tests/true-color-portrait-visualized.toit b/tests/true-color-portrait-visualized.toit index 0974044..43062db 100644 --- a/tests/true-color-portrait-visualized.toit +++ b/tests/true-color-portrait-visualized.toit @@ -25,13 +25,13 @@ main args: display.add Div --x=20 --y=70 --w=30 --h=40 --background=0x4040ff display.add - Label --x=5 --y=80 --label="Testing" --font=sans10 --color=foreground - middle-line := Label --x=5 --y=100 --label="the display" --font=sans10 --color=foreground + Label --x=5 --y=80 --text="Testing" --font=sans10 --color=foreground + middle-line := Label --x=5 --y=100 --text="the display" --font=sans10 --color=foreground display.add middle-line display.draw display.add - Label --x=5 --y=120 --label="for the win" --font=sans10 --color=foreground + Label --x=5 --y=120 --text="for the win" --font=sans10 --color=foreground display.draw From 895ad5af1be11a4c7e9e3c62b9f2c2ddc50755c5 Mon Sep 17 00:00:00 2001 From: Erik Corry Date: Sun, 31 Dec 2023 15:18:01 +0100 Subject: [PATCH 2/8] feedback --- src/element.toit | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/element.toit b/src/element.toit index 835692d..74d4b2a 100644 --- a/src/element.toit +++ b/src/element.toit @@ -4,10 +4,6 @@ import binary show LITTLE-ENDIAN import bitmap show * -import .four-gray as four-gray -import .true-color as true-color -import .gray-scale as gray-scale -import .one-byte_ as one-byte import .style show * import .pixel-display import font show Font @@ -346,9 +342,7 @@ class Label extends Element implements ColoredElement: orientation = value else if key == "alignment": alignment = value - else if key == "label": - text = value - else if key == "text": + else if key == "text" or key == "label": text = value else if key == "icon": icon = value From f76040e8ad15f0cde9781e8486e31284fda0f602 Mon Sep 17 00:00:00 2001 From: Erik Corry Date: Wed, 28 Feb 2024 15:21:37 +0100 Subject: [PATCH 3/8] Add ability to color-transform PNG images --- src/png.toit | 75 +++++++++++++++++- tests/bitmap-2-visualized.toit | 14 +++- tests/gold/bitmap-2-visualized.toit.png | Bin 7622 -> 11507 bytes .../three-color-bitmap-2-visualized.toit.png | Bin 1073 -> 1403 bytes tests/three-color-bitmap-2-visualized.toit | 12 ++- 5 files changed, 98 insertions(+), 3 deletions(-) diff --git a/src/png.toit b/src/png.toit index 3921827..bf33219 100644 --- a/src/png.toit +++ b/src/png.toit @@ -36,6 +36,11 @@ Only PNGs with up to 8 bits per pixel are supported. They can be */ class Png extends CustomElement: png_/png-reader.AbstractPng + last-palette_/ByteArray? := null + last-alpha-palette_/ByteArray? := null + last-transformed-palette_/ByteArray? := null + last-transformed-alpha-palette_/ByteArray? := null + palette-transformer_/Lambda? := null /** Constructs an element that displays a PNG image, given a byte array @@ -51,7 +56,10 @@ class Png extends CustomElement: --id/string?=null --background=null --border/Border?=null - --png-file/ByteArray: + --png-file/ByteArray + --color/int?=null + --palette-transformer/Lambda?=null: + palette-transformer_ = palette-transformer info := png-reader.PngInfo png-file if info.uncompressed-random-access: png_ = png-reader.PngRandomAccess png-file @@ -69,6 +77,51 @@ class Png extends CustomElement: --id = id --background = background --border = border + if color: this.color = color + + /** + Causes the PNG to be redrawn with new values from the palette transformer. + */ + invalidate-palette-transformer -> none: + invalidate + last-transformed-palette_ = null + last-transformed-alpha-palette_ = null + + /** + Causes the palette of the PNG to be ignored, and all pixels will + be drawn with the given color. Alpha (transparency) will be + unchanged. + */ + color= value/int -> none: + invalidate-palette-transformer + palette-transformer_ = :: | r g b a | + #[value >> 16, value >> 8, value, a] + + set-attribute_ key/string value -> none: + if key == "color": + color = value + else: + super key value + /** + The $palette-transformer is an optional Lambda that transforms + the colors in the PNG. The arguments are red, green, blue, and + alpha, all integers from 0-255. It is expected to return a + 4-element ByteArray with the transformed red, green, blue, and + alpha values. This can be used for example if you have a PNG + that is black-and-transparent, and you want to display it as an + image that is red-and-transparent. The returned ByteArray does + not have to be fresh on each invocation. + The palette transformer is not called eagerly, so if it is + going to return new values (eg. to change the color of the PNG) + you must call $invalidate-palette-transformer. + A simpler way to use palette transformation is to simply set the + color on this element. This will cause all PNG pixels to be + drawn with the same color, but alpha (transparency) will still + be taken from the PNG file. + */ + palette-transformer= value/Lambda?: + invalidate-palette-transformer + palette-transformer_ = value // Redraw routine. custom-draw canvas/Canvas: @@ -77,6 +130,26 @@ class Png extends CustomElement: png_.get-indexed-image-data y2 h --accept-8-bit=canvas.supports-8-bit --need-gray-palette=canvas.gray-scale: | y-from/int y-to/int bits-per-pixel/int pixels/ByteArray line-stride/int palette/ByteArray alpha-palette/ByteArray | + if palette-transformer_: + if palette != last-palette_ or alpha-palette != last-alpha-palette_: + if last-transformed-alpha-palette_ == null or + last-transformed-palette_.size != palette.size: + last-transformed-palette_ = ByteArray palette.size + if last-transformed-alpha-palette_ == null or + last-transformed-alpha-palette_.size != palette.size: + last-transformed-alpha-palette_ = ByteArray palette.size + (palette.size / 3).repeat: | i | + transformed := palette-transformer_.call + palette[i * 3] + palette[i * 3 + 1] + palette[i * 3 + 2] + i >= alpha-palette.size ? 0xff : alpha-palette[i] + last-transformed-palette_[i * 3] = transformed[0] + last-transformed-palette_[i * 3 + 1] = transformed[1] + last-transformed-palette_[i * 3 + 2] = transformed[2] + last-transformed-alpha-palette_[i] = transformed[3] + palette = last-transformed-palette_ + alpha-palette = last-transformed-alpha-palette_ if bits-per-pixel == 1: // Last line a little shorter because it has no stride padding. adjust := line-stride - ((round-up w 8) >> 3) diff --git a/tests/bitmap-2-visualized.toit b/tests/bitmap-2-visualized.toit index 3093005..cc2d31c 100644 --- a/tests/bitmap-2-visualized.toit +++ b/tests/bitmap-2-visualized.toit @@ -22,7 +22,7 @@ main args: basename := args[0] - driver := TrueColorPngVisualizer 524 240 basename --outline=0xffffff + driver := TrueColorPngVisualizer 800 240 basename --outline=0xffffff display := PixelDisplay.true-color driver display.background = 0xe0e080 @@ -39,12 +39,21 @@ main args: heater-translucent := file.read-content "tests/third_party/pictogrammers/heater-translucent.png" heater-translucent-uncompressed := file.read-content "tests/third_party/pictogrammers/heater-translucent-uncompressed.png" + swap-red-and-black := :: | r/int g/int b/int a/int | + if r > 0x80: + #[0, 0, 0, a] + else: + #[0xff, 0, 0, a] + display.add (Png --x=16 --y=32 --png-file=heater) display.add (Png --x=100 --y=32 --png-file=heater-4-bit) display.add (Png --x=184 --y=32 --png-file=heater-2-bit) display.add (Png --x=268 --y=32 --png-file=heater-bw) display.add (Png --x=352 --y=32 --png-file=heater-white-bg) display.add (Png --x=436 --y=32 --png-file=heater-translucent) + display.add (Png --x=520 --y=32 --png-file=heater-4-bit --color=0x4080ff) + display.add (Png --x=604 --y=32 --png-file=heater-4-bit --palette-transformer=swap-red-and-black) + display.add (Png --x=688 --y=32 --png-file=heater-bw --color=0x20ffe0) display.add (Png --x=16 --y=120 --png-file=heater-uncompressed) display.add (Png --x=100 --y=120 --png-file=heater-4-bit-uncompressed) @@ -52,6 +61,9 @@ main args: display.add (Png --x=268 --y=120 --png-file=heater-bw-uncompressed) display.add (Png --x=352 --y=120 --png-file=heater-white-bg-uncompressed) display.add (Png --x=436 --y=120 --png-file=heater-translucent-uncompressed) + display.add (Png --x=520 --y=120 --png-file=heater-4-bit-uncompressed --color=0x4080ff) + display.add (Png --x=604 --y=120 --png-file=heater-4-bit-uncompressed --palette-transformer=swap-red-and-black) + display.add (Png --x=688 --y=120 --png-file=heater-bw-uncompressed --color=0x20ffe0) display.draw diff --git a/tests/gold/bitmap-2-visualized.toit.png b/tests/gold/bitmap-2-visualized.toit.png index 6cfa6ffd5cc6aa01b3e64d68a800ac030e245a64..e1fbc7d94fe3fb29d7243b35b8bfdbfae6adf60c 100644 GIT binary patch literal 11507 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 literal 7622 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 diff --git a/tests/gold/three-color-bitmap-2-visualized.toit.png b/tests/gold/three-color-bitmap-2-visualized.toit.png index 2085906e83467631bed4a158bc3fc882ba05466f..a40ab18e46209851c6168e92f93f421073deb5f8 100644 GIT binary patch literal 1403 zcmeAS@N?(olHy`uVBq!ia0y~yVAWt?U^HN228x_CE&m6kI0Jk_T>t<74`c%Ifs=DL z09EOFx;TbZ#J#z+P>{iZgTe5|nniE+2Z^tE9H8>=?s0jbS}54Q_}Qzjy%rZI6qgov-a--)paFc1eB_IGuN@}wu6A{a@Knl z@4bJB?DhB-x8nWe#TA(~r=~3PTxAnq#ikJF_BJP00>ZW6+g!(48DKOLx(%rF>J2f=?+k zU*pMKDS0XA{)B1F`>)OVtbeIm!+-yRJdin`PBeVIJ9&k;et(De>(tr1r$)Ux**kNo z*Uq$5rVEo8Vswue)&3}NpY`{*gQoG)JLV4-Ozl1w`#xY>w7&n^=#@ZgXTYrGJn%JW zv;U>L%zaTm7mHu!&U~BtGA!%n;-%+wLQk1$3pY$-c~G_Truxf?4E_14VM$MS2FEE+ znSSw9F#E1AZr*bx*L<0rmC6RRb&C^Y``S0*KNfhemQKwsE^+jp`*P|0JGKv2Og;Vd za#wN7C!?sysO*Qmt<$WGBVMXsJ;k#?l`*50sV}PXZTOG$mMDGwwWYk~U~M)A34fJe z{!I?L6gTY`Q|WIFKGmgXc*1^pZZ%@g@MMTm1O}wt{L7yWB_kT5^rN+N_1LyWzVgxk z`{W&?`&yG(s~v6k+usJISG`o{=ZUyKSuec8xjSH?&ees}=I3!o^-r-fjsiKBWq~SlM&N;kC6``W z&U`g7vYh52g^xQjEtjJs@H~qqGF3i!nsqdRt}Y# z0o?b~RvPd9GI=+o}<5tSh-WT6jk1TDz2?rnzrSV|Ej5y4&F=`xEN*jzqOgR z{xkQLs+-TAzJ3xA1P+Qu#@E$Br)#UEHaoW(-7C}C{%C&5grIab?Y~Q+W-@M3VOSe* z;7WemzLXu5erOlBaF5Q_)2E%D{qxo|UJMO$AyAla3%Z=O z=*!F~Ir$A~9^PjsxM{1VUSDq-_Kfjo3ETX077PkuNuUJw-etvoNsZKHQ{36s0Mozm zlBN3;b&uDt-6*6DLPqk3_&A%UMtE+Rl%N_Wv_>VOb1IAWMj+>)7m(w*K}eeuD15{V zP0jspv;M!?|LOPs-`DTk^T{0AJju52O<_vEa<$CO$0y|6zgcWLJ`o`_z-Yk43=~n4E(CHII0Jk_T>t<74`c%Ifs=DL z098Hqba4!+hIQv~| zid!ZK@dZdN4Fn=92QU{X;s@eNEqyLmoj&1_1&_wA*K*Ex>YiCEw(j?rz&$2b zPdx+|t(hV*(a5Fk-~6@%>K_dB-)YGHcza0OKGgG1*Y+uoSJqz6J|-W!Gv(4W-`7D( zOU-hZN_ll>1nT|@+Ou#E_tp4=lmGMhFV^2Rf9Hem!Iq+zE(h=}|K_`1QT*!Ltp$3O zr4wKKsq7w|q>eOfvlOF=WQH17GG`eBG&%np$;gimK?YE6d(qnWT3$ z%c^DZ4zZxkDfe7jwb}!Em&I~$8ilK9`Y-F8`E;(+)LUETMqOGe1$0u%ef6N-F*7#b zN~<(p_5RWK_SK$2lh%8jXXo^sdTPtmS(leb`L;he^iasxDH{LZ&&Q=FYlMqSN%ClMJ;rtkMzn(dS55K zREd2UywZd7mX3Si+wWg)8+v$^`kyxR06GrjgZhU}MyqbD4;0Ir=DZ^9^2@Uy z-@Z{#O|{xqE~@vfxt9o7TJ{>~g~6WCYXsu7N1a}lyvj`gUP-^K&JxLNgSD_0<_xafA;&nOooO;g^sOfj9ToMZP;;g zS;1@X{~O-$YxG`%AWm?;1Ln0|3r)NhgONEjQ@XuugDU#B$qSNo845V%{HE&vv4{on NJzf1=);T3K0RXx>`2zp| diff --git a/tests/three-color-bitmap-2-visualized.toit b/tests/three-color-bitmap-2-visualized.toit index 700e04f..640316a 100644 --- a/tests/three-color-bitmap-2-visualized.toit +++ b/tests/three-color-bitmap-2-visualized.toit @@ -23,7 +23,7 @@ main args: basename := args[0] - driver := ThreeColorPngVisualizer 440 240 basename --outline=BLACK + driver := ThreeColorPngVisualizer 610 240 basename --outline=BLACK display := PixelDisplay.three-color driver display.background = WHITE @@ -36,15 +36,25 @@ main args: heater-white-bg := file.read-content "tests/third_party/pictogrammers/heater-white-bg.png" heater-white-bg-uncompressed := file.read-content "tests/third_party/pictogrammers/heater-white-bg-uncompressed.png" + swap-red-and-black := :: | r/int g/int b/int a/int | + if r > 0x80: + #[0, 0, 0, a] + else: + #[0xff, 0, 0, a] + display.add (Png --x=100 --y=32 --png-file=heater-red) display.add (Png --x=184 --y=32 --png-file=heater-2-bit) display.add (Png --x=268 --y=32 --png-file=heater-bw) display.add (Png --x=352 --y=32 --png-file=heater-white-bg) + display.add (Png --x=436 --y=32 --png-file=heater-bw --color=0xff0000) + display.add (Png --x=520 --y=32 --png-file=heater-2-bit --palette-transformer=swap-red-and-black) display.add (Png --x=100 --y=120 --png-file=heater-red-uncompressed) display.add (Png --x=184 --y=120 --png-file=heater-2-bit-uncompressed) display.add (Png --x=268 --y=120 --png-file=heater-bw-uncompressed) display.add (Png --x=352 --y=120 --png-file=heater-white-bg-uncompressed) + display.add (Png --x=436 --y=120 --png-file=heater-bw-uncompressed --color=0xff0000) + display.add (Png --x=520 --y=120 --png-file=heater-2-bit-uncompressed --palette-transformer=swap-red-and-black) display.draw From cb1ec7866608c05a852a2d3864317b5cdf5d9a93 Mon Sep 17 00:00:00 2001 From: Erik Corry Date: Thu, 29 Feb 2024 13:33:32 +0100 Subject: [PATCH 4/8] feedback --- src/png.toit | 55 +++++++++++++--------- tests/bitmap-2-visualized.toit | 4 +- tests/png-visualizer.toit | 10 ++++ tests/three-color-bitmap-2-visualized.toit | 10 +--- tests/toit-png-tools | 2 +- 5 files changed, 49 insertions(+), 32 deletions(-) diff --git a/src/png.toit b/src/png.toit index bf33219..d0f4dcb 100644 --- a/src/png.toit +++ b/src/png.toit @@ -40,7 +40,8 @@ class Png extends CustomElement: last-alpha-palette_/ByteArray? := null last-transformed-palette_/ByteArray? := null last-transformed-alpha-palette_/ByteArray? := null - palette-transformer_/Lambda? := null + palette-transformer_/PaletteTransformer? := null + palette-transformer-buffer_/ByteArray? := null /** Constructs an element that displays a PNG image, given a byte array @@ -58,7 +59,7 @@ class Png extends CustomElement: --border/Border?=null --png-file/ByteArray --color/int?=null - --palette-transformer/Lambda?=null: + --palette-transformer/PaletteTransformer?=null: palette-transformer_ = palette-transformer info := png-reader.PngInfo png-file if info.uncompressed-random-access: @@ -94,8 +95,7 @@ class Png extends CustomElement: */ color= value/int -> none: invalidate-palette-transformer - palette-transformer_ = :: | r g b a | - #[value >> 16, value >> 8, value, a] + palette-transformer_ = SingleColorPaletteTransformer_ value set-attribute_ key/string value -> none: if key == "color": @@ -103,14 +103,10 @@ class Png extends CustomElement: else: super key value /** - The $palette-transformer is an optional Lambda that transforms - the colors in the PNG. The arguments are red, green, blue, and - alpha, all integers from 0-255. It is expected to return a - 4-element ByteArray with the transformed red, green, blue, and - alpha values. This can be used for example if you have a PNG + The $palette-transformer is an optional PaletteTransformer that transforms + the colors in the PNG. This can be used for example if you have a PNG that is black-and-transparent, and you want to display it as an - image that is red-and-transparent. The returned ByteArray does - not have to be fresh on each invocation. + image that is red-and-transparent. The palette transformer is not called eagerly, so if it is going to return new values (eg. to change the color of the PNG) you must call $invalidate-palette-transformer. @@ -119,7 +115,7 @@ class Png extends CustomElement: drawn with the same color, but alpha (transparency) will still be taken from the PNG file. */ - palette-transformer= value/Lambda?: + palette-transformer= value/PaletteTransformer?: invalidate-palette-transformer palette-transformer_ = value @@ -138,16 +134,16 @@ class Png extends CustomElement: if last-transformed-alpha-palette_ == null or last-transformed-alpha-palette_.size != palette.size: last-transformed-alpha-palette_ = ByteArray palette.size + if palette-transformer-buffer_ == null: + palette-transformer-buffer_ = ByteArray 4 (palette.size / 3).repeat: | i | - transformed := palette-transformer_.call - palette[i * 3] - palette[i * 3 + 1] - palette[i * 3 + 2] - i >= alpha-palette.size ? 0xff : alpha-palette[i] - last-transformed-palette_[i * 3] = transformed[0] - last-transformed-palette_[i * 3 + 1] = transformed[1] - last-transformed-palette_[i * 3 + 2] = transformed[2] - last-transformed-alpha-palette_[i] = transformed[3] + 3.repeat: + palette-transformer-buffer_[it] = palette[i * 3 + it] + palette-transformer-buffer_[3] = alpha-palette[i] + palette-transformer_.transform palette-transformer-buffer_ + 3.repeat: + last-transformed-palette_[i * 3 + it] = palette-transformer-buffer_[it] + last-transformed-alpha-palette_[i] = palette-transformer-buffer_[3] palette = last-transformed-palette_ alpha-palette = last-transformed-alpha-palette_ if bits-per-pixel == 1: @@ -171,3 +167,20 @@ class Png extends CustomElement: y2 = y-to type -> string: return "png" + +interface PaletteTransformer: + /** + Takes a 4-element byte array in rgba order and modifies the + byte array to indicate which color and transparency should + be used instead. + */ + transform rgba/ByteArray -> none + +class SingleColorPaletteTransformer_ implements PaletteTransformer: + color_/int + constructor .color_: + + transform rgba/ByteArray -> none: + rgba[0] = color_ >> 16 + rgba[1] = color_ >> 8 + rgba[2] = color_ diff --git a/tests/bitmap-2-visualized.toit b/tests/bitmap-2-visualized.toit index cc2d31c..3e02f4a 100644 --- a/tests/bitmap-2-visualized.toit +++ b/tests/bitmap-2-visualized.toit @@ -52,7 +52,7 @@ main args: display.add (Png --x=352 --y=32 --png-file=heater-white-bg) display.add (Png --x=436 --y=32 --png-file=heater-translucent) display.add (Png --x=520 --y=32 --png-file=heater-4-bit --color=0x4080ff) - display.add (Png --x=604 --y=32 --png-file=heater-4-bit --palette-transformer=swap-red-and-black) + display.add (Png --x=604 --y=32 --png-file=heater-4-bit --palette-transformer=SwapRedAndBlack) display.add (Png --x=688 --y=32 --png-file=heater-bw --color=0x20ffe0) display.add (Png --x=16 --y=120 --png-file=heater-uncompressed) @@ -62,7 +62,7 @@ main args: display.add (Png --x=352 --y=120 --png-file=heater-white-bg-uncompressed) display.add (Png --x=436 --y=120 --png-file=heater-translucent-uncompressed) display.add (Png --x=520 --y=120 --png-file=heater-4-bit-uncompressed --color=0x4080ff) - display.add (Png --x=604 --y=120 --png-file=heater-4-bit-uncompressed --palette-transformer=swap-red-and-black) + display.add (Png --x=604 --y=120 --png-file=heater-4-bit-uncompressed --palette-transformer=SwapRedAndBlack) display.add (Png --x=688 --y=120 --png-file=heater-bw-uncompressed --color=0x20ffe0) display.draw diff --git a/tests/png-visualizer.toit b/tests/png-visualizer.toit index 41b1509..b23205e 100644 --- a/tests/png-visualizer.toit +++ b/tests/png-visualizer.toit @@ -9,6 +9,7 @@ import crypto.crc show * import host.file import monitor show Latch import pixel-display show * +import pixel-display.png import png-tools.png-writer import png-tools.png-reader show * import zlib @@ -403,3 +404,12 @@ byte-swap_ ba/ByteArray -> ByteArray: result := ba.copy byte-swap-32 result return result + +class SwapRedAndBlack implements png.PaletteTransformer: + transform palette/ByteArray -> none: + if palette[0] >= 0x80: + palette[0] = 0 + else: + palette[0] = 0xff + palette[1] = 0 + palette[2] = 0 diff --git a/tests/three-color-bitmap-2-visualized.toit b/tests/three-color-bitmap-2-visualized.toit index 640316a..93b649b 100644 --- a/tests/three-color-bitmap-2-visualized.toit +++ b/tests/three-color-bitmap-2-visualized.toit @@ -36,25 +36,19 @@ main args: heater-white-bg := file.read-content "tests/third_party/pictogrammers/heater-white-bg.png" heater-white-bg-uncompressed := file.read-content "tests/third_party/pictogrammers/heater-white-bg-uncompressed.png" - swap-red-and-black := :: | r/int g/int b/int a/int | - if r > 0x80: - #[0, 0, 0, a] - else: - #[0xff, 0, 0, a] - display.add (Png --x=100 --y=32 --png-file=heater-red) display.add (Png --x=184 --y=32 --png-file=heater-2-bit) display.add (Png --x=268 --y=32 --png-file=heater-bw) display.add (Png --x=352 --y=32 --png-file=heater-white-bg) display.add (Png --x=436 --y=32 --png-file=heater-bw --color=0xff0000) - display.add (Png --x=520 --y=32 --png-file=heater-2-bit --palette-transformer=swap-red-and-black) + display.add (Png --x=520 --y=32 --png-file=heater-2-bit --palette-transformer=SwapRedAndBlack) display.add (Png --x=100 --y=120 --png-file=heater-red-uncompressed) display.add (Png --x=184 --y=120 --png-file=heater-2-bit-uncompressed) display.add (Png --x=268 --y=120 --png-file=heater-bw-uncompressed) display.add (Png --x=352 --y=120 --png-file=heater-white-bg-uncompressed) display.add (Png --x=436 --y=120 --png-file=heater-bw-uncompressed --color=0xff0000) - display.add (Png --x=520 --y=120 --png-file=heater-2-bit-uncompressed --palette-transformer=swap-red-and-black) + display.add (Png --x=520 --y=120 --png-file=heater-2-bit-uncompressed --palette-transformer=SwapRedAndBlack) display.draw diff --git a/tests/toit-png-tools b/tests/toit-png-tools index 8387669..ee472ac 160000 --- a/tests/toit-png-tools +++ b/tests/toit-png-tools @@ -1 +1 @@ -Subproject commit 8387669efa33a7108c746dcb19dd5ad0ac8f89d0 +Subproject commit ee472ac9d4333a138206f9d3a817d3c5432d6f87 From 192622c54eeec86af8f6c6a7adef4a58a6cd4fcb Mon Sep 17 00:00:00 2001 From: Erik Corry Date: Thu, 29 Feb 2024 13:42:38 +0100 Subject: [PATCH 5/8] feedback --- tests/bitmap-2-visualized.toit | 6 ------ tests/png-visualizer.toit | 5 +---- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/tests/bitmap-2-visualized.toit b/tests/bitmap-2-visualized.toit index 3e02f4a..71967c5 100644 --- a/tests/bitmap-2-visualized.toit +++ b/tests/bitmap-2-visualized.toit @@ -39,12 +39,6 @@ main args: heater-translucent := file.read-content "tests/third_party/pictogrammers/heater-translucent.png" heater-translucent-uncompressed := file.read-content "tests/third_party/pictogrammers/heater-translucent-uncompressed.png" - swap-red-and-black := :: | r/int g/int b/int a/int | - if r > 0x80: - #[0, 0, 0, a] - else: - #[0xff, 0, 0, a] - display.add (Png --x=16 --y=32 --png-file=heater) display.add (Png --x=100 --y=32 --png-file=heater-4-bit) display.add (Png --x=184 --y=32 --png-file=heater-2-bit) diff --git a/tests/png-visualizer.toit b/tests/png-visualizer.toit index b23205e..df08a5d 100644 --- a/tests/png-visualizer.toit +++ b/tests/png-visualizer.toit @@ -407,9 +407,6 @@ byte-swap_ ba/ByteArray -> ByteArray: class SwapRedAndBlack implements png.PaletteTransformer: transform palette/ByteArray -> none: - if palette[0] >= 0x80: - palette[0] = 0 - else: - palette[0] = 0xff + palette[0] = (palette[0] >= 0x80) ? 0 : 0xff palette[1] = 0 palette[2] = 0 From ab73bce3e75adcf8e3773ec506cb0e93ac8a42b7 Mon Sep 17 00:00:00 2001 From: Erik Corry Date: Fri, 8 Mar 2024 15:31:33 +0100 Subject: [PATCH 6/8] Make it possible to update the PNG file on a PNG element --- src/png.toit | 38 +++++++++++++----- .../three-color-bitmap-2-visualized.toit.png | Bin 1403 -> 2401 bytes tests/three-color-bitmap-2-visualized.toit | 12 +++++- 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/src/png.toit b/src/png.toit index d0f4dcb..ebc666d 100644 --- a/src/png.toit +++ b/src/png.toit @@ -35,7 +35,7 @@ Only PNGs with up to 8 bits per pixel are supported. They can be transparent, and the opaque colors fully opaque. */ class Png extends CustomElement: - png_/png-reader.AbstractPng + png_/png-reader.AbstractPng? := null last-palette_/ByteArray? := null last-alpha-palette_/ByteArray? := null last-transformed-palette_/ByteArray? := null @@ -57,29 +57,36 @@ class Png extends CustomElement: --id/string?=null --background=null --border/Border?=null - --png-file/ByteArray + --png-file/ByteArray?=null --color/int?=null --palette-transformer/PaletteTransformer?=null: palette-transformer_ = palette-transformer - info := png-reader.PngInfo png-file - if info.uncompressed-random-access: - png_ = png-reader.PngRandomAccess png-file - else: - png_ = png-reader.Png png-file - if png_.bit-depth > 8: throw "UNSUPPORTED" - if png_.color-type == png-reader.COLOR-TYPE-TRUECOLOR or png_.color-type == png-reader.COLOR-TYPE-TRUECOLOR-ALPHA: throw "UNSUPPORTED" + png/png-reader.AbstractPng? := create-png_ png-file super --x = x --y = y - --w = png_.width - --h = png_.height + --w = png ? png.width : 0 + --h = png ? png.height : 0 --style = style --classes = classes --id = id --background = background --border = border + png_ = png if color: this.color = color + static create-png_ png-file/ByteArray? -> png-reader.AbstractPng?: + if not png-file: return null + info := png-reader.PngInfo png-file + png/png-reader.AbstractPng := ? + if info.uncompressed-random-access: + png = png-reader.PngRandomAccess png-file + else: + png = png-reader.Png png-file + if png.bit-depth > 8: throw "UNSUPPORTED" + if png.color-type == png-reader.COLOR-TYPE-TRUECOLOR or png.color-type == png-reader.COLOR-TYPE-TRUECOLOR-ALPHA: throw "UNSUPPORTED" + return png + /** Causes the PNG to be redrawn with new values from the palette transformer. */ @@ -97,11 +104,19 @@ class Png extends CustomElement: invalidate-palette-transformer palette-transformer_ = SingleColorPaletteTransformer_ value + png-file= value/ByteArray? -> none: + invalidate + png_ = create-png_ value + set-size png_.width png_.height // Also invalidates if the size changes. + set-attribute_ key/string value -> none: if key == "color": color = value + else if key == "png-file": + png-file = value else: super key value + /** The $palette-transformer is an optional PaletteTransformer that transforms the colors in the PNG. This can be used for example if you have a PNG @@ -121,6 +136,7 @@ class Png extends CustomElement: // Redraw routine. custom-draw canvas/Canvas: + if not png_: return y2 := 0 while y2 < h and (canvas.bounds-analysis 0 y2 w (h - y2)) != Canvas.DISJOINT: png_.get-indexed-image-data y2 h diff --git a/tests/gold/three-color-bitmap-2-visualized.toit.png b/tests/gold/three-color-bitmap-2-visualized.toit.png index a40ab18e46209851c6168e92f93f421073deb5f8..ac63822c01060199ded5e8ceb4e09cce8218c4bd 100644 GIT binary patch literal 2401 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 diff --git a/tests/three-color-bitmap-2-visualized.toit b/tests/three-color-bitmap-2-visualized.toit index 93b649b..9eb85eb 100644 --- a/tests/three-color-bitmap-2-visualized.toit +++ b/tests/three-color-bitmap-2-visualized.toit @@ -37,12 +37,20 @@ main args: heater-white-bg-uncompressed := file.read-content "tests/third_party/pictogrammers/heater-white-bg-uncompressed.png" display.add (Png --x=100 --y=32 --png-file=heater-red) - display.add (Png --x=184 --y=32 --png-file=heater-2-bit) + display.add (Png --x=184 --y=32 --png-file=heater-red --id="2-bit") display.add (Png --x=268 --y=32 --png-file=heater-bw) display.add (Png --x=352 --y=32 --png-file=heater-white-bg) - display.add (Png --x=436 --y=32 --png-file=heater-bw --color=0xff0000) + display.add (Png --x=436 --y=32 --id="updated-later") display.add (Png --x=520 --y=32 --png-file=heater-2-bit --palette-transformer=SwapRedAndBlack) + display.draw + + updated-later := display.get-element-by-id "updated-later" + updated-later.png-file = heater-bw + updated-later.color = 0xff0000 + + (display.get-element-by-id "2-bit").png-file = heater-2-bit + display.add (Png --x=100 --y=120 --png-file=heater-red-uncompressed) display.add (Png --x=184 --y=120 --png-file=heater-2-bit-uncompressed) display.add (Png --x=268 --y=120 --png-file=heater-bw-uncompressed) From ce764029bf70d4e48010e6a71fd336cfd8d0918d Mon Sep 17 00:00:00 2001 From: Erik Corry Date: Fri, 8 Mar 2024 15:37:29 +0100 Subject: [PATCH 7/8] Fix setting null PNG file --- src/png.toit | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/png.toit b/src/png.toit index ebc666d..11f04ff 100644 --- a/src/png.toit +++ b/src/png.toit @@ -100,14 +100,20 @@ class Png extends CustomElement: be drawn with the given color. Alpha (transparency) will be unchanged. */ - color= value/int -> none: + color= value/int? -> none: invalidate-palette-transformer - palette-transformer_ = SingleColorPaletteTransformer_ value + if value: + palette-transformer_ = SingleColorPaletteTransformer_ value + else: + palette-transformer_ = null png-file= value/ByteArray? -> none: invalidate png_ = create-png_ value - set-size png_.width png_.height // Also invalidates if the size changes. + if png_: + set-size png_.width png_.height // Also invalidates if the size changes. + else: + set-size 0 0 set-attribute_ key/string value -> none: if key == "color": From 482e5ef55f3897483a8eadda627d4fc36def0d17 Mon Sep 17 00:00:00 2001 From: Erik Corry Date: Fri, 8 Mar 2024 16:18:56 +0100 Subject: [PATCH 8/8] Reduce peak memory use --- src/png.toit | 1 + 1 file changed, 1 insertion(+) diff --git a/src/png.toit b/src/png.toit index 11f04ff..81049f2 100644 --- a/src/png.toit +++ b/src/png.toit @@ -109,6 +109,7 @@ class Png extends CustomElement: png-file= value/ByteArray? -> none: invalidate + png_ = null // Reduce peak memory use. png_ = create-png_ value if png_: set-size png_.width png_.height // Also invalidates if the size changes.