mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-04 06:38:47 +00:00
Image: Add improved blending method and test it.
This commit is contained in:
@@ -42,6 +42,23 @@ GA_Pixel :: [2]u8
|
|||||||
G_Pixel_16 :: [1]u16
|
G_Pixel_16 :: [1]u16
|
||||||
GA_Pixel_16 :: [2]u16
|
GA_Pixel_16 :: [2]u16
|
||||||
|
|
||||||
|
blend_single_channel :: #force_inline proc(fg, alpha, bg: $T) -> (res: T) where T == u8 || T == u16 {
|
||||||
|
MAX :: 256 when T == u8 else 65536
|
||||||
|
|
||||||
|
c := u32(fg) * (MAX - u32(alpha)) + u32(bg) * (1 + u32(alpha))
|
||||||
|
return T(c & (MAX - 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
blend_pixel :: #force_inline proc(fg: [$N]$T, alpha: T, bg: [N]T) -> (res: [N]T) where (T == u8 || T == u16), N >= 1 && N <= 4 {
|
||||||
|
MAX :: 256 when T == u8 else 65536
|
||||||
|
|
||||||
|
r_a := u32(fg) * (MAX - u32(alpha)) + u32(bg) * (1 + u32(alpha))
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
blend :: proc{blend_single_channel, blend_pixel}
|
||||||
|
|
||||||
Image :: struct {
|
Image :: struct {
|
||||||
width: int,
|
width: int,
|
||||||
height: int,
|
height: int,
|
||||||
|
|||||||
+9
-11
@@ -597,7 +597,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
|
|||||||
dsc := depth_scale_table
|
dsc := depth_scale_table
|
||||||
scale := dsc[info.header.bit_depth]
|
scale := dsc[info.header.bit_depth]
|
||||||
if scale != 1 {
|
if scale != 1 {
|
||||||
key := mem.slice_data_cast([]u16be, c.data)[0] * u16be(scale)
|
key := (^u16be)(raw_data(c.data))^ * u16be(scale)
|
||||||
c.data = []u8{0, u8(key & 255)}
|
c.data = []u8{0, u8(key & 255)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -762,19 +762,18 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
|
|||||||
for w := 0; w < int(img.width); w += 1 {
|
for w := 0; w < int(img.width); w += 1 {
|
||||||
index := temp.buf[i]
|
index := temp.buf[i]
|
||||||
|
|
||||||
c := _plte.entries[index]
|
c := _plte.entries[index]
|
||||||
a := int(index) < len(trns.data) ? trns.data[index] : 255
|
a := int(index) < len(trns.data) ? trns.data[index] : 255
|
||||||
alpha := f32(a) / 255.0
|
|
||||||
|
|
||||||
if blend_background {
|
if blend_background {
|
||||||
c.r = u8((1.0 - alpha) * bg[0] + f32(c.r) * alpha)
|
c.r = image.blend(c.r, a, u8(u32(bg.r)))
|
||||||
c.g = u8((1.0 - alpha) * bg[1] + f32(c.g) * alpha)
|
c.g = image.blend(c.g, a, u8(u32(bg.g)))
|
||||||
c.b = u8((1.0 - alpha) * bg[2] + f32(c.b) * alpha)
|
c.b = image.blend(c.b, a, u8(u32(bg.b)))
|
||||||
a = 255
|
a = 255
|
||||||
} else if premultiply {
|
} else if premultiply {
|
||||||
c.r = u8(f32(c.r) * alpha)
|
c.r = image.blend(u8(0), a, c.r)
|
||||||
c.g = u8(f32(c.g) * alpha)
|
c.g = image.blend(u8(0), a, c.g)
|
||||||
c.b = u8(f32(c.b) * alpha)
|
c.b = image.blend(u8(0), a, c.b)
|
||||||
}
|
}
|
||||||
|
|
||||||
t.buf[j ] = c.r
|
t.buf[j ] = c.r
|
||||||
@@ -1627,7 +1626,6 @@ defilter :: proc(img: ^Image, filter_bytes: ^bytes.Buffer, header: ^image.PNG_IH
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@(init, private)
|
@(init, private)
|
||||||
_register :: proc() {
|
_register :: proc() {
|
||||||
image.register(.PNG, load_from_bytes, destroy)
|
image.register(.PNG, load_from_bytes, destroy)
|
||||||
|
|||||||
@@ -2358,4 +2358,40 @@ run_bmp_suite :: proc(t: ^testing.T, suite: []Test) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
@test
|
||||||
|
will_it_blend :: proc(t: ^testing.T) {
|
||||||
|
Pixel :: image.RGB_Pixel
|
||||||
|
Pixel_16 :: image.RGB_Pixel_16
|
||||||
|
|
||||||
|
{
|
||||||
|
bg := Pixel{255, 255, 0}
|
||||||
|
fg := Pixel{ 0, 0, 255}
|
||||||
|
|
||||||
|
for a in 0..=255 {
|
||||||
|
blended := Pixel{
|
||||||
|
image.blend(fg.r, u8(a), bg.r),
|
||||||
|
image.blend(fg.g, u8(a), bg.g),
|
||||||
|
image.blend(fg.b, u8(a), bg.b),
|
||||||
|
}
|
||||||
|
testing.expectf(t, blended.r == bg.r - u8(a), "Expected blend(%v, %3d, %v) = %v, got %v", fg.r, a, bg.r, bg.r - u8(a), blended.r)
|
||||||
|
testing.expectf(t, blended.b == 255 - blended.r, "Expected blend(%v, %3d, %v) = %v, got %v", fg.b, a, bg.b, 255 - blended.r, blended.b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
bg := Pixel_16{65535, 65535, 0}
|
||||||
|
fg := Pixel_16{ 0, 0, 65535}
|
||||||
|
|
||||||
|
for a in 0..=65535 {
|
||||||
|
blended := Pixel_16{
|
||||||
|
image.blend(fg.r, u16(a), bg.r),
|
||||||
|
image.blend(fg.g, u16(a), bg.g),
|
||||||
|
image.blend(fg.b, u16(a), bg.b),
|
||||||
|
}
|
||||||
|
testing.expectf(t, blended.r == bg.r - u16(a), "Expected blend(%v, %3d, %v) = %v, got %v", fg.r, a, bg.r, bg.r - u16(a), blended.r)
|
||||||
|
testing.expectf(t, blended.b == 65535 - blended.r, "Expected blend(%v, %3d, %v) = %v, got %v", fg.b, a, bg.b, 65535 - blended.r, blended.b)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -20,7 +20,6 @@ download_assets :: proc() {
|
|||||||
@(require) import "encoding/varint"
|
@(require) import "encoding/varint"
|
||||||
@(require) import "encoding/xml"
|
@(require) import "encoding/xml"
|
||||||
@(require) import "fmt"
|
@(require) import "fmt"
|
||||||
@(require) import "image"
|
|
||||||
@(require) import "math"
|
@(require) import "math"
|
||||||
@(require) import "math/big"
|
@(require) import "math/big"
|
||||||
@(require) import "math/linalg/glsl"
|
@(require) import "math/linalg/glsl"
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ package tests_core
|
|||||||
|
|
||||||
@(require) import "crypto"
|
@(require) import "crypto"
|
||||||
@(require) import "hash"
|
@(require) import "hash"
|
||||||
|
@(require) import "image"
|
||||||
Reference in New Issue
Block a user