21using Pixel = uint32_t;
29void scale_1on3(std::span<const Pixel> in, std::span<Pixel> out);
30void scale_1on4(std::span<const Pixel> in, std::span<Pixel> out);
31void scale_1on6(std::span<const Pixel> in, std::span<Pixel> out);
32void Scale_1on2(std::span<const Pixel> in, std::span<Pixel> out);
33void scale_2on1(std::span<const Pixel> in, std::span<Pixel> out);
34void scale_6on1(std::span<const Pixel> in, std::span<Pixel> out);
35void scale_4on1(std::span<const Pixel> in, std::span<Pixel> out);
36void scale_3on1(std::span<const Pixel> in, std::span<Pixel> out);
37void scale_3on2(std::span<const Pixel> in, std::span<Pixel> out);
38void scale_3on4(std::span<const Pixel> in, std::span<Pixel> out);
39void scale_3on8(std::span<const Pixel> in, std::span<Pixel> out);
40void scale_2on3(std::span<const Pixel> in, std::span<Pixel> out);
41void scale_4on3(std::span<const Pixel> in, std::span<Pixel> out);
42void scale_8on3(std::span<const Pixel> in, std::span<Pixel> out);
43void scale_2on9(std::span<const Pixel> in, std::span<Pixel> out);
44void scale_4on9(std::span<const Pixel> in, std::span<Pixel> out);
45void scale_8on9(std::span<const Pixel> in, std::span<Pixel> out);
46void scale_4on5(std::span<const Pixel> in, std::span<Pixel> out);
47void scale_7on8(std::span<const Pixel> in, std::span<Pixel> out);
48void scale_9on10(std::span<const Pixel> in, std::span<Pixel> out);
49void scale_17on20(std::span<const Pixel> in, std::span<Pixel> out);
58template<
unsigned w1 = 1,
unsigned w2 = 1>
59void blendLines(std::span<const Pixel> in1, std::span<const Pixel> in2,
60 std::span<Pixel> out);
69void alphaBlendLines(std::span<const Pixel> in1, std::span<const Pixel> in2,
70 std::span<Pixel> out);
72 std::span<Pixel> out);
78static inline void scale_1onN(
79 std::span<const Pixel> in, std::span<Pixel> out)
81 auto outWidth = out.size();
82 assert(in.size() == (outWidth / N));
85 for (; i < (outWidth - (N - 1)); i += N, j += 1) {
91 for (
auto k :
xrange(N - 1)) {
92 if ((i + k) < outWidth) out[i + k] = 0;
96inline void scale_1on3(std::span<const Pixel> in, std::span<Pixel> out)
98 scale_1onN<3>(in, out);
101inline void scale_1on4(std::span<const Pixel> in, std::span<Pixel> out)
103 scale_1onN<4>(in, out);
106inline void scale_1on6(std::span<const Pixel> in, std::span<Pixel> out)
108 scale_1onN<6>(in, out);
112inline __m128i unpacklo(__m128i x, __m128i y)
115 return _mm_unpacklo_epi32(x, y);
117inline __m128i unpackhi(__m128i x, __m128i y)
120 return _mm_unpackhi_epi32(x, y);
123inline void scale_1on2_SSE(
const Pixel* __restrict in_,
Pixel* __restrict out_,
size_t srcWidth)
125 size_t bytes = srcWidth *
sizeof(
Pixel);
126 assert((bytes % (4 *
sizeof(__m128i))) == 0);
129 const auto* in = std::bit_cast<const char*>(in_) + bytes;
130 auto* out = std::bit_cast< char*>(out_) + 2 * bytes;
132 auto x = -ptrdiff_t(bytes);
134 __m128i a0 = _mm_loadu_si128(std::bit_cast<const __m128i*>(in + x + 0));
135 __m128i a1 = _mm_loadu_si128(std::bit_cast<const __m128i*>(in + x + 16));
136 __m128i a2 = _mm_loadu_si128(std::bit_cast<const __m128i*>(in + x + 32));
137 __m128i a3 = _mm_loadu_si128(std::bit_cast<const __m128i*>(in + x + 48));
138 __m128i l0 = unpacklo(a0, a0);
139 __m128i h0 = unpackhi(a0, a0);
140 __m128i l1 = unpacklo(a1, a1);
141 __m128i h1 = unpackhi(a1, a1);
142 __m128i l2 = unpacklo(a2, a2);
143 __m128i h2 = unpackhi(a2, a2);
144 __m128i
l3 = unpacklo(a3, a3);
145 __m128i h3 = unpackhi(a3, a3);
146 _mm_storeu_si128(std::bit_cast<__m128i*>(out + 2*x + 0), l0);
147 _mm_storeu_si128(std::bit_cast<__m128i*>(out + 2*x + 16), h0);
148 _mm_storeu_si128(std::bit_cast<__m128i*>(out + 2*x + 32), l1);
149 _mm_storeu_si128(std::bit_cast<__m128i*>(out + 2*x + 48), h1);
150 _mm_storeu_si128(std::bit_cast<__m128i*>(out + 2*x + 64), l2);
151 _mm_storeu_si128(std::bit_cast<__m128i*>(out + 2*x + 80), h2);
152 _mm_storeu_si128(std::bit_cast<__m128i*>(out + 2*x + 96),
l3);
153 _mm_storeu_si128(std::bit_cast<__m128i*>(out + 2*x + 112), h3);
154 x += 4 *
sizeof(__m128i);
159inline void scale_1on2(std::span<const Pixel> in, std::span<Pixel> out)
173 auto srcWidth = in.size();
174 assert(out.size() == 2 * srcWidth);
177 size_t chunk = 4 *
sizeof(__m128i) /
sizeof(
Pixel);
178 size_t srcWidth2 = srcWidth & ~(chunk - 1);
179 scale_1on2_SSE(in.data(), out.data(), srcWidth2);
180 in = in .subspan( srcWidth2);
181 out = out.subspan(2 * srcWidth2);
182 srcWidth -= srcWidth2;
187 for (
auto x :
xrange(srcWidth)) {
188 out[x * 2] = out[x * 2 + 1] = in[x];
193template<
int IMM8>
static inline __m128i shuffle(__m128i x, __m128i y)
195 return _mm_castps_si128(_mm_shuffle_ps(
196 _mm_castsi128_ps(x), _mm_castsi128_ps(y), IMM8));
199inline __m128i blend(__m128i x, __m128i y)
202 __m128i p = shuffle<0x88>(x, y);
203 __m128i q = shuffle<0xDD>(x, y);
204 return _mm_avg_epu8(p, q);
207inline void scale_2on1_SSE(
208 const Pixel* __restrict in_,
Pixel* __restrict out_,
size_t dstBytes)
210 assert((dstBytes % (4 *
sizeof(__m128i))) == 0);
211 assert(dstBytes != 0);
213 const auto* in = std::bit_cast<const char*>(in_) + 2 * dstBytes;
214 auto* out = std::bit_cast< char*>(out_) + dstBytes;
216 auto x = -ptrdiff_t(dstBytes);
218 __m128i a0 = _mm_loadu_si128(std::bit_cast<const __m128i*>(in + 2*x + 0));
219 __m128i a1 = _mm_loadu_si128(std::bit_cast<const __m128i*>(in + 2*x + 16));
220 __m128i a2 = _mm_loadu_si128(std::bit_cast<const __m128i*>(in + 2*x + 32));
221 __m128i a3 = _mm_loadu_si128(std::bit_cast<const __m128i*>(in + 2*x + 48));
222 __m128i a4 = _mm_loadu_si128(std::bit_cast<const __m128i*>(in + 2*x + 64));
223 __m128i a5 = _mm_loadu_si128(std::bit_cast<const __m128i*>(in + 2*x + 80));
224 __m128i a6 = _mm_loadu_si128(std::bit_cast<const __m128i*>(in + 2*x + 96));
225 __m128i a7 = _mm_loadu_si128(std::bit_cast<const __m128i*>(in + 2*x + 112));
226 __m128i b0 = blend(a0, a1);
227 __m128i b1 = blend(a2, a3);
228 __m128i b2 = blend(a4, a5);
229 __m128i b3 = blend(a6, a7);
230 _mm_storeu_si128(std::bit_cast<__m128i*>(out + x + 0), b0);
231 _mm_storeu_si128(std::bit_cast<__m128i*>(out + x + 16), b1);
232 _mm_storeu_si128(std::bit_cast<__m128i*>(out + x + 32), b2);
233 _mm_storeu_si128(std::bit_cast<__m128i*>(out + x + 48), b3);
234 x += 4 *
sizeof(__m128i);
239inline void scale_2on1(std::span<const Pixel> in, std::span<Pixel> out)
241 assert(in.size() == 2 * out.size());
242 auto outWidth = out.size();
244 auto n64 = (outWidth *
sizeof(
Pixel)) & ~63;
245 scale_2on1_SSE(in.data(), out.data(), n64);
246 outWidth &= ((64 /
sizeof(
Pixel)) - 1);
247 if (outWidth == 0) [[likely]]
return;
248 in = in .subspan(2 * n64 /
sizeof(
Pixel));
249 out = out.subspan( n64 /
sizeof(
Pixel));
254 for (
auto i :
xrange(outWidth)) {
255 out[i] = pixelOps.template blend<1, 1>(
256 in[2 * i + 0], in[2 * i + 1]);
260inline void scale_6on1(std::span<const Pixel> in, std::span<Pixel> out)
262 assert(in.size() == 6 * out.size());
264 for (
auto i :
xrange(out.size())) {
265 out[i] = pixelOps.template blend<1, 1, 1, 1, 1, 1>(subspan<6>(in, 6 * i));
269inline void scale_4on1(std::span<const Pixel> in, std::span<Pixel> out)
271 assert(in.size() == 4 * out.size());
273 for (
auto i :
xrange(out.size())) {
274 out[i] = pixelOps.template blend<1, 1, 1, 1>(subspan<4>(in, 4 * i));
278inline void scale_3on1(std::span<const Pixel> in, std::span<Pixel> out)
280 assert(in.size() == 3 * out.size());
282 for (
auto i :
xrange(out.size())) {
283 out[i] = pixelOps.template blend<1, 1, 1>(subspan<3>(in, 3 * i));
287inline void scale_3on2(std::span<const Pixel> in, std::span<Pixel> out)
289 assert((in.size() / 3) == (out.size() / 2));
291 size_t n = out.size();
293 for (; i < (n - 1); i += 2, j += 3) {
294 out[i + 0] = pixelOps.template blend<2, 1>(subspan<2>(in, j + 0));
295 out[i + 1] = pixelOps.template blend<1, 2>(subspan<2>(in, j + 1));
297 if (i < n) out[i] = 0;
300inline void scale_3on4(std::span<const Pixel> in, std::span<Pixel> out)
302 assert((in.size() / 3) == (out.size() / 4));
304 size_t n = out.size();
306 for (; i < (n - 3); i += 4, j += 3) {
307 out[i + 0] = in[j + 0];
308 out[i + 1] = pixelOps.template blend<1, 2>(subspan<2>(in, j + 0));
309 out[i + 2] = pixelOps.template blend<2, 1>(subspan<2>(in, j + 1));
310 out[i + 3] = in[j + 2];
312 for (
auto k :
xrange(4 - 1)) {
313 if ((i + k) < n) out[i + k] = 0;
317inline void scale_3on8(std::span<const Pixel> in, std::span<Pixel> out)
319 assert((in.size() / 3) == (out.size() / 8));
321 size_t n = out.size();
323 for (; i < (n - 7); i += 8, j += 3) {
324 out[i + 0] = in[j + 0];
325 out[i + 1] = in[j + 0];
326 out[i + 2] = pixelOps.template blend<2, 1>(subspan<2>(in, j + 0));
327 out[i + 3] = in[j + 1];
328 out[i + 4] = in[j + 1];
329 out[i + 5] = pixelOps.template blend<1, 2>(subspan<2>(in, j + 1));
330 out[i + 6] = in[j + 2];
331 out[i + 7] = in[j + 2];
333 for (
auto k :
xrange(8 - 1)) {
334 if ((i + k) < n) out[i + k] = 0;
338inline void scale_2on3(std::span<const Pixel> in, std::span<Pixel> out)
340 assert((in.size() / 2) == (out.size() / 3));
342 size_t n = out.size();
344 for (; i < (n - 2); i += 3, j += 2) {
345 out[i + 0] = in[j + 0];
346 out[i + 1] = pixelOps.template blend<1, 1>(subspan<2>(in, j));
347 out[i + 2] = in[j + 1];
349 if ((i + 0) < n) out[i + 0] = 0;
350 if ((i + 1) < n) out[i + 1] = 0;
353inline void scale_4on3(std::span<const Pixel> in, std::span<Pixel> out)
355 assert((in.size() / 4) == (out.size() / 3));
357 size_t n = out.size();
359 for (; i < (n - 2); i += 3, j += 4) {
360 out[i + 0] = pixelOps.template blend<3, 1>(subspan<2>(in, j + 0));
361 out[i + 1] = pixelOps.template blend<1, 1>(subspan<2>(in, j + 1));
362 out[i + 2] = pixelOps.template blend<1, 3>(subspan<2>(in, j + 2));
364 if ((i + 0) < n) out[i + 0] = 0;
365 if ((i + 1) < n) out[i + 1] = 0;
368inline void scale_8on3(std::span<const Pixel> in, std::span<Pixel> out)
370 assert((in.size() / 8) == (out.size() / 3));
372 size_t n = out.size();
374 for (; i < (n - 2); i += 3, j += 8) {
375 out[i + 0] = pixelOps.template blend<3, 3, 2> (subspan<3>(in, j + 0));
376 out[i + 1] = pixelOps.template blend<1, 3, 3, 1>(subspan<4>(in, j + 2));
377 out[i + 2] = pixelOps.template blend<2, 3, 3> (subspan<3>(in, j + 5));
379 if ((i + 0) < n) out[i + 0] = 0;
380 if ((i + 1) < n) out[i + 1] = 0;
383inline void scale_2on9(std::span<const Pixel> in, std::span<Pixel> out)
385 assert((in.size() / 2) == (out.size() / 9));
387 size_t n = out.size();
389 for (; i < (n - 8); i += 9, j += 2) {
390 out[i + 0] = in[j + 0];
391 out[i + 1] = in[j + 0];
392 out[i + 2] = in[j + 0];
393 out[i + 3] = in[j + 0];
394 out[i + 4] = pixelOps.template blend<1, 1>(subspan<2>(in, j));
395 out[i + 5] = in[j + 1];
396 out[i + 6] = in[j + 1];
397 out[i + 7] = in[j + 1];
398 out[i + 8] = in[j + 1];
400 if ((i + 0) < n) out[i + 0] = 0;
401 if ((i + 1) < n) out[i + 1] = 0;
402 if ((i + 2) < n) out[i + 2] = 0;
403 if ((i + 3) < n) out[i + 3] = 0;
404 if ((i + 4) < n) out[i + 4] = 0;
405 if ((i + 5) < n) out[i + 5] = 0;
406 if ((i + 6) < n) out[i + 6] = 0;
407 if ((i + 7) < n) out[i + 7] = 0;
410inline void scale_4on9(std::span<const Pixel> in, std::span<Pixel> out)
412 assert((in.size() / 4) == (out.size() / 9));
414 size_t n = out.size();
416 for (; i < (n - 8); i += 9, j += 4) {
417 out[i + 0] = in[j + 0];
418 out[i + 1] = in[j + 0];
419 out[i + 2] = pixelOps.template blend<1, 3>(subspan<2>(in, j + 0));
420 out[i + 3] = in[j + 1];
421 out[i + 4] = pixelOps.template blend<1, 1>(subspan<2>(in, j + 1));
422 out[i + 5] = in[j + 2];
423 out[i + 6] = pixelOps.template blend<3, 1>(subspan<2>(in, j + 2));
424 out[i + 7] = in[j + 3];
425 out[i + 8] = in[j + 3];
427 if ((i + 0) < n) out[i + 0] = 0;
428 if ((i + 1) < n) out[i + 1] = 0;
429 if ((i + 2) < n) out[i + 2] = 0;
430 if ((i + 3) < n) out[i + 3] = 0;
431 if ((i + 4) < n) out[i + 4] = 0;
432 if ((i + 5) < n) out[i + 5] = 0;
433 if ((i + 6) < n) out[i + 6] = 0;
434 if ((i + 7) < n) out[i + 7] = 0;
437inline void scale_8on9(std::span<const Pixel> in, std::span<Pixel> out)
439 assert((in.size() / 8) == (out.size() / 9));
441 size_t n = out.size();
443 for (; i < (n - 8); i += 9, j += 8) {
444 out[i + 0] = in[j + 0];
445 out[i + 1] = pixelOps.template blend<1, 7>(subspan<2>(in, j + 0));
446 out[i + 2] = pixelOps.template blend<1, 3>(subspan<2>(in, j + 1));
447 out[i + 3] = pixelOps.template blend<3, 5>(subspan<2>(in, j + 2));
448 out[i + 4] = pixelOps.template blend<1, 1>(subspan<2>(in, j + 3));
449 out[i + 5] = pixelOps.template blend<5, 3>(subspan<2>(in, j + 4));
450 out[i + 6] = pixelOps.template blend<3, 1>(subspan<2>(in, j + 5));
451 out[i + 7] = pixelOps.template blend<7, 1>(subspan<2>(in, j + 6));
452 out[i + 8] = in[j + 7];
454 if ((i + 0) < n) out[i + 0] = 0;
455 if ((i + 1) < n) out[i + 1] = 0;
456 if ((i + 2) < n) out[i + 2] = 0;
457 if ((i + 3) < n) out[i + 3] = 0;
458 if ((i + 4) < n) out[i + 4] = 0;
459 if ((i + 5) < n) out[i + 5] = 0;
460 if ((i + 6) < n) out[i + 6] = 0;
461 if ((i + 7) < n) out[i + 7] = 0;
464inline void scale_4on5(std::span<const Pixel> in, std::span<Pixel> out)
466 assert((in.size() / 4) == (out.size() / 5));
468 size_t n = out.size();
469 assert((n % 5) == 0);
470 for (
size_t i = 0, j = 0; i < n; i += 5, j += 4) {
471 out[i + 0] = in[j + 0];
472 out[i + 1] = pixelOps.template blend<1, 3>(subspan<2>(in, j + 0));
473 out[i + 2] = pixelOps.template blend<1, 1>(subspan<2>(in, j + 1));
474 out[i + 3] = pixelOps.template blend<3, 1>(subspan<2>(in, j + 2));
475 out[i + 4] = in[j + 3];
479inline void scale_7on8(std::span<const Pixel> in, std::span<Pixel> out)
481 assert((in.size() / 7) == (out.size() / 8));
483 size_t n = out.size();
484 assert((n % 8) == 0);
485 for (
size_t i = 0, j = 0; i < n; i += 8, j += 7) {
486 out[i + 0] = in[j + 0];
487 out[i + 1] = pixelOps.template blend<1, 6>(subspan<2>(in, j + 0));
488 out[i + 2] = pixelOps.template blend<2, 5>(subspan<2>(in, j + 1));
489 out[i + 3] = pixelOps.template blend<3, 4>(subspan<2>(in, j + 2));
490 out[i + 4] = pixelOps.template blend<4, 3>(subspan<2>(in, j + 3));
491 out[i + 5] = pixelOps.template blend<5, 2>(subspan<2>(in, j + 4));
492 out[i + 6] = pixelOps.template blend<6, 1>(subspan<2>(in, j + 5));
493 out[i + 7] = in[j + 6];
497inline void scale_17on20(std::span<const Pixel> in, std::span<Pixel> out)
499 assert((in.size() / 17) == (out.size() / 20));
501 size_t n = out.size();
502 assert((n % 20) == 0);
503 for (
size_t i = 0, j = 0; i < n; i += 20, j += 17) {
504 out[i + 0] = in[j + 0];
505 out[i + 1] = pixelOps.template blend< 3, 14>(subspan<2>(in, j + 0));
506 out[i + 2] = pixelOps.template blend< 6, 11>(subspan<2>(in, j + 1));
507 out[i + 3] = pixelOps.template blend< 9, 8>(subspan<2>(in, j + 2));
508 out[i + 4] = pixelOps.template blend<12, 5>(subspan<2>(in, j + 3));
509 out[i + 5] = pixelOps.template blend<15, 2>(subspan<2>(in, j + 4));
510 out[i + 6] = in[j + 5];
511 out[i + 7] = pixelOps.template blend< 1, 16>(subspan<2>(in, j + 5));
512 out[i + 8] = pixelOps.template blend< 4, 13>(subspan<2>(in, j + 6));
513 out[i + 9] = pixelOps.template blend< 7, 10>(subspan<2>(in, j + 7));
514 out[i + 10] = pixelOps.template blend<10, 7>(subspan<2>(in, j + 8));
515 out[i + 11] = pixelOps.template blend<13, 4>(subspan<2>(in, j + 9));
516 out[i + 12] = pixelOps.template blend<16, 1>(subspan<2>(in, j + 10));
517 out[i + 13] = in[j + 11];
518 out[i + 14] = pixelOps.template blend< 2, 15>(subspan<2>(in, j + 11));
519 out[i + 15] = pixelOps.template blend< 5, 12>(subspan<2>(in, j + 12));
520 out[i + 16] = pixelOps.template blend< 8, 9>(subspan<2>(in, j + 13));
521 out[i + 17] = pixelOps.template blend<11, 6>(subspan<2>(in, j + 14));
522 out[i + 18] = pixelOps.template blend<14, 3>(subspan<2>(in, j + 15));
523 out[i + 19] = in[j + 16];
527inline void scale_9on10(std::span<const Pixel> in, std::span<Pixel> out)
529 assert((in.size() / 9) == (out.size() / 10));
531 size_t n = out.size();
532 assert((n % 10) == 0);
533 for (
size_t i = 0, j = 0; i < n; i += 10, j += 9) {
534 out[i + 0] = in[j + 0];
535 out[i + 1] = pixelOps.template blend<1, 8>(subspan<2>(in, j + 0));
536 out[i + 2] = pixelOps.template blend<2, 7>(subspan<2>(in, j + 1));
537 out[i + 3] = pixelOps.template blend<3, 6>(subspan<2>(in, j + 2));
538 out[i + 4] = pixelOps.template blend<4, 5>(subspan<2>(in, j + 3));
539 out[i + 5] = pixelOps.template blend<5, 4>(subspan<2>(in, j + 4));
540 out[i + 6] = pixelOps.template blend<6, 3>(subspan<2>(in, j + 5));
541 out[i + 7] = pixelOps.template blend<7, 2>(subspan<2>(in, j + 6));
542 out[i + 8] = pixelOps.template blend<8, 1>(subspan<2>(in, j + 7));
543 out[i + 9] = in[j + 8];
547template<
unsigned w1,
unsigned w2>
548void blendLines(std::span<const Pixel> in1, std::span<const Pixel> in2, std::span<Pixel> out)
553 assert(in1.size() == in2.size());
554 assert(in1.size() == out.size());
557 o = pixelOps.template blend<w1, w2>(i1, i2);
562 std::span<const Pixel> in1, std::span<const Pixel> in2, std::span<Pixel> out)
565 assert(in1.size() == in2.size());
566 assert(in1.size() == out.size());
574 Pixel in1, std::span<const Pixel> in2, std::span<Pixel> out)
580 assert(in2.size() == out.size());
583 unsigned alpha = pixelOps.
alpha(in1);
592 unsigned alpha2 = 256 - alpha;
594 o = in1M + pixelOps.
multiply(i2, alpha2);
unsigned alpha(Pixel p) const
static Pixel multiply(Pixel p, unsigned x)
Perform a component wise multiplication of a pixel with an 8-bit fractional value: result = (pixel * ...
Pixel alphaBlend(Pixel p1, Pixel p2) const
Perform alpha blending of two pixels.
imat3 l3(ivec3(0, 2, 3), ivec3(4, 5, 6), ivec3(7, 8, 9))
This file implemented 3 utility functions:
void scale_3on1(std::span< const Pixel > in, std::span< Pixel > out)
void blendLines(std::span< const Pixel > in1, std::span< const Pixel > in2, std::span< Pixel > out)
BlendLines functor Generate an output line that is an interpolation of two input lines.
void scale_2on1(std::span< const Pixel > in, std::span< Pixel > out)
void scale_7on8(std::span< const Pixel > in, std::span< Pixel > out)
void scale_2on3(std::span< const Pixel > in, std::span< Pixel > out)
void scale_4on9(std::span< const Pixel > in, std::span< Pixel > out)
void scale_4on5(std::span< const Pixel > in, std::span< Pixel > out)
void scale_6on1(std::span< const Pixel > in, std::span< Pixel > out)
void scale_1on2(std::span< const Pixel > in, std::span< Pixel > out)
void Scale_1on2(std::span< const Pixel > in, std::span< Pixel > out)
void scale_1on3(std::span< const Pixel > in, std::span< Pixel > out)
Scale_XonY functions Transforms an input line of pixel to an output line (possibly) with a different ...
void scale_17on20(std::span< const Pixel > in, std::span< Pixel > out)
void scale_4on3(std::span< const Pixel > in, std::span< Pixel > out)
void scale_3on2(std::span< const Pixel > in, std::span< Pixel > out)
void scale_3on8(std::span< const Pixel > in, std::span< Pixel > out)
void scale_2on9(std::span< const Pixel > in, std::span< Pixel > out)
void alphaBlendLines(std::span< const Pixel > in1, std::span< const Pixel > in2, std::span< Pixel > out)
AlphaBlendLines functor Generate an output line that is a per-pixel-alpha-blend of the two input line...
void scale_9on10(std::span< const Pixel > in, std::span< Pixel > out)
void scale_1on4(std::span< const Pixel > in, std::span< Pixel > out)
CharacterConverter::Pixel Pixel
void scale_1on6(std::span< const Pixel > in, std::span< Pixel > out)
void scale_4on1(std::span< const Pixel > in, std::span< Pixel > out)
void scale_3on4(std::span< const Pixel > in, std::span< Pixel > out)
void scale_8on9(std::span< const Pixel > in, std::span< Pixel > out)
void scale_8on3(std::span< const Pixel > in, std::span< Pixel > out)
auto zip_equal(Ranges &&... ranges)
constexpr auto xrange(T e)