mirror of
https://github.com/vlang/v.git
synced 2025-08-04 02:07:28 -04:00
stbi: fix stbi.Image's nr_channels
property, after a forced conversion on load (#22528)
This commit is contained in:
parent
1fb9fec7fa
commit
04bd58596f
@ -36,14 +36,17 @@ fn cb_free(p voidptr) {
|
||||
#include "stb_v_header.h"
|
||||
#flag @VEXEROOT/thirdparty/stb_image/stbi.o
|
||||
|
||||
// Image represents an image loaded from file or memory, or an image, produced after resizing
|
||||
pub struct Image {
|
||||
pub mut:
|
||||
width int
|
||||
height int
|
||||
nr_channels int
|
||||
ok bool
|
||||
data &u8 = unsafe { nil }
|
||||
ext string
|
||||
width int // the width in pixels in the .data
|
||||
height int // the height in pixels in the .data
|
||||
nr_channels int // the number of color channels in the .data
|
||||
ok bool // if the image was loaded successfully
|
||||
data &u8 = unsafe { nil } // the actual data/pixels in the image, after reading and potentially converting the image
|
||||
ext string // the extension of the file, from which the image was loaded
|
||||
//
|
||||
original_nr_channels int // when loaded from memory/disk, this field will contain the original number of channels, based on the data, prior to any conversions. Use only as metadata, not for further conversions.
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -113,21 +116,27 @@ fn C.stbi_load_from_memory(buffer &u8, len int, x &int, y &int, channels_in_file
|
||||
@[params]
|
||||
pub struct LoadParams {
|
||||
pub:
|
||||
// the number of channels you expect the image to have.
|
||||
// If set to 0 stbi will figure out the correct number of channels
|
||||
desired_channels int = C.STBI_rgb_alpha
|
||||
desired_channels int = C.STBI_rgb_alpha // 4 by default (RGBA); desired_channels is the number of color channels, that will be used for representing the image in memory. If set to 0, stbi will figure out the number of channels, based on the original image data.
|
||||
}
|
||||
|
||||
// load load an image from a path
|
||||
// load loads an image from `path`
|
||||
// If you do not pass desired_channels: explicitly, it will default to 4 (RGBA),
|
||||
// The image, will get converted into that internal format, no matter what it was on disk.
|
||||
// Use desired_channels:0, if you need to keep the channels of the image on disk.
|
||||
// Note that displaying such an image, with gg/sokol later, can be a problem.
|
||||
// Converting/resizing it, should work fine though.
|
||||
pub fn load(path string, params LoadParams) !Image {
|
||||
ext := path.all_after_last('.')
|
||||
mut res := Image{
|
||||
ok: true
|
||||
ext: ext
|
||||
nr_channels: params.desired_channels
|
||||
}
|
||||
res.data = C.stbi_load(&char(path.str), &res.width, &res.height, &res.nr_channels,
|
||||
res.data = C.stbi_load(&char(path.str), &res.width, &res.height, &res.original_nr_channels,
|
||||
params.desired_channels)
|
||||
|
||||
if params.desired_channels == 0 {
|
||||
res.nr_channels = res.original_nr_channels
|
||||
}
|
||||
if isnil(res.data) {
|
||||
return error('stbi_image failed to load from "${path}"')
|
||||
}
|
||||
@ -135,12 +144,21 @@ pub fn load(path string, params LoadParams) !Image {
|
||||
}
|
||||
|
||||
// load_from_memory load an image from a memory buffer
|
||||
// If you do not pass desired_channels: explicitly, it will default to 4 (RGBA),
|
||||
// and the image will get converted into that internal format, no matter what it was originally.
|
||||
// Use desired_channels:0, if you need to keep the channels of the image as they were.
|
||||
// Note that displaying such an image, with gg/sokol later, can be a problem.
|
||||
// Converting/resizing it, should work fine though.
|
||||
pub fn load_from_memory(buf &u8, bufsize int, params LoadParams) !Image {
|
||||
mut res := Image{
|
||||
ok: true
|
||||
nr_channels: params.desired_channels
|
||||
}
|
||||
res.data = C.stbi_load_from_memory(buf, bufsize, &res.width, &res.height, &res.nr_channels,
|
||||
res.data = C.stbi_load_from_memory(buf, bufsize, &res.width, &res.height, &res.original_nr_channels,
|
||||
params.desired_channels)
|
||||
if params.desired_channels == 0 {
|
||||
res.nr_channels = res.original_nr_channels
|
||||
}
|
||||
if isnil(res.data) {
|
||||
return error('stbi_image failed to load from memory')
|
||||
}
|
||||
@ -163,6 +181,7 @@ pub fn resize_uint8(img &Image, output_w int, output_h int) !Image {
|
||||
width: output_w
|
||||
height: output_h
|
||||
nr_channels: img.nr_channels
|
||||
original_nr_channels: img.original_nr_channels // preserve the metadata of the original, during resizes
|
||||
}
|
||||
|
||||
res.data = cb_malloc(usize(output_w * output_h * img.nr_channels))
|
||||
|
@ -1,7 +1,10 @@
|
||||
import os
|
||||
import stbi
|
||||
|
||||
const vroot = @VEXEROOT
|
||||
const tfolder = os.join_path(os.vtmp_dir(), 'stbi')
|
||||
const logo_path = os.join_path(vroot, 'examples/assets/logo.png')
|
||||
const background_path = os.join_path(vroot, 'examples/flappylearning/assets/img/background.png')
|
||||
|
||||
fn testsuite_begin() {
|
||||
os.mkdir_all(tfolder) or {}
|
||||
@ -12,10 +15,8 @@ fn testsuite_end() {
|
||||
}
|
||||
|
||||
fn test_stbi_read_write() {
|
||||
vroot := @VEXEROOT
|
||||
path := os.join_path(vroot, 'examples', 'assets', 'logo.png')
|
||||
println('Source path: ${path}')
|
||||
d_s := stbi.load(path) or { panic(err) }
|
||||
println('Source path: ${logo_path}')
|
||||
d_s := stbi.load(logo_path) or { panic(err) }
|
||||
println('Image source data:\n ${d_s}')
|
||||
|
||||
out_path := os.join_path(tfolder, 'test.png')
|
||||
@ -30,9 +31,10 @@ fn test_stbi_read_write() {
|
||||
assert d_s.width == d_d.width
|
||||
assert d_s.height == d_d.height
|
||||
assert d_s.nr_channels == d_d.nr_channels
|
||||
assert d_s.original_nr_channels == 4
|
||||
|
||||
mut v_s := &u32(d_s.data)
|
||||
mut v_d := &u32(d_d.data)
|
||||
mut v_s := unsafe { &u32(d_s.data) }
|
||||
mut v_d := unsafe { &u32(d_d.data) }
|
||||
mut delta := i64(0)
|
||||
for index in 0 .. (d_d.width * d_d.width) {
|
||||
unsafe {
|
||||
@ -44,15 +46,14 @@ fn test_stbi_read_write() {
|
||||
}
|
||||
|
||||
fn test_stbi_resize() {
|
||||
vroot := @VEXEROOT
|
||||
path := os.join_path(vroot, 'examples', 'assets', 'logo.png')
|
||||
println('Source path: ${path}')
|
||||
d_s := stbi.load(path) or { panic(err) }
|
||||
println('Source path: ${logo_path}')
|
||||
d_s := stbi.load(logo_path) or { panic(err) }
|
||||
println('Image source data:\n ${d_s}')
|
||||
|
||||
new_width, new_height := 100, 100
|
||||
|
||||
d_r := stbi.resize_uint8(d_s, new_width, new_height) or { panic(err) }
|
||||
assert d_r.original_nr_channels == 4
|
||||
println('Resized Image source data:\n ${d_s}')
|
||||
|
||||
out_path := os.join_path(tfolder, 'test.png')
|
||||
@ -67,5 +68,24 @@ fn test_stbi_resize() {
|
||||
assert d_d.width == new_width
|
||||
assert d_d.height == new_height
|
||||
assert d_d.nr_channels == d_r.nr_channels
|
||||
assert d_d.original_nr_channels == 4
|
||||
os.rm(out_path) or {}
|
||||
}
|
||||
|
||||
fn test_load_image_with_channels_different_than_4() {
|
||||
img := stbi.load(background_path)!
|
||||
assert img.nr_channels == 4, 'by default, stbi.load should convert images to 4 channels'
|
||||
assert img.original_nr_channels == 3, 'the default, should not affect the img.original_nr_channels field; it should be based solely on the original image data on disk'
|
||||
|
||||
img_resized := stbi.resize_uint8(img, 128, 128)!
|
||||
assert img_resized.nr_channels == 4
|
||||
assert img_resized.original_nr_channels == 3
|
||||
|
||||
img3 := stbi.load(background_path, desired_channels: 0)!
|
||||
assert img3.nr_channels == 3, 'stbi.load, with desired_channels: 0, should return an image, without any conversion. the nr_channels should be determined by the image data'
|
||||
assert img.original_nr_channels == 3, 'the default, should not affect the img.original_nr_channels field; it should be based solely on the original image data on disk'
|
||||
|
||||
img3_resized := stbi.resize_uint8(img3, 128, 128)!
|
||||
assert img3_resized.nr_channels == 3
|
||||
assert img3_resized.original_nr_channels == 3
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user