Haio
0.2.X
Homebrew Asset IO/CDN
Toggle main menu visibility
Loading...
Searching...
No Matches
haio_transform.hpp
Go to the documentation of this file.
1
#pragma once
2
3
#include "
haio_codec.hpp
"
4
5
#include <algorithm>
6
#include <stdexcept>
7
8
/**
9
* geometry on addressable pixels. the colour no longer has to be rgba8888: the only
10
* thing these ever needed from it was how wide a pixel is, which PixelStride answers,
11
* so a crop on rgb565 stops going through a conversion it never used.
12
*/
13
namespace
Haio
{
14
15
/**
16
* a transformed picture keeps everything about the original except its pixels.
17
*
18
* building a fresh Image would drop whatever else the colour carries, which for a
19
* palette is the palette: a cropped picture would come back as indices into nothing.
20
*/
21
template
<Color P>
22
Image<P>
withPixels
(
const
Image<P>
& from,
int
width,
int
height, std::vector<uint8_t> pixels) {
23
Image<P>
out = from;
24
out.
width
= width;
25
out.
height
= height;
26
out.
data
= std::move(pixels);
27
return
out;
28
}
29
30
template
<Color P>
31
requires
Addressable<P>
32
Image<P>
cropImage
(
const
Image<P>
& image,
Rect
rect) {
33
constexpr
auto
stride =
strideOf
(P);
34
35
const
int
x0 = std::clamp(rect.
x
, 0, image.
width
);
36
const
int
y0 = std::clamp(rect.
y
, 0, image.
height
);
37
const
int
x1 = std::clamp(rect.
x
+ rect.
width
, x0, image.
width
);
38
const
int
y1 = std::clamp(rect.
y
+ rect.
height
, y0, image.
height
);
39
const
int
width = x1 - x0;
40
const
int
height = y1 - y0;
41
42
std::vector<uint8_t> out(
static_cast<
size_t
>
(width) *
static_cast<
size_t
>
(height) * stride);
43
for
(
int
y = 0; y < height; y++) {
44
const
auto
src = (
static_cast<
size_t
>
(y0 + y) *
static_cast<
size_t
>
(image.
width
) +
static_cast<
size_t
>
(x0)) * stride;
45
const
auto
dst =
static_cast<
size_t
>
(y) *
static_cast<
size_t
>
(width) * stride;
46
std::copy_n(image.
data
.data() + src,
static_cast<
size_t
>
(width) * stride, out.data() + dst);
47
}
48
return
withPixels
(image, width, height, std::move(out));
49
}
50
51
/** nearest neighbour: one side may be left at zero and follows the other */
52
template
<Color P>
53
requires
Addressable<P>
54
Image<P>
resizeImage
(
const
Image<P>
& image,
Size
size) {
55
constexpr
auto
stride =
strideOf
(P);
56
57
if
(size.
width
<= 0 && size.
height
<= 0)
throw
std::runtime_error(
"resize expects a positive size"
);
58
59
int
width = size.
width
;
60
int
height = size.
height
;
61
if
(width <= 0) width = std::max(1, image.
width
* height / image.
height
);
62
if
(height <= 0) height = std::max(1, image.
height
* width / image.
width
);
63
64
std::vector<uint8_t> out(
static_cast<
size_t
>
(width) *
static_cast<
size_t
>
(height) * stride);
65
for
(
int
y = 0; y < height; y++) {
66
const
int
sy = std::min(image.
height
- 1, y * image.
height
/ height);
67
for
(
int
x = 0; x < width; x++) {
68
const
int
sx = std::min(image.
width
- 1, x * image.
width
/ width);
69
const
auto
src = (
static_cast<
size_t
>
(sy) *
static_cast<
size_t
>
(image.
width
) +
static_cast<
size_t
>
(sx)) * stride;
70
const
auto
dst = (
static_cast<
size_t
>
(y) *
static_cast<
size_t
>
(width) +
static_cast<
size_t
>
(x)) * stride;
71
std::copy_n(image.
data
.data() + src, stride, out.data() + dst);
72
}
73
}
74
return
withPixels
(image, width, height, std::move(out));
75
}
76
77
/**
78
* clears the alpha outside a rounded corner, so this one asks for more than the other
79
* two: a colour with no alpha has no way to say "not here", and asking for square
80
* corners back would be a worse answer than refusing to compile.
81
*/
82
template
<Color P>
83
requires
Maskable<P>
84
Image<P>
roundImageCorners
(
const
Image<P>
& image,
int
radius) {
85
constexpr
auto
stride =
strideOf
(P);
86
constexpr
auto
alpha =
static_cast<
size_t
>
(
alphaOffsetOf
(P));
87
88
if
(radius <= 0)
return
image;
89
90
Image<P>
out = image;
91
const
int
r = std::min(radius, std::min(image.
width
, image.
height
) / 2);
92
const
int
r2 = r * r;
93
94
auto
maskCorner = [&](
int
x,
int
y,
int
cx,
int
cy) {
95
const
int
dx = x - cx;
96
const
int
dy = y - cy;
97
if
(dx * dx + dy * dy > r2) {
98
const
auto
off = (
static_cast<
size_t
>
(y) *
static_cast<
size_t
>
(out.
width
) +
static_cast<
size_t
>
(x)) * stride + alpha;
99
out.
data
[off] = 0;
100
}
101
};
102
103
for
(
int
y = 0; y < r; y++) {
104
for
(
int
x = 0; x < r; x++) {
105
maskCorner(x, y, r - 1, r - 1);
106
maskCorner(out.
width
- 1 - x, y, out.
width
- r, r - 1);
107
maskCorner(x, out.
height
- 1 - y, r - 1, out.
height
- r);
108
maskCorner(out.
width
- 1 - x, out.
height
- 1 - y, out.
width
- r, out.
height
- r);
109
}
110
}
111
112
return
out;
113
}
114
115
}
haio_codec.hpp
Haio
Definition
haio.hpp:11
Haio::cropImage
Image< P > cropImage(const Image< P > &image, Rect rect)
Definition
haio_transform.hpp:32
Haio::Rect::x
int x
Definition
haio_object.hpp:6
Haio::Rect::width
int width
Definition
haio_object.hpp:8
Haio::Rect::height
int height
Definition
haio_object.hpp:9
Haio::Rect::y
int y
Definition
haio_object.hpp:7
Haio::strideOf
constexpr size_t strideOf(Color color)
Definition
haio_codec.hpp:48
Haio::Size::height
int height
Definition
haio_object.hpp:14
Haio::alphaOffsetOf
constexpr int alphaOffsetOf(Color color)
Definition
haio_codec.hpp:78
Haio::roundImageCorners
Image< P > roundImageCorners(const Image< P > &image, int radius)
Definition
haio_transform.hpp:84
Haio::withPixels
Image< P > withPixels(const Image< P > &from, int width, int height, std::vector< uint8_t > pixels)
Definition
haio_transform.hpp:22
Haio::Size::width
int width
Definition
haio_object.hpp:13
Haio::resizeImage
Image< P > resizeImage(const Image< P > &image, Size size)
Definition
haio_transform.hpp:54
Haio::Rect
Definition
haio_object.hpp:5
Haio::Size
Definition
haio_object.hpp:12
Haio::Image
Definition
haio_codec.hpp:36
Haio::Image::height
int height
Definition
haio_codec.hpp:39
Haio::Image::width
int width
Definition
haio_codec.hpp:38
Haio::Image::data
std::vector< uint8_t > data
Definition
haio_codec.hpp:40
include
haio_transform.hpp
Generated by
1.18.0