summaryrefslogtreecommitdiff
path: root/externals/stb/stb_image_resize.h
diff options
context:
space:
mode:
Diffstat (limited to 'externals/stb/stb_image_resize.h')
-rw-r--r--externals/stb/stb_image_resize.h2213
1 files changed, 1 insertions, 2212 deletions
diff --git a/externals/stb/stb_image_resize.h b/externals/stb/stb_image_resize.h
index 073ba20d9..3107e0670 100644
--- a/externals/stb/stb_image_resize.h
+++ b/externals/stb/stb_image_resize.h
@@ -1,4 +1,4 @@
1// SPDX-FileCopyrightText: stb http://nothings.org/stb 1// SPDX-FileCopyrightText: Jorge L Rodriguez
2// SPDX-License-Identifier: MIT 2// SPDX-License-Identifier: MIT
3 3
4/* stb_image_resize - v0.97 - public domain image resizing 4/* stb_image_resize - v0.97 - public domain image resizing
@@ -383,2217 +383,6 @@ STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int
383//// end header file ///////////////////////////////////////////////////// 383//// end header file /////////////////////////////////////////////////////
384#endif // STBIR_INCLUDE_STB_IMAGE_RESIZE_H 384#endif // STBIR_INCLUDE_STB_IMAGE_RESIZE_H
385 385
386
387
388
389
390#ifdef STB_IMAGE_RESIZE_IMPLEMENTATION
391
392#ifndef STBIR_ASSERT
393#include <assert.h>
394#define STBIR_ASSERT(x) assert(x)
395#endif
396
397// For memset
398#include <string.h>
399
400#include <math.h>
401
402#ifndef STBIR_MALLOC
403#include <stdlib.h>
404// use comma operator to evaluate c, to avoid "unused parameter" warnings
405#define STBIR_MALLOC(size,c) ((void)(c), malloc(size))
406#define STBIR_FREE(ptr,c) ((void)(c), free(ptr))
407#endif
408
409#ifndef _MSC_VER
410#ifdef __cplusplus
411#define stbir__inline inline
412#else
413#define stbir__inline
414#endif
415#else
416#define stbir__inline __forceinline
417#endif
418
419
420// should produce compiler error if size is wrong
421typedef unsigned char stbir__validate_uint32[sizeof(stbir_uint32) == 4 ? 1 : -1];
422
423#ifdef _MSC_VER
424#define STBIR__NOTUSED(v) (void)(v)
425#else
426#define STBIR__NOTUSED(v) (void)sizeof(v)
427#endif
428
429#define STBIR__ARRAY_SIZE(a) (sizeof((a))/sizeof((a)[0]))
430
431#ifndef STBIR_DEFAULT_FILTER_UPSAMPLE
432#define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM
433#endif
434
435#ifndef STBIR_DEFAULT_FILTER_DOWNSAMPLE
436#define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_MITCHELL
437#endif
438
439#ifndef STBIR_PROGRESS_REPORT
440#define STBIR_PROGRESS_REPORT(float_0_to_1)
441#endif
442
443#ifndef STBIR_MAX_CHANNELS
444#define STBIR_MAX_CHANNELS 64
445#endif
446
447#if STBIR_MAX_CHANNELS > 65536
448#error "Too many channels; STBIR_MAX_CHANNELS must be no more than 65536."
449// because we store the indices in 16-bit variables
450#endif
451
452// This value is added to alpha just before premultiplication to avoid
453// zeroing out color values. It is equivalent to 2^-80. If you don't want
454// that behavior (it may interfere if you have floating point images with
455// very small alpha values) then you can define STBIR_NO_ALPHA_EPSILON to
456// disable it.
457#ifndef STBIR_ALPHA_EPSILON
458#define STBIR_ALPHA_EPSILON ((float)1 / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20))
459#endif
460
461
462
463#ifdef _MSC_VER
464#define STBIR__UNUSED_PARAM(v) (void)(v)
465#else
466#define STBIR__UNUSED_PARAM(v) (void)sizeof(v)
467#endif
468
469// must match stbir_datatype
470static unsigned char stbir__type_size[] = {
471 1, // STBIR_TYPE_UINT8
472 2, // STBIR_TYPE_UINT16
473 4, // STBIR_TYPE_UINT32
474 4, // STBIR_TYPE_FLOAT
475};
476
477// Kernel function centered at 0
478typedef float (stbir__kernel_fn)(float x, float scale);
479typedef float (stbir__support_fn)(float scale);
480
481typedef struct
482{
483 stbir__kernel_fn* kernel;
484 stbir__support_fn* support;
485} stbir__filter_info;
486
487// When upsampling, the contributors are which source pixels contribute.
488// When downsampling, the contributors are which destination pixels are contributed to.
489typedef struct
490{
491 int n0; // First contributing pixel
492 int n1; // Last contributing pixel
493} stbir__contributors;
494
495typedef struct
496{
497 const void* input_data;
498 int input_w;
499 int input_h;
500 int input_stride_bytes;
501
502 void* output_data;
503 int output_w;
504 int output_h;
505 int output_stride_bytes;
506
507 float s0, t0, s1, t1;
508
509 float horizontal_shift; // Units: output pixels
510 float vertical_shift; // Units: output pixels
511 float horizontal_scale;
512 float vertical_scale;
513
514 int channels;
515 int alpha_channel;
516 stbir_uint32 flags;
517 stbir_datatype type;
518 stbir_filter horizontal_filter;
519 stbir_filter vertical_filter;
520 stbir_edge edge_horizontal;
521 stbir_edge edge_vertical;
522 stbir_colorspace colorspace;
523
524 stbir__contributors* horizontal_contributors;
525 float* horizontal_coefficients;
526
527 stbir__contributors* vertical_contributors;
528 float* vertical_coefficients;
529
530 int decode_buffer_pixels;
531 float* decode_buffer;
532
533 float* horizontal_buffer;
534
535 // cache these because ceil/floor are inexplicably showing up in profile
536 int horizontal_coefficient_width;
537 int vertical_coefficient_width;
538 int horizontal_filter_pixel_width;
539 int vertical_filter_pixel_width;
540 int horizontal_filter_pixel_margin;
541 int vertical_filter_pixel_margin;
542 int horizontal_num_contributors;
543 int vertical_num_contributors;
544
545 int ring_buffer_length_bytes; // The length of an individual entry in the ring buffer. The total number of ring buffers is stbir__get_filter_pixel_width(filter)
546 int ring_buffer_num_entries; // Total number of entries in the ring buffer.
547 int ring_buffer_first_scanline;
548 int ring_buffer_last_scanline;
549 int ring_buffer_begin_index; // first_scanline is at this index in the ring buffer
550 float* ring_buffer;
551
552 float* encode_buffer; // A temporary buffer to store floats so we don't lose precision while we do multiply-adds.
553
554 int horizontal_contributors_size;
555 int horizontal_coefficients_size;
556 int vertical_contributors_size;
557 int vertical_coefficients_size;
558 int decode_buffer_size;
559 int horizontal_buffer_size;
560 int ring_buffer_size;
561 int encode_buffer_size;
562} stbir__info;
563
564
565static const float stbir__max_uint8_as_float = 255.0f;
566static const float stbir__max_uint16_as_float = 65535.0f;
567static const double stbir__max_uint32_as_float = 4294967295.0;
568
569
570static stbir__inline int stbir__min(int a, int b)
571{
572 return a < b ? a : b;
573}
574
575static stbir__inline float stbir__saturate(float x)
576{
577 if (x < 0)
578 return 0;
579
580 if (x > 1)
581 return 1;
582
583 return x;
584}
585
586#ifdef STBIR_SATURATE_INT
587static stbir__inline stbir_uint8 stbir__saturate8(int x)
588{
589 if ((unsigned int) x <= 255)
590 return x;
591
592 if (x < 0)
593 return 0;
594
595 return 255;
596}
597
598static stbir__inline stbir_uint16 stbir__saturate16(int x)
599{
600 if ((unsigned int) x <= 65535)
601 return x;
602
603 if (x < 0)
604 return 0;
605
606 return 65535;
607}
608#endif
609
610static float stbir__srgb_uchar_to_linear_float[256] = {
611 0.000000f, 0.000304f, 0.000607f, 0.000911f, 0.001214f, 0.001518f, 0.001821f, 0.002125f, 0.002428f, 0.002732f, 0.003035f,
612 0.003347f, 0.003677f, 0.004025f, 0.004391f, 0.004777f, 0.005182f, 0.005605f, 0.006049f, 0.006512f, 0.006995f, 0.007499f,
613 0.008023f, 0.008568f, 0.009134f, 0.009721f, 0.010330f, 0.010960f, 0.011612f, 0.012286f, 0.012983f, 0.013702f, 0.014444f,
614 0.015209f, 0.015996f, 0.016807f, 0.017642f, 0.018500f, 0.019382f, 0.020289f, 0.021219f, 0.022174f, 0.023153f, 0.024158f,
615 0.025187f, 0.026241f, 0.027321f, 0.028426f, 0.029557f, 0.030713f, 0.031896f, 0.033105f, 0.034340f, 0.035601f, 0.036889f,
616 0.038204f, 0.039546f, 0.040915f, 0.042311f, 0.043735f, 0.045186f, 0.046665f, 0.048172f, 0.049707f, 0.051269f, 0.052861f,
617 0.054480f, 0.056128f, 0.057805f, 0.059511f, 0.061246f, 0.063010f, 0.064803f, 0.066626f, 0.068478f, 0.070360f, 0.072272f,
618 0.074214f, 0.076185f, 0.078187f, 0.080220f, 0.082283f, 0.084376f, 0.086500f, 0.088656f, 0.090842f, 0.093059f, 0.095307f,
619 0.097587f, 0.099899f, 0.102242f, 0.104616f, 0.107023f, 0.109462f, 0.111932f, 0.114435f, 0.116971f, 0.119538f, 0.122139f,
620 0.124772f, 0.127438f, 0.130136f, 0.132868f, 0.135633f, 0.138432f, 0.141263f, 0.144128f, 0.147027f, 0.149960f, 0.152926f,
621 0.155926f, 0.158961f, 0.162029f, 0.165132f, 0.168269f, 0.171441f, 0.174647f, 0.177888f, 0.181164f, 0.184475f, 0.187821f,
622 0.191202f, 0.194618f, 0.198069f, 0.201556f, 0.205079f, 0.208637f, 0.212231f, 0.215861f, 0.219526f, 0.223228f, 0.226966f,
623 0.230740f, 0.234551f, 0.238398f, 0.242281f, 0.246201f, 0.250158f, 0.254152f, 0.258183f, 0.262251f, 0.266356f, 0.270498f,
624 0.274677f, 0.278894f, 0.283149f, 0.287441f, 0.291771f, 0.296138f, 0.300544f, 0.304987f, 0.309469f, 0.313989f, 0.318547f,
625 0.323143f, 0.327778f, 0.332452f, 0.337164f, 0.341914f, 0.346704f, 0.351533f, 0.356400f, 0.361307f, 0.366253f, 0.371238f,
626 0.376262f, 0.381326f, 0.386430f, 0.391573f, 0.396755f, 0.401978f, 0.407240f, 0.412543f, 0.417885f, 0.423268f, 0.428691f,
627 0.434154f, 0.439657f, 0.445201f, 0.450786f, 0.456411f, 0.462077f, 0.467784f, 0.473532f, 0.479320f, 0.485150f, 0.491021f,
628 0.496933f, 0.502887f, 0.508881f, 0.514918f, 0.520996f, 0.527115f, 0.533276f, 0.539480f, 0.545725f, 0.552011f, 0.558340f,
629 0.564712f, 0.571125f, 0.577581f, 0.584078f, 0.590619f, 0.597202f, 0.603827f, 0.610496f, 0.617207f, 0.623960f, 0.630757f,
630 0.637597f, 0.644480f, 0.651406f, 0.658375f, 0.665387f, 0.672443f, 0.679543f, 0.686685f, 0.693872f, 0.701102f, 0.708376f,
631 0.715694f, 0.723055f, 0.730461f, 0.737911f, 0.745404f, 0.752942f, 0.760525f, 0.768151f, 0.775822f, 0.783538f, 0.791298f,
632 0.799103f, 0.806952f, 0.814847f, 0.822786f, 0.830770f, 0.838799f, 0.846873f, 0.854993f, 0.863157f, 0.871367f, 0.879622f,
633 0.887923f, 0.896269f, 0.904661f, 0.913099f, 0.921582f, 0.930111f, 0.938686f, 0.947307f, 0.955974f, 0.964686f, 0.973445f,
634 0.982251f, 0.991102f, 1.0f
635};
636
637static float stbir__srgb_to_linear(float f)
638{
639 if (f <= 0.04045f)
640 return f / 12.92f;
641 else
642 return (float)pow((f + 0.055f) / 1.055f, 2.4f);
643}
644
645static float stbir__linear_to_srgb(float f)
646{
647 if (f <= 0.0031308f)
648 return f * 12.92f;
649 else
650 return 1.055f * (float)pow(f, 1 / 2.4f) - 0.055f;
651}
652
653#ifndef STBIR_NON_IEEE_FLOAT
654// From https://gist.github.com/rygorous/2203834
655
656typedef union
657{
658 stbir_uint32 u;
659 float f;
660} stbir__FP32;
661
662static const stbir_uint32 fp32_to_srgb8_tab4[104] = {
663 0x0073000d, 0x007a000d, 0x0080000d, 0x0087000d, 0x008d000d, 0x0094000d, 0x009a000d, 0x00a1000d,
664 0x00a7001a, 0x00b4001a, 0x00c1001a, 0x00ce001a, 0x00da001a, 0x00e7001a, 0x00f4001a, 0x0101001a,
665 0x010e0033, 0x01280033, 0x01410033, 0x015b0033, 0x01750033, 0x018f0033, 0x01a80033, 0x01c20033,
666 0x01dc0067, 0x020f0067, 0x02430067, 0x02760067, 0x02aa0067, 0x02dd0067, 0x03110067, 0x03440067,
667 0x037800ce, 0x03df00ce, 0x044600ce, 0x04ad00ce, 0x051400ce, 0x057b00c5, 0x05dd00bc, 0x063b00b5,
668 0x06970158, 0x07420142, 0x07e30130, 0x087b0120, 0x090b0112, 0x09940106, 0x0a1700fc, 0x0a9500f2,
669 0x0b0f01cb, 0x0bf401ae, 0x0ccb0195, 0x0d950180, 0x0e56016e, 0x0f0d015e, 0x0fbc0150, 0x10630143,
670 0x11070264, 0x1238023e, 0x1357021d, 0x14660201, 0x156601e9, 0x165a01d3, 0x174401c0, 0x182401af,
671 0x18fe0331, 0x1a9602fe, 0x1c1502d2, 0x1d7e02ad, 0x1ed4028d, 0x201a0270, 0x21520256, 0x227d0240,
672 0x239f0443, 0x25c003fe, 0x27bf03c4, 0x29a10392, 0x2b6a0367, 0x2d1d0341, 0x2ebe031f, 0x304d0300,
673 0x31d105b0, 0x34a80555, 0x37520507, 0x39d504c5, 0x3c37048b, 0x3e7c0458, 0x40a8042a, 0x42bd0401,
674 0x44c20798, 0x488e071e, 0x4c1c06b6, 0x4f76065d, 0x52a50610, 0x55ac05cc, 0x5892058f, 0x5b590559,
675 0x5e0c0a23, 0x631c0980, 0x67db08f6, 0x6c55087f, 0x70940818, 0x74a007bd, 0x787d076c, 0x7c330723,
676};
677
678static stbir_uint8 stbir__linear_to_srgb_uchar(float in)
679{
680 static const stbir__FP32 almostone = { 0x3f7fffff }; // 1-eps
681 static const stbir__FP32 minval = { (127-13) << 23 };
682 stbir_uint32 tab,bias,scale,t;
683 stbir__FP32 f;
684
685 // Clamp to [2^(-13), 1-eps]; these two values map to 0 and 1, respectively.
686 // The tests are carefully written so that NaNs map to 0, same as in the reference
687 // implementation.
688 if (!(in > minval.f)) // written this way to catch NaNs
689 in = minval.f;
690 if (in > almostone.f)
691 in = almostone.f;
692
693 // Do the table lookup and unpack bias, scale
694 f.f = in;
695 tab = fp32_to_srgb8_tab4[(f.u - minval.u) >> 20];
696 bias = (tab >> 16) << 9;
697 scale = tab & 0xffff;
698
699 // Grab next-highest mantissa bits and perform linear interpolation
700 t = (f.u >> 12) & 0xff;
701 return (unsigned char) ((bias + scale*t) >> 16);
702}
703
704#else
705// sRGB transition values, scaled by 1<<28
706static int stbir__srgb_offset_to_linear_scaled[256] =
707{
708 0, 40738, 122216, 203693, 285170, 366648, 448125, 529603,
709 611080, 692557, 774035, 855852, 942009, 1033024, 1128971, 1229926,
710 1335959, 1447142, 1563542, 1685229, 1812268, 1944725, 2082664, 2226148,
711 2375238, 2529996, 2690481, 2856753, 3028870, 3206888, 3390865, 3580856,
712 3776916, 3979100, 4187460, 4402049, 4622919, 4850123, 5083710, 5323731,
713 5570236, 5823273, 6082892, 6349140, 6622065, 6901714, 7188133, 7481369,
714 7781466, 8088471, 8402427, 8723380, 9051372, 9386448, 9728650, 10078021,
715 10434603, 10798439, 11169569, 11548036, 11933879, 12327139, 12727857, 13136073,
716 13551826, 13975156, 14406100, 14844697, 15290987, 15745007, 16206795, 16676389,
717 17153826, 17639142, 18132374, 18633560, 19142734, 19659934, 20185196, 20718552,
718 21260042, 21809696, 22367554, 22933648, 23508010, 24090680, 24681686, 25281066,
719 25888850, 26505076, 27129772, 27762974, 28404716, 29055026, 29713942, 30381490,
720 31057708, 31742624, 32436272, 33138682, 33849884, 34569912, 35298800, 36036568,
721 36783260, 37538896, 38303512, 39077136, 39859796, 40651528, 41452360, 42262316,
722 43081432, 43909732, 44747252, 45594016, 46450052, 47315392, 48190064, 49074096,
723 49967516, 50870356, 51782636, 52704392, 53635648, 54576432, 55526772, 56486700,
724 57456236, 58435408, 59424248, 60422780, 61431036, 62449032, 63476804, 64514376,
725 65561776, 66619028, 67686160, 68763192, 69850160, 70947088, 72053992, 73170912,
726 74297864, 75434880, 76581976, 77739184, 78906536, 80084040, 81271736, 82469648,
727 83677792, 84896192, 86124888, 87363888, 88613232, 89872928, 91143016, 92423512,
728 93714432, 95015816, 96327688, 97650056, 98982952, 100326408, 101680440, 103045072,
729 104420320, 105806224, 107202800, 108610064, 110028048, 111456776, 112896264, 114346544,
730 115807632, 117279552, 118762328, 120255976, 121760536, 123276016, 124802440, 126339832,
731 127888216, 129447616, 131018048, 132599544, 134192112, 135795792, 137410592, 139036528,
732 140673648, 142321952, 143981456, 145652208, 147334208, 149027488, 150732064, 152447968,
733 154175200, 155913792, 157663776, 159425168, 161197984, 162982240, 164777968, 166585184,
734 168403904, 170234160, 172075968, 173929344, 175794320, 177670896, 179559120, 181458992,
735 183370528, 185293776, 187228736, 189175424, 191133888, 193104112, 195086128, 197079968,
736 199085648, 201103184, 203132592, 205173888, 207227120, 209292272, 211369392, 213458480,
737 215559568, 217672656, 219797792, 221934976, 224084240, 226245600, 228419056, 230604656,
738 232802400, 235012320, 237234432, 239468736, 241715280, 243974080, 246245120, 248528464,
739 250824112, 253132064, 255452368, 257785040, 260130080, 262487520, 264857376, 267239664,
740};
741
742static stbir_uint8 stbir__linear_to_srgb_uchar(float f)
743{
744 int x = (int) (f * (1 << 28)); // has headroom so you don't need to clamp
745 int v = 0;
746 int i;
747
748 // Refine the guess with a short binary search.
749 i = v + 128; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
750 i = v + 64; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
751 i = v + 32; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
752 i = v + 16; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
753 i = v + 8; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
754 i = v + 4; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
755 i = v + 2; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
756 i = v + 1; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
757
758 return (stbir_uint8) v;
759}
760#endif
761
762static float stbir__filter_trapezoid(float x, float scale)
763{
764 float halfscale = scale / 2;
765 float t = 0.5f + halfscale;
766 STBIR_ASSERT(scale <= 1);
767
768 x = (float)fabs(x);
769
770 if (x >= t)
771 return 0;
772 else
773 {
774 float r = 0.5f - halfscale;
775 if (x <= r)
776 return 1;
777 else
778 return (t - x) / scale;
779 }
780}
781
782static float stbir__support_trapezoid(float scale)
783{
784 STBIR_ASSERT(scale <= 1);
785 return 0.5f + scale / 2;
786}
787
788static float stbir__filter_triangle(float x, float s)
789{
790 STBIR__UNUSED_PARAM(s);
791
792 x = (float)fabs(x);
793
794 if (x <= 1.0f)
795 return 1 - x;
796 else
797 return 0;
798}
799
800static float stbir__filter_cubic(float x, float s)
801{
802 STBIR__UNUSED_PARAM(s);
803
804 x = (float)fabs(x);
805
806 if (x < 1.0f)
807 return (4 + x*x*(3*x - 6))/6;
808 else if (x < 2.0f)
809 return (8 + x*(-12 + x*(6 - x)))/6;
810
811 return (0.0f);
812}
813
814static float stbir__filter_catmullrom(float x, float s)
815{
816 STBIR__UNUSED_PARAM(s);
817
818 x = (float)fabs(x);
819
820 if (x < 1.0f)
821 return 1 - x*x*(2.5f - 1.5f*x);
822 else if (x < 2.0f)
823 return 2 - x*(4 + x*(0.5f*x - 2.5f));
824
825 return (0.0f);
826}
827
828static float stbir__filter_mitchell(float x, float s)
829{
830 STBIR__UNUSED_PARAM(s);
831
832 x = (float)fabs(x);
833
834 if (x < 1.0f)
835 return (16 + x*x*(21 * x - 36))/18;
836 else if (x < 2.0f)
837 return (32 + x*(-60 + x*(36 - 7*x)))/18;
838
839 return (0.0f);
840}
841
842static float stbir__support_zero(float s)
843{
844 STBIR__UNUSED_PARAM(s);
845 return 0;
846}
847
848static float stbir__support_one(float s)
849{
850 STBIR__UNUSED_PARAM(s);
851 return 1;
852}
853
854static float stbir__support_two(float s)
855{
856 STBIR__UNUSED_PARAM(s);
857 return 2;
858}
859
860static stbir__filter_info stbir__filter_info_table[] = {
861 { NULL, stbir__support_zero },
862 { stbir__filter_trapezoid, stbir__support_trapezoid },
863 { stbir__filter_triangle, stbir__support_one },
864 { stbir__filter_cubic, stbir__support_two },
865 { stbir__filter_catmullrom, stbir__support_two },
866 { stbir__filter_mitchell, stbir__support_two },
867};
868
869stbir__inline static int stbir__use_upsampling(float ratio)
870{
871 return ratio > 1;
872}
873
874stbir__inline static int stbir__use_width_upsampling(stbir__info* stbir_info)
875{
876 return stbir__use_upsampling(stbir_info->horizontal_scale);
877}
878
879stbir__inline static int stbir__use_height_upsampling(stbir__info* stbir_info)
880{
881 return stbir__use_upsampling(stbir_info->vertical_scale);
882}
883
884// This is the maximum number of input samples that can affect an output sample
885// with the given filter
886static int stbir__get_filter_pixel_width(stbir_filter filter, float scale)
887{
888 STBIR_ASSERT(filter != 0);
889 STBIR_ASSERT(filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
890
891 if (stbir__use_upsampling(scale))
892 return (int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2);
893 else
894 return (int)ceil(stbir__filter_info_table[filter].support(scale) * 2 / scale);
895}
896
897// This is how much to expand buffers to account for filters seeking outside
898// the image boundaries.
899static int stbir__get_filter_pixel_margin(stbir_filter filter, float scale)
900{
901 return stbir__get_filter_pixel_width(filter, scale) / 2;
902}
903
904static int stbir__get_coefficient_width(stbir_filter filter, float scale)
905{
906 if (stbir__use_upsampling(scale))
907 return (int)ceil(stbir__filter_info_table[filter].support(1 / scale) * 2);
908 else
909 return (int)ceil(stbir__filter_info_table[filter].support(scale) * 2);
910}
911
912static int stbir__get_contributors(float scale, stbir_filter filter, int input_size, int output_size)
913{
914 if (stbir__use_upsampling(scale))
915 return output_size;
916 else
917 return (input_size + stbir__get_filter_pixel_margin(filter, scale) * 2);
918}
919
920static int stbir__get_total_horizontal_coefficients(stbir__info* info)
921{
922 return info->horizontal_num_contributors
923 * stbir__get_coefficient_width (info->horizontal_filter, info->horizontal_scale);
924}
925
926static int stbir__get_total_vertical_coefficients(stbir__info* info)
927{
928 return info->vertical_num_contributors
929 * stbir__get_coefficient_width (info->vertical_filter, info->vertical_scale);
930}
931
932static stbir__contributors* stbir__get_contributor(stbir__contributors* contributors, int n)
933{
934 return &contributors[n];
935}
936
937// For perf reasons this code is duplicated in stbir__resample_horizontal_upsample/downsample,
938// if you change it here change it there too.
939static float* stbir__get_coefficient(float* coefficients, stbir_filter filter, float scale, int n, int c)
940{
941 int width = stbir__get_coefficient_width(filter, scale);
942 return &coefficients[width*n + c];
943}
944
945static int stbir__edge_wrap_slow(stbir_edge edge, int n, int max)
946{
947 switch (edge)
948 {
949 case STBIR_EDGE_ZERO:
950 return 0; // we'll decode the wrong pixel here, and then overwrite with 0s later
951
952 case STBIR_EDGE_CLAMP:
953 if (n < 0)
954 return 0;
955
956 if (n >= max)
957 return max - 1;
958
959 return n; // NOTREACHED
960
961 case STBIR_EDGE_REFLECT:
962 {
963 if (n < 0)
964 {
965 if (n < max)
966 return -n;
967 else
968 return max - 1;
969 }
970
971 if (n >= max)
972 {
973 int max2 = max * 2;
974 if (n >= max2)
975 return 0;
976 else
977 return max2 - n - 1;
978 }
979
980 return n; // NOTREACHED
981 }
982
983 case STBIR_EDGE_WRAP:
984 if (n >= 0)
985 return (n % max);
986 else
987 {
988 int m = (-n) % max;
989
990 if (m != 0)
991 m = max - m;
992
993 return (m);
994 }
995 // NOTREACHED
996
997 default:
998 STBIR_ASSERT(!"Unimplemented edge type");
999 return 0;
1000 }
1001}
1002
1003stbir__inline static int stbir__edge_wrap(stbir_edge edge, int n, int max)
1004{
1005 // avoid per-pixel switch
1006 if (n >= 0 && n < max)
1007 return n;
1008 return stbir__edge_wrap_slow(edge, n, max);
1009}
1010
1011// What input pixels contribute to this output pixel?
1012static void stbir__calculate_sample_range_upsample(int n, float out_filter_radius, float scale_ratio, float out_shift, int* in_first_pixel, int* in_last_pixel, float* in_center_of_out)
1013{
1014 float out_pixel_center = (float)n + 0.5f;
1015 float out_pixel_influence_lowerbound = out_pixel_center - out_filter_radius;
1016 float out_pixel_influence_upperbound = out_pixel_center + out_filter_radius;
1017
1018 float in_pixel_influence_lowerbound = (out_pixel_influence_lowerbound + out_shift) / scale_ratio;
1019 float in_pixel_influence_upperbound = (out_pixel_influence_upperbound + out_shift) / scale_ratio;
1020
1021 *in_center_of_out = (out_pixel_center + out_shift) / scale_ratio;
1022 *in_first_pixel = (int)(floor(in_pixel_influence_lowerbound + 0.5));
1023 *in_last_pixel = (int)(floor(in_pixel_influence_upperbound - 0.5));
1024}
1025
1026// What output pixels does this input pixel contribute to?
1027static void stbir__calculate_sample_range_downsample(int n, float in_pixels_radius, float scale_ratio, float out_shift, int* out_first_pixel, int* out_last_pixel, float* out_center_of_in)
1028{
1029 float in_pixel_center = (float)n + 0.5f;
1030 float in_pixel_influence_lowerbound = in_pixel_center - in_pixels_radius;
1031 float in_pixel_influence_upperbound = in_pixel_center + in_pixels_radius;
1032
1033 float out_pixel_influence_lowerbound = in_pixel_influence_lowerbound * scale_ratio - out_shift;
1034 float out_pixel_influence_upperbound = in_pixel_influence_upperbound * scale_ratio - out_shift;
1035
1036 *out_center_of_in = in_pixel_center * scale_ratio - out_shift;
1037 *out_first_pixel = (int)(floor(out_pixel_influence_lowerbound + 0.5));
1038 *out_last_pixel = (int)(floor(out_pixel_influence_upperbound - 0.5));
1039}
1040
1041static void stbir__calculate_coefficients_upsample(stbir_filter filter, float scale, int in_first_pixel, int in_last_pixel, float in_center_of_out, stbir__contributors* contributor, float* coefficient_group)
1042{
1043 int i;
1044 float total_filter = 0;
1045 float filter_scale;
1046
1047 STBIR_ASSERT(in_last_pixel - in_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical.
1048
1049 contributor->n0 = in_first_pixel;
1050 contributor->n1 = in_last_pixel;
1051
1052 STBIR_ASSERT(contributor->n1 >= contributor->n0);
1053
1054 for (i = 0; i <= in_last_pixel - in_first_pixel; i++)
1055 {
1056 float in_pixel_center = (float)(i + in_first_pixel) + 0.5f;
1057 coefficient_group[i] = stbir__filter_info_table[filter].kernel(in_center_of_out - in_pixel_center, 1 / scale);
1058
1059 // If the coefficient is zero, skip it. (Don't do the <0 check here, we want the influence of those outside pixels.)
1060 if (i == 0 && !coefficient_group[i])
1061 {
1062 contributor->n0 = ++in_first_pixel;
1063 i--;
1064 continue;
1065 }
1066
1067 total_filter += coefficient_group[i];
1068 }
1069
1070 // NOTE(fg): Not actually true in general, nor is there any reason to expect it should be.
1071 // It would be true in exact math but is at best approximately true in floating-point math,
1072 // and it would not make sense to try and put actual bounds on this here because it depends
1073 // on the image aspect ratio which can get pretty extreme.
1074 //STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(in_last_pixel + 1) + 0.5f - in_center_of_out, 1/scale) == 0);
1075
1076 STBIR_ASSERT(total_filter > 0.9);
1077 STBIR_ASSERT(total_filter < 1.1f); // Make sure it's not way off.
1078
1079 // Make sure the sum of all coefficients is 1.
1080 filter_scale = 1 / total_filter;
1081
1082 for (i = 0; i <= in_last_pixel - in_first_pixel; i++)
1083 coefficient_group[i] *= filter_scale;
1084
1085 for (i = in_last_pixel - in_first_pixel; i >= 0; i--)
1086 {
1087 if (coefficient_group[i])
1088 break;
1089
1090 // This line has no weight. We can skip it.
1091 contributor->n1 = contributor->n0 + i - 1;
1092 }
1093}
1094
1095static void stbir__calculate_coefficients_downsample(stbir_filter filter, float scale_ratio, int out_first_pixel, int out_last_pixel, float out_center_of_in, stbir__contributors* contributor, float* coefficient_group)
1096{
1097 int i;
1098
1099 STBIR_ASSERT(out_last_pixel - out_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(scale_ratio) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical.
1100
1101 contributor->n0 = out_first_pixel;
1102 contributor->n1 = out_last_pixel;
1103
1104 STBIR_ASSERT(contributor->n1 >= contributor->n0);
1105
1106 for (i = 0; i <= out_last_pixel - out_first_pixel; i++)
1107 {
1108 float out_pixel_center = (float)(i + out_first_pixel) + 0.5f;
1109 float x = out_pixel_center - out_center_of_in;
1110 coefficient_group[i] = stbir__filter_info_table[filter].kernel(x, scale_ratio) * scale_ratio;
1111 }
1112
1113 // NOTE(fg): Not actually true in general, nor is there any reason to expect it should be.
1114 // It would be true in exact math but is at best approximately true in floating-point math,
1115 // and it would not make sense to try and put actual bounds on this here because it depends
1116 // on the image aspect ratio which can get pretty extreme.
1117 //STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(out_last_pixel + 1) + 0.5f - out_center_of_in, scale_ratio) == 0);
1118
1119 for (i = out_last_pixel - out_first_pixel; i >= 0; i--)
1120 {
1121 if (coefficient_group[i])
1122 break;
1123
1124 // This line has no weight. We can skip it.
1125 contributor->n1 = contributor->n0 + i - 1;
1126 }
1127}
1128
1129static void stbir__normalize_downsample_coefficients(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, int input_size, int output_size)
1130{
1131 int num_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size);
1132 int num_coefficients = stbir__get_coefficient_width(filter, scale_ratio);
1133 int i, j;
1134 int skip;
1135
1136 for (i = 0; i < output_size; i++)
1137 {
1138 float scale;
1139 float total = 0;
1140
1141 for (j = 0; j < num_contributors; j++)
1142 {
1143 if (i >= contributors[j].n0 && i <= contributors[j].n1)
1144 {
1145 float coefficient = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0);
1146 total += coefficient;
1147 }
1148 else if (i < contributors[j].n0)
1149 break;
1150 }
1151
1152 STBIR_ASSERT(total > 0.9f);
1153 STBIR_ASSERT(total < 1.1f);
1154
1155 scale = 1 / total;
1156
1157 for (j = 0; j < num_contributors; j++)
1158 {
1159 if (i >= contributors[j].n0 && i <= contributors[j].n1)
1160 *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0) *= scale;
1161 else if (i < contributors[j].n0)
1162 break;
1163 }
1164 }
1165
1166 // Optimize: Skip zero coefficients and contributions outside of image bounds.
1167 // Do this after normalizing because normalization depends on the n0/n1 values.
1168 for (j = 0; j < num_contributors; j++)
1169 {
1170 int range, max, width;
1171
1172 skip = 0;
1173 while (*stbir__get_coefficient(coefficients, filter, scale_ratio, j, skip) == 0)
1174 skip++;
1175
1176 contributors[j].n0 += skip;
1177
1178 while (contributors[j].n0 < 0)
1179 {
1180 contributors[j].n0++;
1181 skip++;
1182 }
1183
1184 range = contributors[j].n1 - contributors[j].n0 + 1;
1185 max = stbir__min(num_coefficients, range);
1186
1187 width = stbir__get_coefficient_width(filter, scale_ratio);
1188 for (i = 0; i < max; i++)
1189 {
1190 if (i + skip >= width)
1191 break;
1192
1193 *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i) = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i + skip);
1194 }
1195
1196 continue;
1197 }
1198
1199 // Using min to avoid writing into invalid pixels.
1200 for (i = 0; i < num_contributors; i++)
1201 contributors[i].n1 = stbir__min(contributors[i].n1, output_size - 1);
1202}
1203
1204// Each scan line uses the same kernel values so we should calculate the kernel
1205// values once and then we can use them for every scan line.
1206static void stbir__calculate_filters(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, float shift, int input_size, int output_size)
1207{
1208 int n;
1209 int total_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size);
1210
1211 if (stbir__use_upsampling(scale_ratio))
1212 {
1213 float out_pixels_radius = stbir__filter_info_table[filter].support(1 / scale_ratio) * scale_ratio;
1214
1215 // Looping through out pixels
1216 for (n = 0; n < total_contributors; n++)
1217 {
1218 float in_center_of_out; // Center of the current out pixel in the in pixel space
1219 int in_first_pixel, in_last_pixel;
1220
1221 stbir__calculate_sample_range_upsample(n, out_pixels_radius, scale_ratio, shift, &in_first_pixel, &in_last_pixel, &in_center_of_out);
1222
1223 stbir__calculate_coefficients_upsample(filter, scale_ratio, in_first_pixel, in_last_pixel, in_center_of_out, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0));
1224 }
1225 }
1226 else
1227 {
1228 float in_pixels_radius = stbir__filter_info_table[filter].support(scale_ratio) / scale_ratio;
1229
1230 // Looping through in pixels
1231 for (n = 0; n < total_contributors; n++)
1232 {
1233 float out_center_of_in; // Center of the current out pixel in the in pixel space
1234 int out_first_pixel, out_last_pixel;
1235 int n_adjusted = n - stbir__get_filter_pixel_margin(filter, scale_ratio);
1236
1237 stbir__calculate_sample_range_downsample(n_adjusted, in_pixels_radius, scale_ratio, shift, &out_first_pixel, &out_last_pixel, &out_center_of_in);
1238
1239 stbir__calculate_coefficients_downsample(filter, scale_ratio, out_first_pixel, out_last_pixel, out_center_of_in, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0));
1240 }
1241
1242 stbir__normalize_downsample_coefficients(contributors, coefficients, filter, scale_ratio, input_size, output_size);
1243 }
1244}
1245
1246static float* stbir__get_decode_buffer(stbir__info* stbir_info)
1247{
1248 // The 0 index of the decode buffer starts after the margin. This makes
1249 // it okay to use negative indexes on the decode buffer.
1250 return &stbir_info->decode_buffer[stbir_info->horizontal_filter_pixel_margin * stbir_info->channels];
1251}
1252
1253#define STBIR__DECODE(type, colorspace) ((int)(type) * (STBIR_MAX_COLORSPACES) + (int)(colorspace))
1254
1255static void stbir__decode_scanline(stbir__info* stbir_info, int n)
1256{
1257 int c;
1258 int channels = stbir_info->channels;
1259 int alpha_channel = stbir_info->alpha_channel;
1260 int type = stbir_info->type;
1261 int colorspace = stbir_info->colorspace;
1262 int input_w = stbir_info->input_w;
1263 size_t input_stride_bytes = stbir_info->input_stride_bytes;
1264 float* decode_buffer = stbir__get_decode_buffer(stbir_info);
1265 stbir_edge edge_horizontal = stbir_info->edge_horizontal;
1266 stbir_edge edge_vertical = stbir_info->edge_vertical;
1267 size_t in_buffer_row_offset = stbir__edge_wrap(edge_vertical, n, stbir_info->input_h) * input_stride_bytes;
1268 const void* input_data = (char *) stbir_info->input_data + in_buffer_row_offset;
1269 int max_x = input_w + stbir_info->horizontal_filter_pixel_margin;
1270 int decode = STBIR__DECODE(type, colorspace);
1271
1272 int x = -stbir_info->horizontal_filter_pixel_margin;
1273
1274 // special handling for STBIR_EDGE_ZERO because it needs to return an item that doesn't appear in the input,
1275 // and we want to avoid paying overhead on every pixel if not STBIR_EDGE_ZERO
1276 if (edge_vertical == STBIR_EDGE_ZERO && (n < 0 || n >= stbir_info->input_h))
1277 {
1278 for (; x < max_x; x++)
1279 for (c = 0; c < channels; c++)
1280 decode_buffer[x*channels + c] = 0;
1281 return;
1282 }
1283
1284 switch (decode)
1285 {
1286 case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR):
1287 for (; x < max_x; x++)
1288 {
1289 int decode_pixel_index = x * channels;
1290 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1291 for (c = 0; c < channels; c++)
1292 decode_buffer[decode_pixel_index + c] = ((float)((const unsigned char*)input_data)[input_pixel_index + c]) / stbir__max_uint8_as_float;
1293 }
1294 break;
1295
1296 case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB):
1297 for (; x < max_x; x++)
1298 {
1299 int decode_pixel_index = x * channels;
1300 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1301 for (c = 0; c < channels; c++)
1302 decode_buffer[decode_pixel_index + c] = stbir__srgb_uchar_to_linear_float[((const unsigned char*)input_data)[input_pixel_index + c]];
1303
1304 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1305 decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned char*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint8_as_float;
1306 }
1307 break;
1308
1309 case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR):
1310 for (; x < max_x; x++)
1311 {
1312 int decode_pixel_index = x * channels;
1313 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1314 for (c = 0; c < channels; c++)
1315 decode_buffer[decode_pixel_index + c] = ((float)((const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float;
1316 }
1317 break;
1318
1319 case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB):
1320 for (; x < max_x; x++)
1321 {
1322 int decode_pixel_index = x * channels;
1323 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1324 for (c = 0; c < channels; c++)
1325 decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((float)((const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float);
1326
1327 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1328 decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned short*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint16_as_float;
1329 }
1330 break;
1331
1332 case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR):
1333 for (; x < max_x; x++)
1334 {
1335 int decode_pixel_index = x * channels;
1336 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1337 for (c = 0; c < channels; c++)
1338 decode_buffer[decode_pixel_index + c] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float);
1339 }
1340 break;
1341
1342 case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB):
1343 for (; x < max_x; x++)
1344 {
1345 int decode_pixel_index = x * channels;
1346 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1347 for (c = 0; c < channels; c++)
1348 decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear((float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float));
1349
1350 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1351 decode_buffer[decode_pixel_index + alpha_channel] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint32_as_float);
1352 }
1353 break;
1354
1355 case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR):
1356 for (; x < max_x; x++)
1357 {
1358 int decode_pixel_index = x * channels;
1359 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1360 for (c = 0; c < channels; c++)
1361 decode_buffer[decode_pixel_index + c] = ((const float*)input_data)[input_pixel_index + c];
1362 }
1363 break;
1364
1365 case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB):
1366 for (; x < max_x; x++)
1367 {
1368 int decode_pixel_index = x * channels;
1369 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1370 for (c = 0; c < channels; c++)
1371 decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((const float*)input_data)[input_pixel_index + c]);
1372
1373 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1374 decode_buffer[decode_pixel_index + alpha_channel] = ((const float*)input_data)[input_pixel_index + alpha_channel];
1375 }
1376
1377 break;
1378
1379 default:
1380 STBIR_ASSERT(!"Unknown type/colorspace/channels combination.");
1381 break;
1382 }
1383
1384 if (!(stbir_info->flags & STBIR_FLAG_ALPHA_PREMULTIPLIED))
1385 {
1386 for (x = -stbir_info->horizontal_filter_pixel_margin; x < max_x; x++)
1387 {
1388 int decode_pixel_index = x * channels;
1389
1390 // If the alpha value is 0 it will clobber the color values. Make sure it's not.
1391 float alpha = decode_buffer[decode_pixel_index + alpha_channel];
1392#ifndef STBIR_NO_ALPHA_EPSILON
1393 if (stbir_info->type != STBIR_TYPE_FLOAT) {
1394 alpha += STBIR_ALPHA_EPSILON;
1395 decode_buffer[decode_pixel_index + alpha_channel] = alpha;
1396 }
1397#endif
1398 for (c = 0; c < channels; c++)
1399 {
1400 if (c == alpha_channel)
1401 continue;
1402
1403 decode_buffer[decode_pixel_index + c] *= alpha;
1404 }
1405 }
1406 }
1407
1408 if (edge_horizontal == STBIR_EDGE_ZERO)
1409 {
1410 for (x = -stbir_info->horizontal_filter_pixel_margin; x < 0; x++)
1411 {
1412 for (c = 0; c < channels; c++)
1413 decode_buffer[x*channels + c] = 0;
1414 }
1415 for (x = input_w; x < max_x; x++)
1416 {
1417 for (c = 0; c < channels; c++)
1418 decode_buffer[x*channels + c] = 0;
1419 }
1420 }
1421}
1422
1423static float* stbir__get_ring_buffer_entry(float* ring_buffer, int index, int ring_buffer_length)
1424{
1425 return &ring_buffer[index * ring_buffer_length];
1426}
1427
1428static float* stbir__add_empty_ring_buffer_entry(stbir__info* stbir_info, int n)
1429{
1430 int ring_buffer_index;
1431 float* ring_buffer;
1432
1433 stbir_info->ring_buffer_last_scanline = n;
1434
1435 if (stbir_info->ring_buffer_begin_index < 0)
1436 {
1437 ring_buffer_index = stbir_info->ring_buffer_begin_index = 0;
1438 stbir_info->ring_buffer_first_scanline = n;
1439 }
1440 else
1441 {
1442 ring_buffer_index = (stbir_info->ring_buffer_begin_index + (stbir_info->ring_buffer_last_scanline - stbir_info->ring_buffer_first_scanline)) % stbir_info->ring_buffer_num_entries;
1443 STBIR_ASSERT(ring_buffer_index != stbir_info->ring_buffer_begin_index);
1444 }
1445
1446 ring_buffer = stbir__get_ring_buffer_entry(stbir_info->ring_buffer, ring_buffer_index, stbir_info->ring_buffer_length_bytes / sizeof(float));
1447 memset(ring_buffer, 0, stbir_info->ring_buffer_length_bytes);
1448
1449 return ring_buffer;
1450}
1451
1452
1453static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, float* output_buffer)
1454{
1455 int x, k;
1456 int output_w = stbir_info->output_w;
1457 int channels = stbir_info->channels;
1458 float* decode_buffer = stbir__get_decode_buffer(stbir_info);
1459 stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors;
1460 float* horizontal_coefficients = stbir_info->horizontal_coefficients;
1461 int coefficient_width = stbir_info->horizontal_coefficient_width;
1462
1463 for (x = 0; x < output_w; x++)
1464 {
1465 int n0 = horizontal_contributors[x].n0;
1466 int n1 = horizontal_contributors[x].n1;
1467
1468 int out_pixel_index = x * channels;
1469 int coefficient_group = coefficient_width * x;
1470 int coefficient_counter = 0;
1471
1472 STBIR_ASSERT(n1 >= n0);
1473 STBIR_ASSERT(n0 >= -stbir_info->horizontal_filter_pixel_margin);
1474 STBIR_ASSERT(n1 >= -stbir_info->horizontal_filter_pixel_margin);
1475 STBIR_ASSERT(n0 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin);
1476 STBIR_ASSERT(n1 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin);
1477
1478 switch (channels) {
1479 case 1:
1480 for (k = n0; k <= n1; k++)
1481 {
1482 int in_pixel_index = k * 1;
1483 float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
1484 STBIR_ASSERT(coefficient != 0);
1485 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1486 }
1487 break;
1488 case 2:
1489 for (k = n0; k <= n1; k++)
1490 {
1491 int in_pixel_index = k * 2;
1492 float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
1493 STBIR_ASSERT(coefficient != 0);
1494 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1495 output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1496 }
1497 break;
1498 case 3:
1499 for (k = n0; k <= n1; k++)
1500 {
1501 int in_pixel_index = k * 3;
1502 float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
1503 STBIR_ASSERT(coefficient != 0);
1504 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1505 output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1506 output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
1507 }
1508 break;
1509 case 4:
1510 for (k = n0; k <= n1; k++)
1511 {
1512 int in_pixel_index = k * 4;
1513 float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
1514 STBIR_ASSERT(coefficient != 0);
1515 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1516 output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1517 output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
1518 output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient;
1519 }
1520 break;
1521 default:
1522 for (k = n0; k <= n1; k++)
1523 {
1524 int in_pixel_index = k * channels;
1525 float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
1526 int c;
1527 STBIR_ASSERT(coefficient != 0);
1528 for (c = 0; c < channels; c++)
1529 output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient;
1530 }
1531 break;
1532 }
1533 }
1534}
1535
1536static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, float* output_buffer)
1537{
1538 int x, k;
1539 int input_w = stbir_info->input_w;
1540 int channels = stbir_info->channels;
1541 float* decode_buffer = stbir__get_decode_buffer(stbir_info);
1542 stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors;
1543 float* horizontal_coefficients = stbir_info->horizontal_coefficients;
1544 int coefficient_width = stbir_info->horizontal_coefficient_width;
1545 int filter_pixel_margin = stbir_info->horizontal_filter_pixel_margin;
1546 int max_x = input_w + filter_pixel_margin * 2;
1547
1548 STBIR_ASSERT(!stbir__use_width_upsampling(stbir_info));
1549
1550 switch (channels) {
1551 case 1:
1552 for (x = 0; x < max_x; x++)
1553 {
1554 int n0 = horizontal_contributors[x].n0;
1555 int n1 = horizontal_contributors[x].n1;
1556
1557 int in_x = x - filter_pixel_margin;
1558 int in_pixel_index = in_x * 1;
1559 int max_n = n1;
1560 int coefficient_group = coefficient_width * x;
1561
1562 for (k = n0; k <= max_n; k++)
1563 {
1564 int out_pixel_index = k * 1;
1565 float coefficient = horizontal_coefficients[coefficient_group + k - n0];
1566 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1567 }
1568 }
1569 break;
1570
1571 case 2:
1572 for (x = 0; x < max_x; x++)
1573 {
1574 int n0 = horizontal_contributors[x].n0;
1575 int n1 = horizontal_contributors[x].n1;
1576
1577 int in_x = x - filter_pixel_margin;
1578 int in_pixel_index = in_x * 2;
1579 int max_n = n1;
1580 int coefficient_group = coefficient_width * x;
1581
1582 for (k = n0; k <= max_n; k++)
1583 {
1584 int out_pixel_index = k * 2;
1585 float coefficient = horizontal_coefficients[coefficient_group + k - n0];
1586 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1587 output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1588 }
1589 }
1590 break;
1591
1592 case 3:
1593 for (x = 0; x < max_x; x++)
1594 {
1595 int n0 = horizontal_contributors[x].n0;
1596 int n1 = horizontal_contributors[x].n1;
1597
1598 int in_x = x - filter_pixel_margin;
1599 int in_pixel_index = in_x * 3;
1600 int max_n = n1;
1601 int coefficient_group = coefficient_width * x;
1602
1603 for (k = n0; k <= max_n; k++)
1604 {
1605 int out_pixel_index = k * 3;
1606 float coefficient = horizontal_coefficients[coefficient_group + k - n0];
1607 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1608 output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1609 output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
1610 }
1611 }
1612 break;
1613
1614 case 4:
1615 for (x = 0; x < max_x; x++)
1616 {
1617 int n0 = horizontal_contributors[x].n0;
1618 int n1 = horizontal_contributors[x].n1;
1619
1620 int in_x = x - filter_pixel_margin;
1621 int in_pixel_index = in_x * 4;
1622 int max_n = n1;
1623 int coefficient_group = coefficient_width * x;
1624
1625 for (k = n0; k <= max_n; k++)
1626 {
1627 int out_pixel_index = k * 4;
1628 float coefficient = horizontal_coefficients[coefficient_group + k - n0];
1629 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1630 output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1631 output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
1632 output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient;
1633 }
1634 }
1635 break;
1636
1637 default:
1638 for (x = 0; x < max_x; x++)
1639 {
1640 int n0 = horizontal_contributors[x].n0;
1641 int n1 = horizontal_contributors[x].n1;
1642
1643 int in_x = x - filter_pixel_margin;
1644 int in_pixel_index = in_x * channels;
1645 int max_n = n1;
1646 int coefficient_group = coefficient_width * x;
1647
1648 for (k = n0; k <= max_n; k++)
1649 {
1650 int c;
1651 int out_pixel_index = k * channels;
1652 float coefficient = horizontal_coefficients[coefficient_group + k - n0];
1653 for (c = 0; c < channels; c++)
1654 output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient;
1655 }
1656 }
1657 break;
1658 }
1659}
1660
1661static void stbir__decode_and_resample_upsample(stbir__info* stbir_info, int n)
1662{
1663 // Decode the nth scanline from the source image into the decode buffer.
1664 stbir__decode_scanline(stbir_info, n);
1665
1666 // Now resample it into the ring buffer.
1667 if (stbir__use_width_upsampling(stbir_info))
1668 stbir__resample_horizontal_upsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n));
1669 else
1670 stbir__resample_horizontal_downsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n));
1671
1672 // Now it's sitting in the ring buffer ready to be used as source for the vertical sampling.
1673}
1674
1675static void stbir__decode_and_resample_downsample(stbir__info* stbir_info, int n)
1676{
1677 // Decode the nth scanline from the source image into the decode buffer.
1678 stbir__decode_scanline(stbir_info, n);
1679
1680 memset(stbir_info->horizontal_buffer, 0, stbir_info->output_w * stbir_info->channels * sizeof(float));
1681
1682 // Now resample it into the horizontal buffer.
1683 if (stbir__use_width_upsampling(stbir_info))
1684 stbir__resample_horizontal_upsample(stbir_info, stbir_info->horizontal_buffer);
1685 else
1686 stbir__resample_horizontal_downsample(stbir_info, stbir_info->horizontal_buffer);
1687
1688 // Now it's sitting in the horizontal buffer ready to be distributed into the ring buffers.
1689}
1690
1691// Get the specified scan line from the ring buffer.
1692static float* stbir__get_ring_buffer_scanline(int get_scanline, float* ring_buffer, int begin_index, int first_scanline, int ring_buffer_num_entries, int ring_buffer_length)
1693{
1694 int ring_buffer_index = (begin_index + (get_scanline - first_scanline)) % ring_buffer_num_entries;
1695 return stbir__get_ring_buffer_entry(ring_buffer, ring_buffer_index, ring_buffer_length);
1696}
1697
1698
1699static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void *output_buffer, float *encode_buffer, int channels, int alpha_channel, int decode)
1700{
1701 int x;
1702 int n;
1703 int num_nonalpha;
1704 stbir_uint16 nonalpha[STBIR_MAX_CHANNELS];
1705
1706 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_PREMULTIPLIED))
1707 {
1708 for (x=0; x < num_pixels; ++x)
1709 {
1710 int pixel_index = x*channels;
1711
1712 float alpha = encode_buffer[pixel_index + alpha_channel];
1713 float reciprocal_alpha = alpha ? 1.0f / alpha : 0;
1714
1715 // unrolling this produced a 1% slowdown upscaling a large RGBA linear-space image on my machine - stb
1716 for (n = 0; n < channels; n++)
1717 if (n != alpha_channel)
1718 encode_buffer[pixel_index + n] *= reciprocal_alpha;
1719
1720 // We added in a small epsilon to prevent the color channel from being deleted with zero alpha.
1721 // Because we only add it for integer types, it will automatically be discarded on integer
1722 // conversion, so we don't need to subtract it back out (which would be problematic for
1723 // numeric precision reasons).
1724 }
1725 }
1726
1727 // build a table of all channels that need colorspace correction, so
1728 // we don't perform colorspace correction on channels that don't need it.
1729 for (x = 0, num_nonalpha = 0; x < channels; ++x)
1730 {
1731 if (x != alpha_channel || (stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE))
1732 {
1733 nonalpha[num_nonalpha++] = (stbir_uint16)x;
1734 }
1735 }
1736
1737 #define STBIR__ROUND_INT(f) ((int) ((f)+0.5))
1738 #define STBIR__ROUND_UINT(f) ((stbir_uint32) ((f)+0.5))
1739
1740 #ifdef STBIR__SATURATE_INT
1741 #define STBIR__ENCODE_LINEAR8(f) stbir__saturate8 (STBIR__ROUND_INT((f) * stbir__max_uint8_as_float ))
1742 #define STBIR__ENCODE_LINEAR16(f) stbir__saturate16(STBIR__ROUND_INT((f) * stbir__max_uint16_as_float))
1743 #else
1744 #define STBIR__ENCODE_LINEAR8(f) (unsigned char ) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint8_as_float )
1745 #define STBIR__ENCODE_LINEAR16(f) (unsigned short) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint16_as_float)
1746 #endif
1747
1748 switch (decode)
1749 {
1750 case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR):
1751 for (x=0; x < num_pixels; ++x)
1752 {
1753 int pixel_index = x*channels;
1754
1755 for (n = 0; n < channels; n++)
1756 {
1757 int index = pixel_index + n;
1758 ((unsigned char*)output_buffer)[index] = STBIR__ENCODE_LINEAR8(encode_buffer[index]);
1759 }
1760 }
1761 break;
1762
1763 case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB):
1764 for (x=0; x < num_pixels; ++x)
1765 {
1766 int pixel_index = x*channels;
1767
1768 for (n = 0; n < num_nonalpha; n++)
1769 {
1770 int index = pixel_index + nonalpha[n];
1771 ((unsigned char*)output_buffer)[index] = stbir__linear_to_srgb_uchar(encode_buffer[index]);
1772 }
1773
1774 if (!(stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE))
1775 ((unsigned char *)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR8(encode_buffer[pixel_index+alpha_channel]);
1776 }
1777 break;
1778
1779 case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR):
1780 for (x=0; x < num_pixels; ++x)
1781 {
1782 int pixel_index = x*channels;
1783
1784 for (n = 0; n < channels; n++)
1785 {
1786 int index = pixel_index + n;
1787 ((unsigned short*)output_buffer)[index] = STBIR__ENCODE_LINEAR16(encode_buffer[index]);
1788 }
1789 }
1790 break;
1791
1792 case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB):
1793 for (x=0; x < num_pixels; ++x)
1794 {
1795 int pixel_index = x*channels;
1796
1797 for (n = 0; n < num_nonalpha; n++)
1798 {
1799 int index = pixel_index + nonalpha[n];
1800 ((unsigned short*)output_buffer)[index] = (unsigned short)STBIR__ROUND_INT(stbir__linear_to_srgb(stbir__saturate(encode_buffer[index])) * stbir__max_uint16_as_float);
1801 }
1802
1803 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1804 ((unsigned short*)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR16(encode_buffer[pixel_index + alpha_channel]);
1805 }
1806
1807 break;
1808
1809 case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR):
1810 for (x=0; x < num_pixels; ++x)
1811 {
1812 int pixel_index = x*channels;
1813
1814 for (n = 0; n < channels; n++)
1815 {
1816 int index = pixel_index + n;
1817 ((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__saturate(encode_buffer[index])) * stbir__max_uint32_as_float);
1818 }
1819 }
1820 break;
1821
1822 case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB):
1823 for (x=0; x < num_pixels; ++x)
1824 {
1825 int pixel_index = x*channels;
1826
1827 for (n = 0; n < num_nonalpha; n++)
1828 {
1829 int index = pixel_index + nonalpha[n];
1830 ((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__linear_to_srgb(stbir__saturate(encode_buffer[index]))) * stbir__max_uint32_as_float);
1831 }
1832
1833 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1834 ((unsigned int*)output_buffer)[pixel_index + alpha_channel] = (unsigned int)STBIR__ROUND_INT(((double)stbir__saturate(encode_buffer[pixel_index + alpha_channel])) * stbir__max_uint32_as_float);
1835 }
1836 break;
1837
1838 case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR):
1839 for (x=0; x < num_pixels; ++x)
1840 {
1841 int pixel_index = x*channels;
1842
1843 for (n = 0; n < channels; n++)
1844 {
1845 int index = pixel_index + n;
1846 ((float*)output_buffer)[index] = encode_buffer[index];
1847 }
1848 }
1849 break;
1850
1851 case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB):
1852 for (x=0; x < num_pixels; ++x)
1853 {
1854 int pixel_index = x*channels;
1855
1856 for (n = 0; n < num_nonalpha; n++)
1857 {
1858 int index = pixel_index + nonalpha[n];
1859 ((float*)output_buffer)[index] = stbir__linear_to_srgb(encode_buffer[index]);
1860 }
1861
1862 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1863 ((float*)output_buffer)[pixel_index + alpha_channel] = encode_buffer[pixel_index + alpha_channel];
1864 }
1865 break;
1866
1867 default:
1868 STBIR_ASSERT(!"Unknown type/colorspace/channels combination.");
1869 break;
1870 }
1871}
1872
1873static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n)
1874{
1875 int x, k;
1876 int output_w = stbir_info->output_w;
1877 stbir__contributors* vertical_contributors = stbir_info->vertical_contributors;
1878 float* vertical_coefficients = stbir_info->vertical_coefficients;
1879 int channels = stbir_info->channels;
1880 int alpha_channel = stbir_info->alpha_channel;
1881 int type = stbir_info->type;
1882 int colorspace = stbir_info->colorspace;
1883 int ring_buffer_entries = stbir_info->ring_buffer_num_entries;
1884 void* output_data = stbir_info->output_data;
1885 float* encode_buffer = stbir_info->encode_buffer;
1886 int decode = STBIR__DECODE(type, colorspace);
1887 int coefficient_width = stbir_info->vertical_coefficient_width;
1888 int coefficient_counter;
1889 int contributor = n;
1890
1891 float* ring_buffer = stbir_info->ring_buffer;
1892 int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index;
1893 int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline;
1894 int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float);
1895
1896 int n0,n1, output_row_start;
1897 int coefficient_group = coefficient_width * contributor;
1898
1899 n0 = vertical_contributors[contributor].n0;
1900 n1 = vertical_contributors[contributor].n1;
1901
1902 output_row_start = n * stbir_info->output_stride_bytes;
1903
1904 STBIR_ASSERT(stbir__use_height_upsampling(stbir_info));
1905
1906 memset(encode_buffer, 0, output_w * sizeof(float) * channels);
1907
1908 // I tried reblocking this for better cache usage of encode_buffer
1909 // (using x_outer, k, x_inner), but it lost speed. -- stb
1910
1911 coefficient_counter = 0;
1912 switch (channels) {
1913 case 1:
1914 for (k = n0; k <= n1; k++)
1915 {
1916 int coefficient_index = coefficient_counter++;
1917 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
1918 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
1919 for (x = 0; x < output_w; ++x)
1920 {
1921 int in_pixel_index = x * 1;
1922 encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
1923 }
1924 }
1925 break;
1926 case 2:
1927 for (k = n0; k <= n1; k++)
1928 {
1929 int coefficient_index = coefficient_counter++;
1930 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
1931 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
1932 for (x = 0; x < output_w; ++x)
1933 {
1934 int in_pixel_index = x * 2;
1935 encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
1936 encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient;
1937 }
1938 }
1939 break;
1940 case 3:
1941 for (k = n0; k <= n1; k++)
1942 {
1943 int coefficient_index = coefficient_counter++;
1944 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
1945 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
1946 for (x = 0; x < output_w; ++x)
1947 {
1948 int in_pixel_index = x * 3;
1949 encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
1950 encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient;
1951 encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient;
1952 }
1953 }
1954 break;
1955 case 4:
1956 for (k = n0; k <= n1; k++)
1957 {
1958 int coefficient_index = coefficient_counter++;
1959 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
1960 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
1961 for (x = 0; x < output_w; ++x)
1962 {
1963 int in_pixel_index = x * 4;
1964 encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
1965 encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient;
1966 encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient;
1967 encode_buffer[in_pixel_index + 3] += ring_buffer_entry[in_pixel_index + 3] * coefficient;
1968 }
1969 }
1970 break;
1971 default:
1972 for (k = n0; k <= n1; k++)
1973 {
1974 int coefficient_index = coefficient_counter++;
1975 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
1976 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
1977 for (x = 0; x < output_w; ++x)
1978 {
1979 int in_pixel_index = x * channels;
1980 int c;
1981 for (c = 0; c < channels; c++)
1982 encode_buffer[in_pixel_index + c] += ring_buffer_entry[in_pixel_index + c] * coefficient;
1983 }
1984 }
1985 break;
1986 }
1987 stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, encode_buffer, channels, alpha_channel, decode);
1988}
1989
1990static void stbir__resample_vertical_downsample(stbir__info* stbir_info, int n)
1991{
1992 int x, k;
1993 int output_w = stbir_info->output_w;
1994 stbir__contributors* vertical_contributors = stbir_info->vertical_contributors;
1995 float* vertical_coefficients = stbir_info->vertical_coefficients;
1996 int channels = stbir_info->channels;
1997 int ring_buffer_entries = stbir_info->ring_buffer_num_entries;
1998 float* horizontal_buffer = stbir_info->horizontal_buffer;
1999 int coefficient_width = stbir_info->vertical_coefficient_width;
2000 int contributor = n + stbir_info->vertical_filter_pixel_margin;
2001
2002 float* ring_buffer = stbir_info->ring_buffer;
2003 int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index;
2004 int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline;
2005 int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float);
2006 int n0,n1;
2007
2008 n0 = vertical_contributors[contributor].n0;
2009 n1 = vertical_contributors[contributor].n1;
2010
2011 STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info));
2012
2013 for (k = n0; k <= n1; k++)
2014 {
2015 int coefficient_index = k - n0;
2016 int coefficient_group = coefficient_width * contributor;
2017 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
2018
2019 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
2020
2021 switch (channels) {
2022 case 1:
2023 for (x = 0; x < output_w; x++)
2024 {
2025 int in_pixel_index = x * 1;
2026 ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
2027 }
2028 break;
2029 case 2:
2030 for (x = 0; x < output_w; x++)
2031 {
2032 int in_pixel_index = x * 2;
2033 ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
2034 ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient;
2035 }
2036 break;
2037 case 3:
2038 for (x = 0; x < output_w; x++)
2039 {
2040 int in_pixel_index = x * 3;
2041 ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
2042 ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient;
2043 ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient;
2044 }
2045 break;
2046 case 4:
2047 for (x = 0; x < output_w; x++)
2048 {
2049 int in_pixel_index = x * 4;
2050 ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
2051 ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient;
2052 ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient;
2053 ring_buffer_entry[in_pixel_index + 3] += horizontal_buffer[in_pixel_index + 3] * coefficient;
2054 }
2055 break;
2056 default:
2057 for (x = 0; x < output_w; x++)
2058 {
2059 int in_pixel_index = x * channels;
2060
2061 int c;
2062 for (c = 0; c < channels; c++)
2063 ring_buffer_entry[in_pixel_index + c] += horizontal_buffer[in_pixel_index + c] * coefficient;
2064 }
2065 break;
2066 }
2067 }
2068}
2069
2070static void stbir__buffer_loop_upsample(stbir__info* stbir_info)
2071{
2072 int y;
2073 float scale_ratio = stbir_info->vertical_scale;
2074 float out_scanlines_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(1/scale_ratio) * scale_ratio;
2075
2076 STBIR_ASSERT(stbir__use_height_upsampling(stbir_info));
2077
2078 for (y = 0; y < stbir_info->output_h; y++)
2079 {
2080 float in_center_of_out = 0; // Center of the current out scanline in the in scanline space
2081 int in_first_scanline = 0, in_last_scanline = 0;
2082
2083 stbir__calculate_sample_range_upsample(y, out_scanlines_radius, scale_ratio, stbir_info->vertical_shift, &in_first_scanline, &in_last_scanline, &in_center_of_out);
2084
2085 STBIR_ASSERT(in_last_scanline - in_first_scanline + 1 <= stbir_info->ring_buffer_num_entries);
2086
2087 if (stbir_info->ring_buffer_begin_index >= 0)
2088 {
2089 // Get rid of whatever we don't need anymore.
2090 while (in_first_scanline > stbir_info->ring_buffer_first_scanline)
2091 {
2092 if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline)
2093 {
2094 // We just popped the last scanline off the ring buffer.
2095 // Reset it to the empty state.
2096 stbir_info->ring_buffer_begin_index = -1;
2097 stbir_info->ring_buffer_first_scanline = 0;
2098 stbir_info->ring_buffer_last_scanline = 0;
2099 break;
2100 }
2101 else
2102 {
2103 stbir_info->ring_buffer_first_scanline++;
2104 stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries;
2105 }
2106 }
2107 }
2108
2109 // Load in new ones.
2110 if (stbir_info->ring_buffer_begin_index < 0)
2111 stbir__decode_and_resample_upsample(stbir_info, in_first_scanline);
2112
2113 while (in_last_scanline > stbir_info->ring_buffer_last_scanline)
2114 stbir__decode_and_resample_upsample(stbir_info, stbir_info->ring_buffer_last_scanline + 1);
2115
2116 // Now all buffers should be ready to write a row of vertical sampling.
2117 stbir__resample_vertical_upsample(stbir_info, y);
2118
2119 STBIR_PROGRESS_REPORT((float)y / stbir_info->output_h);
2120 }
2121}
2122
2123static void stbir__empty_ring_buffer(stbir__info* stbir_info, int first_necessary_scanline)
2124{
2125 int output_stride_bytes = stbir_info->output_stride_bytes;
2126 int channels = stbir_info->channels;
2127 int alpha_channel = stbir_info->alpha_channel;
2128 int type = stbir_info->type;
2129 int colorspace = stbir_info->colorspace;
2130 int output_w = stbir_info->output_w;
2131 void* output_data = stbir_info->output_data;
2132 int decode = STBIR__DECODE(type, colorspace);
2133
2134 float* ring_buffer = stbir_info->ring_buffer;
2135 int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float);
2136
2137 if (stbir_info->ring_buffer_begin_index >= 0)
2138 {
2139 // Get rid of whatever we don't need anymore.
2140 while (first_necessary_scanline > stbir_info->ring_buffer_first_scanline)
2141 {
2142 if (stbir_info->ring_buffer_first_scanline >= 0 && stbir_info->ring_buffer_first_scanline < stbir_info->output_h)
2143 {
2144 int output_row_start = stbir_info->ring_buffer_first_scanline * output_stride_bytes;
2145 float* ring_buffer_entry = stbir__get_ring_buffer_entry(ring_buffer, stbir_info->ring_buffer_begin_index, ring_buffer_length);
2146 stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, ring_buffer_entry, channels, alpha_channel, decode);
2147 STBIR_PROGRESS_REPORT((float)stbir_info->ring_buffer_first_scanline / stbir_info->output_h);
2148 }
2149
2150 if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline)
2151 {
2152 // We just popped the last scanline off the ring buffer.
2153 // Reset it to the empty state.
2154 stbir_info->ring_buffer_begin_index = -1;
2155 stbir_info->ring_buffer_first_scanline = 0;
2156 stbir_info->ring_buffer_last_scanline = 0;
2157 break;
2158 }
2159 else
2160 {
2161 stbir_info->ring_buffer_first_scanline++;
2162 stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries;
2163 }
2164 }
2165 }
2166}
2167
2168static void stbir__buffer_loop_downsample(stbir__info* stbir_info)
2169{
2170 int y;
2171 float scale_ratio = stbir_info->vertical_scale;
2172 int output_h = stbir_info->output_h;
2173 float in_pixels_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(scale_ratio) / scale_ratio;
2174 int pixel_margin = stbir_info->vertical_filter_pixel_margin;
2175 int max_y = stbir_info->input_h + pixel_margin;
2176
2177 STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info));
2178
2179 for (y = -pixel_margin; y < max_y; y++)
2180 {
2181 float out_center_of_in; // Center of the current out scanline in the in scanline space
2182 int out_first_scanline, out_last_scanline;
2183
2184 stbir__calculate_sample_range_downsample(y, in_pixels_radius, scale_ratio, stbir_info->vertical_shift, &out_first_scanline, &out_last_scanline, &out_center_of_in);
2185
2186 STBIR_ASSERT(out_last_scanline - out_first_scanline + 1 <= stbir_info->ring_buffer_num_entries);
2187
2188 if (out_last_scanline < 0 || out_first_scanline >= output_h)
2189 continue;
2190
2191 stbir__empty_ring_buffer(stbir_info, out_first_scanline);
2192
2193 stbir__decode_and_resample_downsample(stbir_info, y);
2194
2195 // Load in new ones.
2196 if (stbir_info->ring_buffer_begin_index < 0)
2197 stbir__add_empty_ring_buffer_entry(stbir_info, out_first_scanline);
2198
2199 while (out_last_scanline > stbir_info->ring_buffer_last_scanline)
2200 stbir__add_empty_ring_buffer_entry(stbir_info, stbir_info->ring_buffer_last_scanline + 1);
2201
2202 // Now the horizontal buffer is ready to write to all ring buffer rows.
2203 stbir__resample_vertical_downsample(stbir_info, y);
2204 }
2205
2206 stbir__empty_ring_buffer(stbir_info, stbir_info->output_h);
2207}
2208
2209static void stbir__setup(stbir__info *info, int input_w, int input_h, int output_w, int output_h, int channels)
2210{
2211 info->input_w = input_w;
2212 info->input_h = input_h;
2213 info->output_w = output_w;
2214 info->output_h = output_h;
2215 info->channels = channels;
2216}
2217
2218static void stbir__calculate_transform(stbir__info *info, float s0, float t0, float s1, float t1, float *transform)
2219{
2220 info->s0 = s0;
2221 info->t0 = t0;
2222 info->s1 = s1;
2223 info->t1 = t1;
2224
2225 if (transform)
2226 {
2227 info->horizontal_scale = transform[0];
2228 info->vertical_scale = transform[1];
2229 info->horizontal_shift = transform[2];
2230 info->vertical_shift = transform[3];
2231 }
2232 else
2233 {
2234 info->horizontal_scale = ((float)info->output_w / info->input_w) / (s1 - s0);
2235 info->vertical_scale = ((float)info->output_h / info->input_h) / (t1 - t0);
2236
2237 info->horizontal_shift = s0 * info->output_w / (s1 - s0);
2238 info->vertical_shift = t0 * info->output_h / (t1 - t0);
2239 }
2240}
2241
2242static void stbir__choose_filter(stbir__info *info, stbir_filter h_filter, stbir_filter v_filter)
2243{
2244 if (h_filter == 0)
2245 h_filter = stbir__use_upsampling(info->horizontal_scale) ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE;
2246 if (v_filter == 0)
2247 v_filter = stbir__use_upsampling(info->vertical_scale) ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE;
2248 info->horizontal_filter = h_filter;
2249 info->vertical_filter = v_filter;
2250}
2251
2252static stbir_uint32 stbir__calculate_memory(stbir__info *info)
2253{
2254 int pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale);
2255 int filter_height = stbir__get_filter_pixel_width(info->vertical_filter, info->vertical_scale);
2256
2257 info->horizontal_num_contributors = stbir__get_contributors(info->horizontal_scale, info->horizontal_filter, info->input_w, info->output_w);
2258 info->vertical_num_contributors = stbir__get_contributors(info->vertical_scale , info->vertical_filter , info->input_h, info->output_h);
2259
2260 // One extra entry because floating point precision problems sometimes cause an extra to be necessary.
2261 info->ring_buffer_num_entries = filter_height + 1;
2262
2263 info->horizontal_contributors_size = info->horizontal_num_contributors * sizeof(stbir__contributors);
2264 info->horizontal_coefficients_size = stbir__get_total_horizontal_coefficients(info) * sizeof(float);
2265 info->vertical_contributors_size = info->vertical_num_contributors * sizeof(stbir__contributors);
2266 info->vertical_coefficients_size = stbir__get_total_vertical_coefficients(info) * sizeof(float);
2267 info->decode_buffer_size = (info->input_w + pixel_margin * 2) * info->channels * sizeof(float);
2268 info->horizontal_buffer_size = info->output_w * info->channels * sizeof(float);
2269 info->ring_buffer_size = info->output_w * info->channels * info->ring_buffer_num_entries * sizeof(float);
2270 info->encode_buffer_size = info->output_w * info->channels * sizeof(float);
2271
2272 STBIR_ASSERT(info->horizontal_filter != 0);
2273 STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); // this now happens too late
2274 STBIR_ASSERT(info->vertical_filter != 0);
2275 STBIR_ASSERT(info->vertical_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); // this now happens too late
2276
2277 if (stbir__use_height_upsampling(info))
2278 // The horizontal buffer is for when we're downsampling the height and we
2279 // can't output the result of sampling the decode buffer directly into the
2280 // ring buffers.
2281 info->horizontal_buffer_size = 0;
2282 else
2283 // The encode buffer is to retain precision in the height upsampling method
2284 // and isn't used when height downsampling.
2285 info->encode_buffer_size = 0;
2286
2287 return info->horizontal_contributors_size + info->horizontal_coefficients_size
2288 + info->vertical_contributors_size + info->vertical_coefficients_size
2289 + info->decode_buffer_size + info->horizontal_buffer_size
2290 + info->ring_buffer_size + info->encode_buffer_size;
2291}
2292
2293static int stbir__resize_allocated(stbir__info *info,
2294 const void* input_data, int input_stride_in_bytes,
2295 void* output_data, int output_stride_in_bytes,
2296 int alpha_channel, stbir_uint32 flags, stbir_datatype type,
2297 stbir_edge edge_horizontal, stbir_edge edge_vertical, stbir_colorspace colorspace,
2298 void* tempmem, size_t tempmem_size_in_bytes)
2299{
2300 size_t memory_required = stbir__calculate_memory(info);
2301
2302 int width_stride_input = input_stride_in_bytes ? input_stride_in_bytes : info->channels * info->input_w * stbir__type_size[type];
2303 int width_stride_output = output_stride_in_bytes ? output_stride_in_bytes : info->channels * info->output_w * stbir__type_size[type];
2304
2305#ifdef STBIR_DEBUG_OVERWRITE_TEST
2306#define OVERWRITE_ARRAY_SIZE 8
2307 unsigned char overwrite_output_before_pre[OVERWRITE_ARRAY_SIZE];
2308 unsigned char overwrite_tempmem_before_pre[OVERWRITE_ARRAY_SIZE];
2309 unsigned char overwrite_output_after_pre[OVERWRITE_ARRAY_SIZE];
2310 unsigned char overwrite_tempmem_after_pre[OVERWRITE_ARRAY_SIZE];
2311
2312 size_t begin_forbidden = width_stride_output * (info->output_h - 1) + info->output_w * info->channels * stbir__type_size[type];
2313 memcpy(overwrite_output_before_pre, &((unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE);
2314 memcpy(overwrite_output_after_pre, &((unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE);
2315 memcpy(overwrite_tempmem_before_pre, &((unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE);
2316 memcpy(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE);
2317#endif
2318
2319 STBIR_ASSERT(info->channels >= 0);
2320 STBIR_ASSERT(info->channels <= STBIR_MAX_CHANNELS);
2321
2322 if (info->channels < 0 || info->channels > STBIR_MAX_CHANNELS)
2323 return 0;
2324
2325 STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
2326 STBIR_ASSERT(info->vertical_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
2327
2328 if (info->horizontal_filter >= STBIR__ARRAY_SIZE(stbir__filter_info_table))
2329 return 0;
2330 if (info->vertical_filter >= STBIR__ARRAY_SIZE(stbir__filter_info_table))
2331 return 0;
2332
2333 if (alpha_channel < 0)
2334 flags |= STBIR_FLAG_ALPHA_USES_COLORSPACE | STBIR_FLAG_ALPHA_PREMULTIPLIED;
2335
2336 if (!(flags&STBIR_FLAG_ALPHA_USES_COLORSPACE) || !(flags&STBIR_FLAG_ALPHA_PREMULTIPLIED)) {
2337 STBIR_ASSERT(alpha_channel >= 0 && alpha_channel < info->channels);
2338 }
2339
2340 if (alpha_channel >= info->channels)
2341 return 0;
2342
2343 STBIR_ASSERT(tempmem);
2344
2345 if (!tempmem)
2346 return 0;
2347
2348 STBIR_ASSERT(tempmem_size_in_bytes >= memory_required);
2349
2350 if (tempmem_size_in_bytes < memory_required)
2351 return 0;
2352
2353 memset(tempmem, 0, tempmem_size_in_bytes);
2354
2355 info->input_data = input_data;
2356 info->input_stride_bytes = width_stride_input;
2357
2358 info->output_data = output_data;
2359 info->output_stride_bytes = width_stride_output;
2360
2361 info->alpha_channel = alpha_channel;
2362 info->flags = flags;
2363 info->type = type;
2364 info->edge_horizontal = edge_horizontal;
2365 info->edge_vertical = edge_vertical;
2366 info->colorspace = colorspace;
2367
2368 info->horizontal_coefficient_width = stbir__get_coefficient_width (info->horizontal_filter, info->horizontal_scale);
2369 info->vertical_coefficient_width = stbir__get_coefficient_width (info->vertical_filter , info->vertical_scale );
2370 info->horizontal_filter_pixel_width = stbir__get_filter_pixel_width (info->horizontal_filter, info->horizontal_scale);
2371 info->vertical_filter_pixel_width = stbir__get_filter_pixel_width (info->vertical_filter , info->vertical_scale );
2372 info->horizontal_filter_pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale);
2373 info->vertical_filter_pixel_margin = stbir__get_filter_pixel_margin(info->vertical_filter , info->vertical_scale );
2374
2375 info->ring_buffer_length_bytes = info->output_w * info->channels * sizeof(float);
2376 info->decode_buffer_pixels = info->input_w + info->horizontal_filter_pixel_margin * 2;
2377
2378#define STBIR__NEXT_MEMPTR(current, newtype) (newtype*)(((unsigned char*)current) + current##_size)
2379
2380 info->horizontal_contributors = (stbir__contributors *) tempmem;
2381 info->horizontal_coefficients = STBIR__NEXT_MEMPTR(info->horizontal_contributors, float);
2382 info->vertical_contributors = STBIR__NEXT_MEMPTR(info->horizontal_coefficients, stbir__contributors);
2383 info->vertical_coefficients = STBIR__NEXT_MEMPTR(info->vertical_contributors, float);
2384 info->decode_buffer = STBIR__NEXT_MEMPTR(info->vertical_coefficients, float);
2385
2386 if (stbir__use_height_upsampling(info))
2387 {
2388 info->horizontal_buffer = NULL;
2389 info->ring_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer, float);
2390 info->encode_buffer = STBIR__NEXT_MEMPTR(info->ring_buffer, float);
2391
2392 STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->encode_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes);
2393 }
2394 else
2395 {
2396 info->horizontal_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer, float);
2397 info->ring_buffer = STBIR__NEXT_MEMPTR(info->horizontal_buffer, float);
2398 info->encode_buffer = NULL;
2399
2400 STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->ring_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes);
2401 }
2402
2403#undef STBIR__NEXT_MEMPTR
2404
2405 // This signals that the ring buffer is empty
2406 info->ring_buffer_begin_index = -1;
2407
2408 stbir__calculate_filters(info->horizontal_contributors, info->horizontal_coefficients, info->horizontal_filter, info->horizontal_scale, info->horizontal_shift, info->input_w, info->output_w);
2409 stbir__calculate_filters(info->vertical_contributors, info->vertical_coefficients, info->vertical_filter, info->vertical_scale, info->vertical_shift, info->input_h, info->output_h);
2410
2411 STBIR_PROGRESS_REPORT(0);
2412
2413 if (stbir__use_height_upsampling(info))
2414 stbir__buffer_loop_upsample(info);
2415 else
2416 stbir__buffer_loop_downsample(info);
2417
2418 STBIR_PROGRESS_REPORT(1);
2419
2420#ifdef STBIR_DEBUG_OVERWRITE_TEST
2421 STBIR_ASSERT(memcmp(overwrite_output_before_pre, &((unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0);
2422 STBIR_ASSERT(memcmp(overwrite_output_after_pre, &((unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE) == 0);
2423 STBIR_ASSERT(memcmp(overwrite_tempmem_before_pre, &((unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0);
2424 STBIR_ASSERT(memcmp(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE) == 0);
2425#endif
2426
2427 return 1;
2428}
2429
2430
2431static int stbir__resize_arbitrary(
2432 void *alloc_context,
2433 const void* input_data, int input_w, int input_h, int input_stride_in_bytes,
2434 void* output_data, int output_w, int output_h, int output_stride_in_bytes,
2435 float s0, float t0, float s1, float t1, float *transform,
2436 int channels, int alpha_channel, stbir_uint32 flags, stbir_datatype type,
2437 stbir_filter h_filter, stbir_filter v_filter,
2438 stbir_edge edge_horizontal, stbir_edge edge_vertical, stbir_colorspace colorspace)
2439{
2440 stbir__info info;
2441 int result;
2442 size_t memory_required;
2443 void* extra_memory;
2444
2445 stbir__setup(&info, input_w, input_h, output_w, output_h, channels);
2446 stbir__calculate_transform(&info, s0,t0,s1,t1,transform);
2447 stbir__choose_filter(&info, h_filter, v_filter);
2448 memory_required = stbir__calculate_memory(&info);
2449 extra_memory = STBIR_MALLOC(memory_required, alloc_context);
2450
2451 if (!extra_memory)
2452 return 0;
2453
2454 result = stbir__resize_allocated(&info, input_data, input_stride_in_bytes,
2455 output_data, output_stride_in_bytes,
2456 alpha_channel, flags, type,
2457 edge_horizontal, edge_vertical,
2458 colorspace, extra_memory, memory_required);
2459
2460 STBIR_FREE(extra_memory, alloc_context);
2461
2462 return result;
2463}
2464
2465STBIRDEF int stbir_resize_uint8( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
2466 unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
2467 int num_channels)
2468{
2469 return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
2470 output_pixels, output_w, output_h, output_stride_in_bytes,
2471 0,0,1,1,NULL,num_channels,-1,0, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
2472 STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR);
2473}
2474
2475STBIRDEF int stbir_resize_float( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
2476 float *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
2477 int num_channels)
2478{
2479 return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
2480 output_pixels, output_w, output_h, output_stride_in_bytes,
2481 0,0,1,1,NULL,num_channels,-1,0, STBIR_TYPE_FLOAT, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
2482 STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR);
2483}
2484
2485STBIRDEF int stbir_resize_uint8_srgb(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
2486 unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
2487 int num_channels, int alpha_channel, int flags)
2488{
2489 return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
2490 output_pixels, output_w, output_h, output_stride_in_bytes,
2491 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
2492 STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB);
2493}
2494
2495STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
2496 unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
2497 int num_channels, int alpha_channel, int flags,
2498 stbir_edge edge_wrap_mode)
2499{
2500 return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
2501 output_pixels, output_w, output_h, output_stride_in_bytes,
2502 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
2503 edge_wrap_mode, edge_wrap_mode, STBIR_COLORSPACE_SRGB);
2504}
2505
2506STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
2507 unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
2508 int num_channels, int alpha_channel, int flags,
2509 stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
2510 void *alloc_context)
2511{
2512 return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
2513 output_pixels, output_w, output_h, output_stride_in_bytes,
2514 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, filter, filter,
2515 edge_wrap_mode, edge_wrap_mode, space);
2516}
2517
2518STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
2519 stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
2520 int num_channels, int alpha_channel, int flags,
2521 stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
2522 void *alloc_context)
2523{
2524 return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
2525 output_pixels, output_w, output_h, output_stride_in_bytes,
2526 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT16, filter, filter,
2527 edge_wrap_mode, edge_wrap_mode, space);
2528}
2529
2530
2531STBIRDEF int stbir_resize_float_generic( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
2532 float *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
2533 int num_channels, int alpha_channel, int flags,
2534 stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
2535 void *alloc_context)
2536{
2537 return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
2538 output_pixels, output_w, output_h, output_stride_in_bytes,
2539 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_FLOAT, filter, filter,
2540 edge_wrap_mode, edge_wrap_mode, space);
2541}
2542
2543
2544STBIRDEF int stbir_resize( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
2545 void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
2546 stbir_datatype datatype,
2547 int num_channels, int alpha_channel, int flags,
2548 stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
2549 stbir_filter filter_horizontal, stbir_filter filter_vertical,
2550 stbir_colorspace space, void *alloc_context)
2551{
2552 return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
2553 output_pixels, output_w, output_h, output_stride_in_bytes,
2554 0,0,1,1,NULL,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical,
2555 edge_mode_horizontal, edge_mode_vertical, space);
2556}
2557
2558
2559STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
2560 void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
2561 stbir_datatype datatype,
2562 int num_channels, int alpha_channel, int flags,
2563 stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
2564 stbir_filter filter_horizontal, stbir_filter filter_vertical,
2565 stbir_colorspace space, void *alloc_context,
2566 float x_scale, float y_scale,
2567 float x_offset, float y_offset)
2568{
2569 float transform[4];
2570 transform[0] = x_scale;
2571 transform[1] = y_scale;
2572 transform[2] = x_offset;
2573 transform[3] = y_offset;
2574 return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
2575 output_pixels, output_w, output_h, output_stride_in_bytes,
2576 0,0,1,1,transform,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical,
2577 edge_mode_horizontal, edge_mode_vertical, space);
2578}
2579
2580STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
2581 void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
2582 stbir_datatype datatype,
2583 int num_channels, int alpha_channel, int flags,
2584 stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
2585 stbir_filter filter_horizontal, stbir_filter filter_vertical,
2586 stbir_colorspace space, void *alloc_context,
2587 float s0, float t0, float s1, float t1)
2588{
2589 return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
2590 output_pixels, output_w, output_h, output_stride_in_bytes,
2591 s0,t0,s1,t1,NULL,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical,
2592 edge_mode_horizontal, edge_mode_vertical, space);
2593}
2594
2595#endif // STB_IMAGE_RESIZE_IMPLEMENTATION
2596
2597/* 386/*
2598------------------------------------------------------------------------------ 387------------------------------------------------------------------------------
2599This software is available under 2 licenses -- choose whichever you prefer. 388This software is available under 2 licenses -- choose whichever you prefer.