Skip to content

core:image add support for option .flip_vertical #4826

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 3 additions & 11 deletions core/image/bmp/bmp.odin
Original file line number Diff line number Diff line change
Expand Up @@ -242,17 +242,9 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
case: return img, .Unsupported_Compression
}

// Flipped vertically
if info.height < 0 {
pixels := mem.slice_data_cast([]RGB_Pixel, img.pixels.buf[:])
for y in 0..<img.height / 2 {
for x in 0..<img.width {
top := y * img.width + x
bot := (img.height - y - 1) * img.width + x

pixels[top], pixels[bot] = pixels[bot], pixels[top]
}
}
// is flipped XOR user wants to flip
if (int(info.height < 0) ~ int(.vertical_flip in options)) == 1 {
image.vertical_flip(img)
}
return
}
Expand Down
21 changes: 21 additions & 0 deletions core/image/common.odin
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
List of contributors:
Jeroen van Rijn: Initial implementation, optimization.
Ginger Bill: Cosmetic changes.
DerTee: Vertical flip.
*/

// package image implements a general 2D image library to be used with other image related packages
package image

import "core:bytes"
import "core:mem"
import "core:slice"
import "core:io"
import "core:compress"
import "base:runtime"
Expand Down Expand Up @@ -133,6 +135,10 @@ Image_Option:
color. As this negates the use for an alpha channel, we'll drop it _unless_
you also specify `.alpha_add_if_missing`.

`.vertical_flip`
Does an inplace vertical flip of the pixels of the given image on load.
This option only supports images with 8 or 16 bit channels!

Options that don't apply to an image format will be ignored by their loader.
*/

Expand All @@ -146,6 +152,7 @@ Option :: enum {
alpha_drop_if_present, // Unimplemented for QOI. Returns error.
alpha_premultiply, // Unimplemented for QOI. Returns error.
blend_background, // Ignored for non-PNG formats
vertical_flip, // Flip image vertically on load

// Unimplemented
do_not_expand_grayscale,
Expand Down Expand Up @@ -1438,6 +1445,20 @@ expand_grayscale :: proc(img: ^Image, allocator := context.allocator) -> (ok: bo
return true
}

// Does an inplace vertical flip of the pixels of the given image.
// Vertical flip is only supported for images with 8 or 16 bit channels!
vertical_flip :: proc(img: ^Image) {
assert(img.depth > 0 && (img.depth % 8 == 0), "Image bit depth must be multiple of 8, currently either 8 or 16 bit!")
pixels := img.pixels.buf[:]
bytes_per_pixel := img.depth/8 * img.channels
stride := img.width * bytes_per_pixel
for y in 0..<img.height / 2 {
top := y * stride
bot := (img.height - y - 1) * stride
slice.ptr_swap_non_overlapping(&pixels[top], &pixels[bot], stride)
}
}

/*
Helper functions to read and write data from/to a Context, etc.
*/
Expand Down
8 changes: 6 additions & 2 deletions core/image/netpbm/netpbm.odin
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import "core:unicode"
import "base:runtime"

Image :: image.Image
Options :: image.Options
Format :: image.Netpbm_Format
Header :: image.Netpbm_Header
Info :: image.Netpbm_Info
Expand All @@ -27,7 +28,7 @@ PFM :: Formats{.Pf, .PF}
ASCII :: Formats{.P1, .P2, .P3}
BINARY :: Formats{.P4, .P5, .P6} + PAM + PFM

load_from_bytes :: proc(data: []byte, allocator := context.allocator) -> (img: ^Image, err: Error) {
load_from_bytes :: proc(data: []byte, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) {
context.allocator = allocator

img = new(Image)
Expand All @@ -47,6 +48,9 @@ load_from_bytes :: proc(data: []byte, allocator := context.allocator) -> (img: ^
}
img.metadata = info

if .vertical_flip in options {
image.vertical_flip(img)
}
return img, nil
}

Expand Down Expand Up @@ -722,7 +726,7 @@ autoselect_pbm_format_from_image :: proc(img: ^Image, prefer_binary := true, for
@(init, private)
_register :: proc() {
loader :: proc(data: []byte, options: image.Options, allocator: mem.Allocator) -> (img: ^Image, err: Error) {
return load_from_bytes(data, allocator)
return load_from_bytes(data, options, allocator)
}
destroyer :: proc(img: ^Image) {
_ = destroy(img)
Expand Down
3 changes: 3 additions & 0 deletions core/image/png/png.odin
Original file line number Diff line number Diff line change
Expand Up @@ -1182,6 +1182,9 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
panic("We should never see bit depths other than 8, 16 and 'Paletted' here.")
}

if .vertical_flip in options {
image.vertical_flip(img)
}
return img, nil
}

Expand Down
4 changes: 4 additions & 0 deletions core/image/qoi/qoi.odin
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,10 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
return img, .Post_Processing_Error
}

if .vertical_flip in options {
image.vertical_flip(img)
}

return
}

Expand Down
7 changes: 5 additions & 2 deletions core/image/tga/tga.odin
Original file line number Diff line number Diff line change
Expand Up @@ -304,8 +304,11 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a

pixel: RGBA_Pixel

// is flipped XOR user wants to flip
do_read_from_top := bool(int(origin_is_top) ~ int(.vertical_flip in options))

stride := img.width * dest_channels
line := 0 if origin_is_top else img.height - 1
line := 0 if do_read_from_top else img.height - 1

for _ in 0..<img.height {
offset := line * stride + (0 if origin_is_left else (stride - dest_channels))
Expand Down Expand Up @@ -369,7 +372,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
offset += dest_channels if origin_is_left else -dest_channels
rle_repetition_count -= 1
}
line += 1 if origin_is_top else -1
line += 1 if do_read_from_top else -1
}
return img, nil
}
Expand Down