mirror of
https://github.com/eddyem/improclib.git
synced 2025-12-06 02:35:15 +03:00
convert for usage with libusefull_macros v0.3.2
This commit is contained in:
parent
34de5183c9
commit
97a0366582
@ -1,6 +1,6 @@
|
|||||||
cmake_minimum_required(VERSION 3.20)
|
cmake_minimum_required(VERSION 3.20)
|
||||||
set(PROJ improc)
|
set(PROJ improc)
|
||||||
set(MINOR_VERSION "1")
|
set(MINOR_VERSION "2")
|
||||||
set(MID_VERSION "0")
|
set(MID_VERSION "0")
|
||||||
set(MAJOR_VERSION "0")
|
set(MAJOR_VERSION "0")
|
||||||
set(VERSION "${MAJOR_VERSION}.${MID_VERSION}.${MINOR_VERSION}")
|
set(VERSION "${MAJOR_VERSION}.${MID_VERSION}.${MINOR_VERSION}")
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h> // memcpy
|
#include <string.h> // memcpy
|
||||||
|
|||||||
@ -21,6 +21,7 @@
|
|||||||
#include <usefull_macros.h>
|
#include <usefull_macros.h>
|
||||||
|
|
||||||
int main(int argc, char **argv){
|
int main(int argc, char **argv){
|
||||||
|
sl_init();
|
||||||
if(argc != 2){
|
if(argc != 2){
|
||||||
fprintf(stderr, "Usage: %s filename - open bw image file, equalize histogram, plot two crosses ans save as output.jpg\n", argv[0]);
|
fprintf(stderr, "Usage: %s filename - open bw image file, equalize histogram, plot two crosses ans save as output.jpg\n", argv[0]);
|
||||||
return 1;
|
return 1;
|
||||||
@ -31,9 +32,9 @@ int main(int argc, char **argv){
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
int w = I->width, h = I->height;
|
int w = I->width, h = I->height;
|
||||||
double t0 = dtime();
|
double t0 = sl_dtime();
|
||||||
uint8_t *eq = il_equalize8(I, 3, 0.1);
|
uint8_t *eq = il_equalize8(I, 3, 0.1);
|
||||||
green("Equalize: %g ms\n", (dtime() - t0)*1e3);
|
green("Equalize: %g ms\n", (sl_dtime() - t0)*1e3);
|
||||||
il_Image_free(&I);
|
il_Image_free(&I);
|
||||||
if(!eq) return 3;
|
if(!eq) return 3;
|
||||||
il_Img3 *I3 = MALLOC(il_Img3, 1);
|
il_Img3 *I3 = MALLOC(il_Img3, 1);
|
||||||
|
|||||||
@ -24,7 +24,7 @@ static int help = 0, w = 1024, h = 1024, Niter = 1000000;
|
|||||||
static double xsigma = 10., ysigma = 10., x0 = 512., y0 = 512.;
|
static double xsigma = 10., ysigma = 10., x0 = 512., y0 = 512.;
|
||||||
static char *outp = "output.png";
|
static char *outp = "output.png";
|
||||||
|
|
||||||
static myoption cmdlnopts[] = {
|
static sl_option_t cmdlnopts[] = {
|
||||||
{"help", NO_ARGS, NULL, '?', arg_int, APTR(&help), "show this help"},
|
{"help", NO_ARGS, NULL, '?', arg_int, APTR(&help), "show this help"},
|
||||||
{"width", NEED_ARG, NULL, 'w', arg_int, APTR(&w), "resulting image width (default: 1024)"},
|
{"width", NEED_ARG, NULL, 'w', arg_int, APTR(&w), "resulting image width (default: 1024)"},
|
||||||
{"height", NEED_ARG, NULL, 'h', arg_int, APTR(&h), "resulting image height (default: 1024)"},
|
{"height", NEED_ARG, NULL, 'h', arg_int, APTR(&h), "resulting image height (default: 1024)"},
|
||||||
@ -38,9 +38,9 @@ static myoption cmdlnopts[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, char **argv){
|
int main(int argc, char **argv){
|
||||||
initial_setup();
|
sl_init();
|
||||||
parseargs(&argc, &argv, cmdlnopts);
|
sl_parseargs(&argc, &argv, cmdlnopts);
|
||||||
if(help) showhelp(-1, cmdlnopts);
|
if(help) sl_showhelp(-1, cmdlnopts);
|
||||||
if(w < 1 || h < 1) ERRX("Wrong image size");
|
if(w < 1 || h < 1) ERRX("Wrong image size");
|
||||||
if(xsigma < DBL_EPSILON || ysigma < DBL_EPSILON) ERRX("STD should be >0");
|
if(xsigma < DBL_EPSILON || ysigma < DBL_EPSILON) ERRX("STD should be >0");
|
||||||
if(Niter < 1) ERRX("Iteration number should be a large positive number");
|
if(Niter < 1) ERRX("Iteration number should be a large positive number");
|
||||||
|
|||||||
@ -27,7 +27,7 @@ static char *outp = "output.jpg", *inp = NULL;
|
|||||||
|
|
||||||
static il_Pattern *star = NULL, *cross = NULL;
|
static il_Pattern *star = NULL, *cross = NULL;
|
||||||
|
|
||||||
static myoption cmdlnopts[] = {
|
static sl_option_t cmdlnopts[] = {
|
||||||
{"help", NO_ARGS, NULL, '?', arg_int, APTR(&help), "show this help"},
|
{"help", NO_ARGS, NULL, '?', arg_int, APTR(&help), "show this help"},
|
||||||
{"width", NEED_ARG, NULL, 'w', arg_int, APTR(&w), "resulting image width (default: 1024)"},
|
{"width", NEED_ARG, NULL, 'w', arg_int, APTR(&w), "resulting image width (default: 1024)"},
|
||||||
{"height", NEED_ARG, NULL, 'h', arg_int, APTR(&h), "resulting image height (default: 1024)"},
|
{"height", NEED_ARG, NULL, 'h', arg_int, APTR(&h), "resulting image height (default: 1024)"},
|
||||||
@ -85,11 +85,11 @@ static void addfromfile(il_Img3 *I, void (*fn)(il_Img3*, const char*)){
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv){
|
int main(int argc, char **argv){
|
||||||
initial_setup();
|
sl_init();
|
||||||
char *helpstring = "Usage: %s [args] x1,y1[,amp1] x2,y2[,amp2] ... xn,yn[,amp3] - draw 'stars' at coords xi,yi with amplitude ampi (default: 255)\n\n\tWhere args are:\n";
|
char *helpstring = "Usage: %s [args] x1,y1[,amp1] x2,y2[,amp2] ... xn,yn[,amp3] - draw 'stars' at coords xi,yi with amplitude ampi (default: 255)\n\n\tWhere args are:\n";
|
||||||
change_helpstring(helpstring);
|
sl_helpstring(helpstring);
|
||||||
parseargs(&argc, &argv, cmdlnopts);
|
sl_parseargs(&argc, &argv, cmdlnopts);
|
||||||
if(help) showhelp(-1, cmdlnopts);
|
if(help) sl_showhelp(-1, cmdlnopts);
|
||||||
if(w < 1 || h < 1) ERRX("Wrong image size");
|
if(w < 1 || h < 1) ERRX("Wrong image size");
|
||||||
if(argc == 0 && inp == NULL) ERRX("Point at least one coordinate pair or file name");
|
if(argc == 0 && inp == NULL) ERRX("Point at least one coordinate pair or file name");
|
||||||
il_Img3 *I = il_Img3_new(w, h);
|
il_Img3 *I = il_Img3_new(w, h);
|
||||||
@ -100,9 +100,9 @@ int main(int argc, char **argv){
|
|||||||
for(int i = 0; i < argc; ++i) addstar(I, argv[i]);
|
for(int i = 0; i < argc; ++i) addstar(I, argv[i]);
|
||||||
if(inp) addfromfile(I, addstar);
|
if(inp) addfromfile(I, addstar);
|
||||||
il_Pattern_free(&star);
|
il_Pattern_free(&star);
|
||||||
double t0 = dtime();
|
double t0 = sl_dtime();
|
||||||
il_Img3_addPoisson(I, lambda);
|
il_Img3_addPoisson(I, lambda);
|
||||||
green("Poisson noice took %gms\n", (dtime()-t0) * 1e3);
|
green("Poisson noice took %gms\n", (sl_dtime()-t0) * 1e3);
|
||||||
if(!il_Img3_jpg(outp, I, 95)) WARNX("Can't save %s", outp);
|
if(!il_Img3_jpg(outp, I, 95)) WARNX("Can't save %s", outp);
|
||||||
for(int i = 0; i < argc; ++i) addcross(I, argv[i]);
|
for(int i = 0; i < argc; ++i) addcross(I, argv[i]);
|
||||||
if(inp) addfromfile(I, addcross);
|
if(inp) addfromfile(I, addcross);
|
||||||
|
|||||||
@ -27,7 +27,7 @@ static char *outp = "output.png", *inp = NULL;
|
|||||||
|
|
||||||
static il_Image *star = NULL;
|
static il_Image *star = NULL;
|
||||||
|
|
||||||
static myoption cmdlnopts[] = {
|
static sl_option_t cmdlnopts[] = {
|
||||||
{"help", NO_ARGS, NULL, '?', arg_int, APTR(&help), "show this help"},
|
{"help", NO_ARGS, NULL, '?', arg_int, APTR(&help), "show this help"},
|
||||||
{"width", NEED_ARG, NULL, 'w', arg_int, APTR(&w), "resulting image width (default: 1024)"},
|
{"width", NEED_ARG, NULL, 'w', arg_int, APTR(&w), "resulting image width (default: 1024)"},
|
||||||
{"height", NEED_ARG, NULL, 'h', arg_int, APTR(&h), "resulting image height (default: 1024)"},
|
{"height", NEED_ARG, NULL, 'h', arg_int, APTR(&h), "resulting image height (default: 1024)"},
|
||||||
@ -78,11 +78,11 @@ static void addfromfile(il_Image *I){
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv){
|
int main(int argc, char **argv){
|
||||||
initial_setup();
|
sl_init();
|
||||||
char *helpstring = "Usage: %s [args] x1,y1[,w1] x2,y2[,w2] ... xn,yn[,w3] - draw 'stars' at coords xi,yi with weight wi (default: 1.)\n\n\tWhere args are:\n";
|
char *helpstring = "Usage: %s [args] x1,y1[,w1] x2,y2[,w2] ... xn,yn[,w3] - draw 'stars' at coords xi,yi with weight wi (default: 1.)\n\n\tWhere args are:\n";
|
||||||
change_helpstring(helpstring);
|
sl_helpstring(helpstring);
|
||||||
parseargs(&argc, &argv, cmdlnopts);
|
sl_parseargs(&argc, &argv, cmdlnopts);
|
||||||
if(help) showhelp(-1, cmdlnopts);
|
if(help) sl_showhelp(-1, cmdlnopts);
|
||||||
if(w < 1 || h < 1) ERRX("Wrong image size");
|
if(w < 1 || h < 1) ERRX("Wrong image size");
|
||||||
if(argc == 0 && inp == NULL) ERRX("Point at least one coordinate pair or file name");
|
if(argc == 0 && inp == NULL) ERRX("Point at least one coordinate pair or file name");
|
||||||
il_Image *I = il_Image_new(w, h, IMTYPE_U16);
|
il_Image *I = il_Image_new(w, h, IMTYPE_U16);
|
||||||
|
|||||||
@ -27,7 +27,7 @@ static int help = 0, ndilat = 0, neros = 0;
|
|||||||
double bg = -1.;
|
double bg = -1.;
|
||||||
static char *infile = NULL, *outbg = NULL, *outbin = NULL;
|
static char *infile = NULL, *outbg = NULL, *outbin = NULL;
|
||||||
|
|
||||||
static myoption cmdlnopts[] = {
|
static sl_option_t cmdlnopts[] = {
|
||||||
{"help", NO_ARGS, NULL, 'h', arg_int, APTR(&help), "show this help"},
|
{"help", NO_ARGS, NULL, 'h', arg_int, APTR(&help), "show this help"},
|
||||||
{"input", NEED_ARG, NULL, 'i', arg_string, APTR(&infile), "input file name"},
|
{"input", NEED_ARG, NULL, 'i', arg_string, APTR(&infile), "input file name"},
|
||||||
{"obg", NEED_ARG, NULL, 0, arg_string, APTR(&outbg), "input minus bg jpeg filename"},
|
{"obg", NEED_ARG, NULL, 0, arg_string, APTR(&outbg), "input minus bg jpeg filename"},
|
||||||
@ -39,9 +39,9 @@ static myoption cmdlnopts[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, char **argv){
|
int main(int argc, char **argv){
|
||||||
initial_setup();
|
sl_init();
|
||||||
parseargs(&argc, &argv, cmdlnopts);
|
sl_parseargs(&argc, &argv, cmdlnopts);
|
||||||
if(help) showhelp(-1, cmdlnopts);
|
if(help) sl_showhelp(-1, cmdlnopts);
|
||||||
if(!infile) ERRX("Point name of input file");
|
if(!infile) ERRX("Point name of input file");
|
||||||
il_Image *I = il_Image_read(infile);
|
il_Image *I = il_Image_read(infile);
|
||||||
if(!I) ERR("Can't read %s", infile);
|
if(!I) ERR("Can't read %s", infile);
|
||||||
@ -54,23 +54,23 @@ int main(int argc, char **argv){
|
|||||||
uint8_t *idata = (uint8_t*) Ibg->data;
|
uint8_t *idata = (uint8_t*) Ibg->data;
|
||||||
for(int i = 0; i < wh; ++i) idata[i] = (idata[i] > ibg) ? idata[i] - ibg : 0;
|
for(int i = 0; i < wh; ++i) idata[i] = (idata[i] > ibg) ? idata[i] - ibg : 0;
|
||||||
if(outbg) il_write_jpg(outbg, Ibg->width, Ibg->height, 1, idata, 95);
|
if(outbg) il_write_jpg(outbg, Ibg->width, Ibg->height, 1, idata, 95);
|
||||||
double t0 = dtime();
|
double t0 = sl_dtime();
|
||||||
uint8_t *Ibin = il_Image2bin(I, bg);
|
uint8_t *Ibin = il_Image2bin(I, bg);
|
||||||
if(!Ibin) ERRX("Can't binarize image");
|
if(!Ibin) ERRX("Can't binarize image");
|
||||||
green("Binarization: %gms\n", 1e3*(dtime()-t0));
|
green("Binarization: %gms\n", 1e3*(sl_dtime()-t0));
|
||||||
if(neros > 0){
|
if(neros > 0){
|
||||||
t0 = dtime();
|
t0 = sl_dtime();
|
||||||
uint8_t *eros = il_erosionN(Ibin, w, h, neros);
|
uint8_t *eros = il_erosionN(Ibin, w, h, neros);
|
||||||
FREE(Ibin);
|
FREE(Ibin);
|
||||||
Ibin = eros;
|
Ibin = eros;
|
||||||
green("%d erosions: %gms\n", neros, 1e3*(dtime()-t0));
|
green("%d erosions: %gms\n", neros, 1e3*(sl_dtime()-t0));
|
||||||
}
|
}
|
||||||
if(ndilat > 0){
|
if(ndilat > 0){
|
||||||
t0 = dtime();
|
t0 = sl_dtime();
|
||||||
uint8_t *dilat = il_dilationN(Ibin, w, h, ndilat);
|
uint8_t *dilat = il_dilationN(Ibin, w, h, ndilat);
|
||||||
FREE(Ibin);
|
FREE(Ibin);
|
||||||
Ibin = dilat;
|
Ibin = dilat;
|
||||||
green("%d dilations: %gms\n", ndilat, 1e3*(dtime()-t0));
|
green("%d dilations: %gms\n", ndilat, 1e3*(sl_dtime()-t0));
|
||||||
}
|
}
|
||||||
if(outbin){
|
if(outbin){
|
||||||
il_Image *tmp = il_bin2Image(Ibin, w, h);
|
il_Image *tmp = il_bin2Image(Ibin, w, h);
|
||||||
@ -78,9 +78,9 @@ int main(int argc, char **argv){
|
|||||||
il_Image_free(&tmp);
|
il_Image_free(&tmp);
|
||||||
}
|
}
|
||||||
il_ConnComps *comps;
|
il_ConnComps *comps;
|
||||||
t0 = dtime();
|
t0 = sl_dtime();
|
||||||
size_t *labels = il_CClabel4(Ibin, w, h, &comps);
|
size_t *labels = il_CClabel4(Ibin, w, h, &comps);
|
||||||
green("Labeling: %gms\n", 1e3*(dtime()-t0));
|
green("Labeling: %gms\n", 1e3*(sl_dtime()-t0));
|
||||||
if(labels && comps->Nobj > 1){
|
if(labels && comps->Nobj > 1){
|
||||||
printf("Detected %zd components\n", comps->Nobj-1);
|
printf("Detected %zd components\n", comps->Nobj-1);
|
||||||
il_Box *box = comps->boxes + 1;
|
il_Box *box = comps->boxes + 1;
|
||||||
|
|||||||
@ -24,7 +24,7 @@ static int help = 0, w = 1024, h = 1024;
|
|||||||
static double lambda = 15.;
|
static double lambda = 15.;
|
||||||
static char *outp = "output.png";
|
static char *outp = "output.png";
|
||||||
|
|
||||||
static myoption cmdlnopts[] = {
|
static sl_option_t cmdlnopts[] = {
|
||||||
{"help", NO_ARGS, NULL, '?', arg_int, APTR(&help), "show this help"},
|
{"help", NO_ARGS, NULL, '?', arg_int, APTR(&help), "show this help"},
|
||||||
{"width", NEED_ARG, NULL, 'w', arg_int, APTR(&w), "resulting image width (default: 1024)"},
|
{"width", NEED_ARG, NULL, 'w', arg_int, APTR(&w), "resulting image width (default: 1024)"},
|
||||||
{"height", NEED_ARG, NULL, 'h', arg_int, APTR(&h), "resulting image height (default: 1024)"},
|
{"height", NEED_ARG, NULL, 'h', arg_int, APTR(&h), "resulting image height (default: 1024)"},
|
||||||
@ -34,9 +34,9 @@ static myoption cmdlnopts[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, char **argv){
|
int main(int argc, char **argv){
|
||||||
initial_setup();
|
sl_init();
|
||||||
parseargs(&argc, &argv, cmdlnopts);
|
sl_parseargs(&argc, &argv, cmdlnopts);
|
||||||
if(help) showhelp(-1, cmdlnopts);
|
if(help) sl_showhelp(-1, cmdlnopts);
|
||||||
if(w < 1 || h < 1) ERRX("Wrong image size");
|
if(w < 1 || h < 1) ERRX("Wrong image size");
|
||||||
if(lambda < 1.) ERRX("LAMBDA should be >=1");
|
if(lambda < 1.) ERRX("LAMBDA should be >=1");
|
||||||
il_Image *I = il_Image_new(w, h, IMTYPE_U8);
|
il_Image *I = il_Image_new(w, h, IMTYPE_U8);
|
||||||
|
|||||||
37
imagefile.c
37
imagefile.c
@ -61,7 +61,7 @@ static char *hexdmp(const char sig[8]){
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const int bytes[IMTYPE_AMOUNT] = {
|
static const int bytes[IMTYPE_AMOUNT] = {
|
||||||
[IMTYPE_U8] = 1,
|
[IMTYPE_U8] = 1,
|
||||||
[IMTYPE_U16] = 2,
|
[IMTYPE_U16] = 2,
|
||||||
[IMTYPE_U32] = 4,
|
[IMTYPE_U32] = 4,
|
||||||
@ -158,7 +158,19 @@ il_Image *il_u82Image(const uint8_t *data, int width, int height){
|
|||||||
*/
|
*/
|
||||||
static inline il_Image *im_loadmono(const char *name){
|
static inline il_Image *im_loadmono(const char *name){
|
||||||
int width, height, channels;
|
int width, height, channels;
|
||||||
uint8_t *img = stbi_load(name, &width, &height, &channels, 1);
|
int is16 = stbi_is_16_bit(name);
|
||||||
|
#ifdef EBUG
|
||||||
|
int x,y,n,ok;
|
||||||
|
ok = stbi_info(name, &x, &y, &n);
|
||||||
|
if(ok){
|
||||||
|
green("%s: %dx%d pix, %d channels", name, x,y, n);
|
||||||
|
if(is16) green("\t16bit!");
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
void *img;
|
||||||
|
if(is16) img = stbi_load_16(name, &width, &height, &channels, 1);
|
||||||
|
else img = stbi_load(name, &width, &height, &channels, 1);
|
||||||
if(!img){
|
if(!img){
|
||||||
WARNX("Error in loading the image %s\n", name);
|
WARNX("Error in loading the image %s\n", name);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -167,8 +179,8 @@ static inline il_Image *im_loadmono(const char *name){
|
|||||||
I->data = img;
|
I->data = img;
|
||||||
I->width = width;
|
I->width = width;
|
||||||
I->height = height;
|
I->height = height;
|
||||||
I->type = IMTYPE_U8;
|
I->type = is16 ? IMTYPE_U16 : IMTYPE_U8;
|
||||||
I->pixbytes = 1;
|
I->pixbytes = bytes[I->type];
|
||||||
il_Image_minmax(I);
|
il_Image_minmax(I);
|
||||||
return I;
|
return I;
|
||||||
}
|
}
|
||||||
@ -300,7 +312,8 @@ size_t *il_histogram16(const il_Image *I){
|
|||||||
}
|
}
|
||||||
return histogram;
|
return histogram;
|
||||||
}
|
}
|
||||||
|
// near-zero threshold to find 2nd derivative bend-point
|
||||||
|
#define DERIV_THRESHOLD (5)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief calc_background - Simple background calculation by histogram
|
* @brief calc_background - Simple background calculation by histogram
|
||||||
@ -345,9 +358,9 @@ int il_Image_background(il_Image *img, double *bkg){
|
|||||||
int lastidx = histosize - 1;
|
int lastidx = histosize - 1;
|
||||||
OMP_FOR()
|
OMP_FOR()
|
||||||
for(int i = 2; i < lastidx; ++i)
|
for(int i = 2; i < lastidx; ++i)
|
||||||
diff2[i] = (histogram[i+2]+histogram[i-2]-2*histogram[i])/4;
|
diff2[i] = ((ssize_t)histogram[i+2]+(ssize_t)histogram[i-2]-2*(ssize_t)histogram[i])/4;
|
||||||
//green("HISTO:\n");
|
//green("HISTO:\n");
|
||||||
//for(int i = 0; i < 256; ++i) printf("%d:\t%d\t%d\n", i, histogram[i], diff2[i]);
|
//for(int i = 0; i < 256; ++i) printf("%d:\t%zd\t%zd\n", i, histogram[i], diff2[i]);
|
||||||
FREE(histogram);
|
FREE(histogram);
|
||||||
if(modeidx < 2) modeidx = 2;
|
if(modeidx < 2) modeidx = 2;
|
||||||
if((int)modeidx > lastidx-1){
|
if((int)modeidx > lastidx-1){
|
||||||
@ -357,11 +370,13 @@ int il_Image_background(il_Image *img, double *bkg){
|
|||||||
}
|
}
|
||||||
size_t borderidx = modeidx;
|
size_t borderidx = modeidx;
|
||||||
for(int i = modeidx; i < lastidx; ++i){ // search bend-point by second derivate
|
for(int i = modeidx; i < lastidx; ++i){ // search bend-point by second derivate
|
||||||
if(diff2[i] <= 0 && diff2[i+1] <= 0){
|
//if(diff2[i] <= 0 && diff2[i+1] <= 0){
|
||||||
|
if(diff2[i] < DERIV_THRESHOLD && diff2[i] > -DERIV_THRESHOLD && diff2[i+1] < DERIV_THRESHOLD && diff2[i+1] > -DERIV_THRESHOLD){
|
||||||
|
//DBG("i=%d, diff=%zd, next=%zd", i, diff2[i], diff2[i+1]);
|
||||||
borderidx = i; break;
|
borderidx = i; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//DBG("borderidx=%d -> %d", borderidx, (borderidx+modeidx)/2);
|
DBG("borderidx=%zd, modeidx=%zd, avr=%zd", borderidx, modeidx, (borderidx+modeidx)/2);
|
||||||
//*bk = (borderidx + modeidx) / 2;
|
//*bk = (borderidx + modeidx) / 2;
|
||||||
*bkg = borderidx;
|
*bkg = borderidx;
|
||||||
FREE(diff2);
|
FREE(diff2);
|
||||||
@ -601,7 +616,7 @@ static void dminmax(il_Image *I){
|
|||||||
void il_Image_minmax(il_Image *I){
|
void il_Image_minmax(il_Image *I){
|
||||||
if(!I || !I->data) return;
|
if(!I || !I->data) return;
|
||||||
#ifdef EBUG
|
#ifdef EBUG
|
||||||
double t0 = dtime();
|
double t0 = sl_dtime();
|
||||||
#endif
|
#endif
|
||||||
switch(I->type){
|
switch(I->type){
|
||||||
case IMTYPE_U8:
|
case IMTYPE_U8:
|
||||||
@ -622,7 +637,7 @@ void il_Image_minmax(il_Image *I){
|
|||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DBG("Image_minmax(): Min=%g, Max=%g, time: %gms", I->minval, I->maxval, (dtime()-t0)*1e3);
|
DBG("Image_minmax(): Min=%g, Max=%g, time: %gms", I->minval, I->maxval, (sl_dtime()-t0)*1e3);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE QtCreatorProject>
|
<!DOCTYPE QtCreatorProject>
|
||||||
<!-- Written by QtCreator 12.0.1, 2024-02-02T10:40:45. -->
|
<!-- Written by QtCreator 16.0.0, 2025-04-16T09:21:12. -->
|
||||||
<qtcreator>
|
<qtcreator>
|
||||||
<data>
|
<data>
|
||||||
<variable>EnvironmentId</variable>
|
<variable>EnvironmentId</variable>
|
||||||
@ -13,8 +13,8 @@
|
|||||||
<data>
|
<data>
|
||||||
<variable>ProjectExplorer.Project.EditorSettings</variable>
|
<variable>ProjectExplorer.Project.EditorSettings</variable>
|
||||||
<valuemap type="QVariantMap">
|
<valuemap type="QVariantMap">
|
||||||
|
<value type="bool" key="EditorConfiguration.AutoDetect">true</value>
|
||||||
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
|
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
|
||||||
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
|
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
|
||||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
|
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
|
||||||
<value type="QString" key="language">Cpp</value>
|
<value type="QString" key="language">Cpp</value>
|
||||||
@ -33,6 +33,7 @@
|
|||||||
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
|
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
|
||||||
<value type="int" key="EditorConfiguration.IndentSize">4</value>
|
<value type="int" key="EditorConfiguration.IndentSize">4</value>
|
||||||
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
|
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
|
||||||
|
<value type="int" key="EditorConfiguration.LineEndingBehavior">0</value>
|
||||||
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
|
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
|
||||||
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
|
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
|
||||||
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
|
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
|
||||||
@ -69,7 +70,9 @@
|
|||||||
<value type="bool" key="AutoTest.Framework.QtQuickTest">true</value>
|
<value type="bool" key="AutoTest.Framework.QtQuickTest">true</value>
|
||||||
<value type="bool" key="AutoTest.Framework.QtTest">true</value>
|
<value type="bool" key="AutoTest.Framework.QtTest">true</value>
|
||||||
</valuemap>
|
</valuemap>
|
||||||
|
<value type="bool" key="AutoTest.ApplyFilter">false</value>
|
||||||
<valuemap type="QVariantMap" key="AutoTest.CheckStates"/>
|
<valuemap type="QVariantMap" key="AutoTest.CheckStates"/>
|
||||||
|
<valuelist type="QVariantList" key="AutoTest.PathFilters"/>
|
||||||
<value type="int" key="AutoTest.RunAfterBuild">0</value>
|
<value type="int" key="AutoTest.RunAfterBuild">0</value>
|
||||||
<value type="bool" key="AutoTest.UseGlobal">true</value>
|
<value type="bool" key="AutoTest.UseGlobal">true</value>
|
||||||
<valuemap type="QVariantMap" key="ClangTools">
|
<valuemap type="QVariantMap" key="ClangTools">
|
||||||
@ -96,7 +99,7 @@
|
|||||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
<value type="qlonglong" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
<value type="qlonglong" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
||||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/eddy/Docs/SAO/Image_processing/Image_processing_library=improclib</value>
|
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/eddy/Docs/SAO/Image_processing/Image_processing_library.improclib</value>
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||||
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
|
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
|
||||||
@ -153,6 +156,7 @@
|
|||||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||||
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
||||||
|
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
|
||||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey"></value>
|
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey"></value>
|
||||||
|
|||||||
352
stb/stb_image.h
352
stb/stb_image.h
@ -1,4 +1,4 @@
|
|||||||
/* stb_image - v2.28 - public domain image loader - http://nothings.org/stb
|
/* stb_image - v2.29 - public domain image loader - http://nothings.org/stb
|
||||||
no warranty implied; use at your own risk
|
no warranty implied; use at your own risk
|
||||||
|
|
||||||
Do this:
|
Do this:
|
||||||
@ -48,6 +48,7 @@ LICENSE
|
|||||||
|
|
||||||
RECENT REVISION HISTORY:
|
RECENT REVISION HISTORY:
|
||||||
|
|
||||||
|
2.29 (2023-05-xx) optimizations
|
||||||
2.28 (2023-01-29) many error fixes, security errors, just tons of stuff
|
2.28 (2023-01-29) many error fixes, security errors, just tons of stuff
|
||||||
2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes
|
2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes
|
||||||
2.26 (2020-07-13) many minor fixes
|
2.26 (2020-07-13) many minor fixes
|
||||||
@ -1072,8 +1073,8 @@ static int stbi__addints_valid(int a, int b)
|
|||||||
return a <= INT_MAX - b;
|
return a <= INT_MAX - b;
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns 1 if the product of two signed shorts is valid, 0 on overflow.
|
// returns 1 if the product of two ints fits in a signed short, 0 on overflow.
|
||||||
static int stbi__mul2shorts_valid(short a, short b)
|
static int stbi__mul2shorts_valid(int a, int b)
|
||||||
{
|
{
|
||||||
if (b == 0 || b == -1) return 1; // multiplication by 0 is always 0; check for -1 so SHRT_MIN/b doesn't overflow
|
if (b == 0 || b == -1) return 1; // multiplication by 0 is always 0; check for -1 so SHRT_MIN/b doesn't overflow
|
||||||
if ((a >= 0) == (b >= 0)) return a <= SHRT_MAX/b; // product is positive, so similar to mul2sizes_valid
|
if ((a >= 0) == (b >= 0)) return a <= SHRT_MAX/b; // product is positive, so similar to mul2sizes_valid
|
||||||
@ -3384,13 +3385,13 @@ static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int stbi__skip_jpeg_junk_at_end(stbi__jpeg *j)
|
static stbi_uc stbi__skip_jpeg_junk_at_end(stbi__jpeg *j)
|
||||||
{
|
{
|
||||||
// some JPEGs have junk at end, skip over it but if we find what looks
|
// some JPEGs have junk at end, skip over it but if we find what looks
|
||||||
// like a valid marker, resume there
|
// like a valid marker, resume there
|
||||||
while (!stbi__at_eof(j->s)) {
|
while (!stbi__at_eof(j->s)) {
|
||||||
int x = stbi__get8(j->s);
|
stbi_uc x = stbi__get8(j->s);
|
||||||
while (x == 255) { // might be a marker
|
while (x == 0xff) { // might be a marker
|
||||||
if (stbi__at_eof(j->s)) return STBI__MARKER_none;
|
if (stbi__at_eof(j->s)) return STBI__MARKER_none;
|
||||||
x = stbi__get8(j->s);
|
x = stbi__get8(j->s);
|
||||||
if (x != 0x00 && x != 0xff) {
|
if (x != 0x00 && x != 0xff) {
|
||||||
@ -4176,6 +4177,7 @@ typedef struct
|
|||||||
{
|
{
|
||||||
stbi_uc *zbuffer, *zbuffer_end;
|
stbi_uc *zbuffer, *zbuffer_end;
|
||||||
int num_bits;
|
int num_bits;
|
||||||
|
int hit_zeof_once;
|
||||||
stbi__uint32 code_buffer;
|
stbi__uint32 code_buffer;
|
||||||
|
|
||||||
char *zout;
|
char *zout;
|
||||||
@ -4242,10 +4244,21 @@ stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z)
|
|||||||
int b,s;
|
int b,s;
|
||||||
if (a->num_bits < 16) {
|
if (a->num_bits < 16) {
|
||||||
if (stbi__zeof(a)) {
|
if (stbi__zeof(a)) {
|
||||||
return -1; /* report error for unexpected end of data. */
|
if (!a->hit_zeof_once) {
|
||||||
|
// This is the first time we hit eof, insert 16 extra padding btis
|
||||||
|
// to allow us to keep going; if we actually consume any of them
|
||||||
|
// though, that is invalid data. This is caught later.
|
||||||
|
a->hit_zeof_once = 1;
|
||||||
|
a->num_bits += 16; // add 16 implicit zero bits
|
||||||
|
} else {
|
||||||
|
// We already inserted our extra 16 padding bits and are again
|
||||||
|
// out, this stream is actually prematurely terminated.
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
stbi__fill_bits(a);
|
stbi__fill_bits(a);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
b = z->fast[a->code_buffer & STBI__ZFAST_MASK];
|
b = z->fast[a->code_buffer & STBI__ZFAST_MASK];
|
||||||
if (b) {
|
if (b) {
|
||||||
s = b >> 9;
|
s = b >> 9;
|
||||||
@ -4309,6 +4322,13 @@ static int stbi__parse_huffman_block(stbi__zbuf *a)
|
|||||||
int len,dist;
|
int len,dist;
|
||||||
if (z == 256) {
|
if (z == 256) {
|
||||||
a->zout = zout;
|
a->zout = zout;
|
||||||
|
if (a->hit_zeof_once && a->num_bits < 16) {
|
||||||
|
// The first time we hit zeof, we inserted 16 extra zero bits into our bit
|
||||||
|
// buffer so the decoder can just do its speculative decoding. But if we
|
||||||
|
// actually consumed any of those bits (which is the case when num_bits < 16),
|
||||||
|
// the stream actually read past the end so it is malformed.
|
||||||
|
return stbi__err("unexpected end","Corrupt PNG");
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (z >= 286) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, length codes 286 and 287 must not appear in compressed data
|
if (z >= 286) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, length codes 286 and 287 must not appear in compressed data
|
||||||
@ -4320,7 +4340,7 @@ static int stbi__parse_huffman_block(stbi__zbuf *a)
|
|||||||
dist = stbi__zdist_base[z];
|
dist = stbi__zdist_base[z];
|
||||||
if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]);
|
if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]);
|
||||||
if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG");
|
if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG");
|
||||||
if (zout + len > a->zout_end) {
|
if (len > a->zout_end - zout) {
|
||||||
if (!stbi__zexpand(a, zout, len)) return 0;
|
if (!stbi__zexpand(a, zout, len)) return 0;
|
||||||
zout = a->zout;
|
zout = a->zout;
|
||||||
}
|
}
|
||||||
@ -4464,6 +4484,7 @@ static int stbi__parse_zlib(stbi__zbuf *a, int parse_header)
|
|||||||
if (!stbi__parse_zlib_header(a)) return 0;
|
if (!stbi__parse_zlib_header(a)) return 0;
|
||||||
a->num_bits = 0;
|
a->num_bits = 0;
|
||||||
a->code_buffer = 0;
|
a->code_buffer = 0;
|
||||||
|
a->hit_zeof_once = 0;
|
||||||
do {
|
do {
|
||||||
final = stbi__zreceive(a,1);
|
final = stbi__zreceive(a,1);
|
||||||
type = stbi__zreceive(a,2);
|
type = stbi__zreceive(a,2);
|
||||||
@ -4619,9 +4640,8 @@ enum {
|
|||||||
STBI__F_up=2,
|
STBI__F_up=2,
|
||||||
STBI__F_avg=3,
|
STBI__F_avg=3,
|
||||||
STBI__F_paeth=4,
|
STBI__F_paeth=4,
|
||||||
// synthetic filters used for first scanline to avoid needing a dummy row of 0s
|
// synthetic filter used for first scanline to avoid needing a dummy row of 0s
|
||||||
STBI__F_avg_first,
|
STBI__F_avg_first
|
||||||
STBI__F_paeth_first
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static stbi_uc first_row_filter[5] =
|
static stbi_uc first_row_filter[5] =
|
||||||
@ -4630,22 +4650,47 @@ static stbi_uc first_row_filter[5] =
|
|||||||
STBI__F_sub,
|
STBI__F_sub,
|
||||||
STBI__F_none,
|
STBI__F_none,
|
||||||
STBI__F_avg_first,
|
STBI__F_avg_first,
|
||||||
STBI__F_paeth_first
|
STBI__F_sub // Paeth with b=c=0 turns out to be equivalent to sub
|
||||||
};
|
};
|
||||||
|
|
||||||
static int stbi__paeth(int a, int b, int c)
|
static int stbi__paeth(int a, int b, int c)
|
||||||
{
|
{
|
||||||
int p = a + b - c;
|
// This formulation looks very different from the reference in the PNG spec, but is
|
||||||
int pa = abs(p-a);
|
// actually equivalent and has favorable data dependencies and admits straightforward
|
||||||
int pb = abs(p-b);
|
// generation of branch-free code, which helps performance significantly.
|
||||||
int pc = abs(p-c);
|
int thresh = c*3 - (a + b);
|
||||||
if (pa <= pb && pa <= pc) return a;
|
int lo = a < b ? a : b;
|
||||||
if (pb <= pc) return b;
|
int hi = a < b ? b : a;
|
||||||
return c;
|
int t0 = (hi <= thresh) ? lo : c;
|
||||||
|
int t1 = (thresh <= lo) ? hi : t0;
|
||||||
|
return t1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 };
|
static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 };
|
||||||
|
|
||||||
|
// adds an extra all-255 alpha channel
|
||||||
|
// dest == src is legal
|
||||||
|
// img_n must be 1 or 3
|
||||||
|
static void stbi__create_png_alpha_expand8(stbi_uc *dest, stbi_uc *src, stbi__uint32 x, int img_n)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
// must process data backwards since we allow dest==src
|
||||||
|
if (img_n == 1) {
|
||||||
|
for (i=x-1; i >= 0; --i) {
|
||||||
|
dest[i*2+1] = 255;
|
||||||
|
dest[i*2+0] = src[i];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
STBI_ASSERT(img_n == 3);
|
||||||
|
for (i=x-1; i >= 0; --i) {
|
||||||
|
dest[i*4+3] = 255;
|
||||||
|
dest[i*4+2] = src[i*3+2];
|
||||||
|
dest[i*4+1] = src[i*3+1];
|
||||||
|
dest[i*4+0] = src[i*3+0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// create the png data from post-deflated data
|
// create the png data from post-deflated data
|
||||||
static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color)
|
static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color)
|
||||||
{
|
{
|
||||||
@ -4653,6 +4698,8 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
|
|||||||
stbi__context *s = a->s;
|
stbi__context *s = a->s;
|
||||||
stbi__uint32 i,j,stride = x*out_n*bytes;
|
stbi__uint32 i,j,stride = x*out_n*bytes;
|
||||||
stbi__uint32 img_len, img_width_bytes;
|
stbi__uint32 img_len, img_width_bytes;
|
||||||
|
stbi_uc *filter_buf;
|
||||||
|
int all_ok = 1;
|
||||||
int k;
|
int k;
|
||||||
int img_n = s->img_n; // copy it into a local for later
|
int img_n = s->img_n; // copy it into a local for later
|
||||||
|
|
||||||
@ -4664,8 +4711,11 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
|
|||||||
a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into
|
a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into
|
||||||
if (!a->out) return stbi__err("outofmem", "Out of memory");
|
if (!a->out) return stbi__err("outofmem", "Out of memory");
|
||||||
|
|
||||||
|
// note: error exits here don't need to clean up a->out individually,
|
||||||
|
// stbi__do_png always does on error.
|
||||||
if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG");
|
if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG");
|
||||||
img_width_bytes = (((img_n * x * depth) + 7) >> 3);
|
img_width_bytes = (((img_n * x * depth) + 7) >> 3);
|
||||||
|
if (!stbi__mad2sizes_valid(img_width_bytes, y, img_width_bytes)) return stbi__err("too large", "Corrupt PNG");
|
||||||
img_len = (img_width_bytes + 1) * y;
|
img_len = (img_width_bytes + 1) * y;
|
||||||
|
|
||||||
// we used to check for exact match between raw_len and img_len on non-interlaced PNGs,
|
// we used to check for exact match between raw_len and img_len on non-interlaced PNGs,
|
||||||
@ -4673,188 +4723,136 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
|
|||||||
// so just check for raw_len < img_len always.
|
// so just check for raw_len < img_len always.
|
||||||
if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG");
|
if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG");
|
||||||
|
|
||||||
for (j=0; j < y; ++j) {
|
// Allocate two scan lines worth of filter workspace buffer.
|
||||||
stbi_uc *cur = a->out + stride*j;
|
filter_buf = (stbi_uc *) stbi__malloc_mad2(img_width_bytes, 2, 0);
|
||||||
stbi_uc *prior;
|
if (!filter_buf) return stbi__err("outofmem", "Out of memory");
|
||||||
int filter = *raw++;
|
|
||||||
|
|
||||||
if (filter > 4)
|
|
||||||
return stbi__err("invalid filter","Corrupt PNG");
|
|
||||||
|
|
||||||
|
// Filtering for low-bit-depth images
|
||||||
if (depth < 8) {
|
if (depth < 8) {
|
||||||
if (img_width_bytes > x) return stbi__err("invalid width","Corrupt PNG");
|
|
||||||
cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place
|
|
||||||
filter_bytes = 1;
|
filter_bytes = 1;
|
||||||
width = img_width_bytes;
|
width = img_width_bytes;
|
||||||
}
|
}
|
||||||
prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above
|
|
||||||
|
for (j=0; j < y; ++j) {
|
||||||
|
// cur/prior filter buffers alternate
|
||||||
|
stbi_uc *cur = filter_buf + (j & 1)*img_width_bytes;
|
||||||
|
stbi_uc *prior = filter_buf + (~j & 1)*img_width_bytes;
|
||||||
|
stbi_uc *dest = a->out + stride*j;
|
||||||
|
int nk = width * filter_bytes;
|
||||||
|
int filter = *raw++;
|
||||||
|
|
||||||
|
// check filter type
|
||||||
|
if (filter > 4) {
|
||||||
|
all_ok = stbi__err("invalid filter","Corrupt PNG");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// if first row, use special filter that doesn't sample previous row
|
// if first row, use special filter that doesn't sample previous row
|
||||||
if (j == 0) filter = first_row_filter[filter];
|
if (j == 0) filter = first_row_filter[filter];
|
||||||
|
|
||||||
// handle first byte explicitly
|
// perform actual filtering
|
||||||
for (k=0; k < filter_bytes; ++k) {
|
|
||||||
switch (filter) {
|
switch (filter) {
|
||||||
case STBI__F_none : cur[k] = raw[k]; break;
|
case STBI__F_none:
|
||||||
case STBI__F_sub : cur[k] = raw[k]; break;
|
memcpy(cur, raw, nk);
|
||||||
case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break;
|
break;
|
||||||
case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break;
|
case STBI__F_sub:
|
||||||
case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break;
|
memcpy(cur, raw, filter_bytes);
|
||||||
case STBI__F_avg_first : cur[k] = raw[k]; break;
|
for (k = filter_bytes; k < nk; ++k)
|
||||||
case STBI__F_paeth_first: cur[k] = raw[k]; break;
|
cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]);
|
||||||
}
|
break;
|
||||||
}
|
case STBI__F_up:
|
||||||
|
|
||||||
if (depth == 8) {
|
|
||||||
if (img_n != out_n)
|
|
||||||
cur[img_n] = 255; // first pixel
|
|
||||||
raw += img_n;
|
|
||||||
cur += out_n;
|
|
||||||
prior += out_n;
|
|
||||||
} else if (depth == 16) {
|
|
||||||
if (img_n != out_n) {
|
|
||||||
cur[filter_bytes] = 255; // first pixel top byte
|
|
||||||
cur[filter_bytes+1] = 255; // first pixel bottom byte
|
|
||||||
}
|
|
||||||
raw += filter_bytes;
|
|
||||||
cur += output_bytes;
|
|
||||||
prior += output_bytes;
|
|
||||||
} else {
|
|
||||||
raw += 1;
|
|
||||||
cur += 1;
|
|
||||||
prior += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// this is a little gross, so that we don't switch per-pixel or per-component
|
|
||||||
if (depth < 8 || img_n == out_n) {
|
|
||||||
int nk = (width - 1)*filter_bytes;
|
|
||||||
#define STBI__CASE(f) \
|
|
||||||
case f: \
|
|
||||||
for (k = 0; k < nk; ++k)
|
for (k = 0; k < nk; ++k)
|
||||||
switch (filter) {
|
cur[k] = STBI__BYTECAST(raw[k] + prior[k]);
|
||||||
// "none" filter turns into a memcpy here; make that explicit.
|
break;
|
||||||
case STBI__F_none: memcpy(cur, raw, nk); break;
|
case STBI__F_avg:
|
||||||
STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break;
|
for (k = 0; k < filter_bytes; ++k)
|
||||||
STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;
|
cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1));
|
||||||
STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break;
|
for (k = filter_bytes; k < nk; ++k)
|
||||||
STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break;
|
cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1));
|
||||||
STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break;
|
break;
|
||||||
STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break;
|
case STBI__F_paeth:
|
||||||
|
for (k = 0; k < filter_bytes; ++k)
|
||||||
|
cur[k] = STBI__BYTECAST(raw[k] + prior[k]); // prior[k] == stbi__paeth(0,prior[k],0)
|
||||||
|
for (k = filter_bytes; k < nk; ++k)
|
||||||
|
cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes], prior[k], prior[k-filter_bytes]));
|
||||||
|
break;
|
||||||
|
case STBI__F_avg_first:
|
||||||
|
memcpy(cur, raw, filter_bytes);
|
||||||
|
for (k = filter_bytes; k < nk; ++k)
|
||||||
|
cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
#undef STBI__CASE
|
|
||||||
raw += nk;
|
raw += nk;
|
||||||
|
|
||||||
|
// expand decoded bits in cur to dest, also adding an extra alpha channel if desired
|
||||||
|
if (depth < 8) {
|
||||||
|
stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range
|
||||||
|
stbi_uc *in = cur;
|
||||||
|
stbi_uc *out = dest;
|
||||||
|
stbi_uc inb = 0;
|
||||||
|
stbi__uint32 nsmp = x*img_n;
|
||||||
|
|
||||||
|
// expand bits to bytes first
|
||||||
|
if (depth == 4) {
|
||||||
|
for (i=0; i < nsmp; ++i) {
|
||||||
|
if ((i & 1) == 0) inb = *in++;
|
||||||
|
*out++ = scale * (inb >> 4);
|
||||||
|
inb <<= 4;
|
||||||
|
}
|
||||||
|
} else if (depth == 2) {
|
||||||
|
for (i=0; i < nsmp; ++i) {
|
||||||
|
if ((i & 3) == 0) inb = *in++;
|
||||||
|
*out++ = scale * (inb >> 6);
|
||||||
|
inb <<= 2;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
STBI_ASSERT(depth == 1);
|
||||||
|
for (i=0; i < nsmp; ++i) {
|
||||||
|
if ((i & 7) == 0) inb = *in++;
|
||||||
|
*out++ = scale * (inb >> 7);
|
||||||
|
inb <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert alpha=255 values if desired
|
||||||
|
if (img_n != out_n)
|
||||||
|
stbi__create_png_alpha_expand8(dest, dest, x, img_n);
|
||||||
|
} else if (depth == 8) {
|
||||||
|
if (img_n == out_n)
|
||||||
|
memcpy(dest, cur, x*img_n);
|
||||||
|
else
|
||||||
|
stbi__create_png_alpha_expand8(dest, cur, x, img_n);
|
||||||
|
} else if (depth == 16) {
|
||||||
|
// convert the image data from big-endian to platform-native
|
||||||
|
stbi__uint16 *dest16 = (stbi__uint16*)dest;
|
||||||
|
stbi__uint32 nsmp = x*img_n;
|
||||||
|
|
||||||
|
if (img_n == out_n) {
|
||||||
|
for (i = 0; i < nsmp; ++i, ++dest16, cur += 2)
|
||||||
|
*dest16 = (cur[0] << 8) | cur[1];
|
||||||
} else {
|
} else {
|
||||||
STBI_ASSERT(img_n+1 == out_n);
|
STBI_ASSERT(img_n+1 == out_n);
|
||||||
#define STBI__CASE(f) \
|
|
||||||
case f: \
|
|
||||||
for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \
|
|
||||||
for (k=0; k < filter_bytes; ++k)
|
|
||||||
switch (filter) {
|
|
||||||
STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break;
|
|
||||||
STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break;
|
|
||||||
STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;
|
|
||||||
STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break;
|
|
||||||
STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break;
|
|
||||||
STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break;
|
|
||||||
STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break;
|
|
||||||
}
|
|
||||||
#undef STBI__CASE
|
|
||||||
|
|
||||||
// the loop above sets the high byte of the pixels' alpha, but for
|
|
||||||
// 16 bit png files we also need the low byte set. we'll do that here.
|
|
||||||
if (depth == 16) {
|
|
||||||
cur = a->out + stride*j; // start at the beginning of the row again
|
|
||||||
for (i=0; i < x; ++i,cur+=output_bytes) {
|
|
||||||
cur[filter_bytes+1] = 255;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// we make a separate pass to expand bits to pixels; for performance,
|
|
||||||
// this could run two scanlines behind the above code, so it won't
|
|
||||||
// intefere with filtering but will still be in the cache.
|
|
||||||
if (depth < 8) {
|
|
||||||
for (j=0; j < y; ++j) {
|
|
||||||
stbi_uc *cur = a->out + stride*j;
|
|
||||||
stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes;
|
|
||||||
// unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit
|
|
||||||
// png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop
|
|
||||||
stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range
|
|
||||||
|
|
||||||
// note that the final byte might overshoot and write more data than desired.
|
|
||||||
// we can allocate enough data that this never writes out of memory, but it
|
|
||||||
// could also overwrite the next scanline. can it overwrite non-empty data
|
|
||||||
// on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel.
|
|
||||||
// so we need to explicitly clamp the final ones
|
|
||||||
|
|
||||||
if (depth == 4) {
|
|
||||||
for (k=x*img_n; k >= 2; k-=2, ++in) {
|
|
||||||
*cur++ = scale * ((*in >> 4) );
|
|
||||||
*cur++ = scale * ((*in ) & 0x0f);
|
|
||||||
}
|
|
||||||
if (k > 0) *cur++ = scale * ((*in >> 4) );
|
|
||||||
} else if (depth == 2) {
|
|
||||||
for (k=x*img_n; k >= 4; k-=4, ++in) {
|
|
||||||
*cur++ = scale * ((*in >> 6) );
|
|
||||||
*cur++ = scale * ((*in >> 4) & 0x03);
|
|
||||||
*cur++ = scale * ((*in >> 2) & 0x03);
|
|
||||||
*cur++ = scale * ((*in ) & 0x03);
|
|
||||||
}
|
|
||||||
if (k > 0) *cur++ = scale * ((*in >> 6) );
|
|
||||||
if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03);
|
|
||||||
if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03);
|
|
||||||
} else if (depth == 1) {
|
|
||||||
for (k=x*img_n; k >= 8; k-=8, ++in) {
|
|
||||||
*cur++ = scale * ((*in >> 7) );
|
|
||||||
*cur++ = scale * ((*in >> 6) & 0x01);
|
|
||||||
*cur++ = scale * ((*in >> 5) & 0x01);
|
|
||||||
*cur++ = scale * ((*in >> 4) & 0x01);
|
|
||||||
*cur++ = scale * ((*in >> 3) & 0x01);
|
|
||||||
*cur++ = scale * ((*in >> 2) & 0x01);
|
|
||||||
*cur++ = scale * ((*in >> 1) & 0x01);
|
|
||||||
*cur++ = scale * ((*in ) & 0x01);
|
|
||||||
}
|
|
||||||
if (k > 0) *cur++ = scale * ((*in >> 7) );
|
|
||||||
if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01);
|
|
||||||
if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01);
|
|
||||||
if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01);
|
|
||||||
if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01);
|
|
||||||
if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01);
|
|
||||||
if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01);
|
|
||||||
}
|
|
||||||
if (img_n != out_n) {
|
|
||||||
int q;
|
|
||||||
// insert alpha = 255
|
|
||||||
cur = a->out + stride*j;
|
|
||||||
if (img_n == 1) {
|
if (img_n == 1) {
|
||||||
for (q=x-1; q >= 0; --q) {
|
for (i = 0; i < x; ++i, dest16 += 2, cur += 2) {
|
||||||
cur[q*2+1] = 255;
|
dest16[0] = (cur[0] << 8) | cur[1];
|
||||||
cur[q*2+0] = cur[q];
|
dest16[1] = 0xffff;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
STBI_ASSERT(img_n == 3);
|
STBI_ASSERT(img_n == 3);
|
||||||
for (q=x-1; q >= 0; --q) {
|
for (i = 0; i < x; ++i, dest16 += 4, cur += 6) {
|
||||||
cur[q*4+3] = 255;
|
dest16[0] = (cur[0] << 8) | cur[1];
|
||||||
cur[q*4+2] = cur[q*3+2];
|
dest16[1] = (cur[2] << 8) | cur[3];
|
||||||
cur[q*4+1] = cur[q*3+1];
|
dest16[2] = (cur[4] << 8) | cur[5];
|
||||||
cur[q*4+0] = cur[q*3+0];
|
dest16[3] = 0xffff;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (depth == 16) {
|
|
||||||
// force the image data from big-endian to platform-native.
|
|
||||||
// this is done in a separate pass due to the decoding relying
|
|
||||||
// on the data being untouched, but could probably be done
|
|
||||||
// per-line during decode if care is taken.
|
|
||||||
stbi_uc *cur = a->out;
|
|
||||||
stbi__uint16 *cur16 = (stbi__uint16*)cur;
|
|
||||||
|
|
||||||
for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) {
|
STBI_FREE(filter_buf);
|
||||||
*cur16 = (cur[0] << 8) | cur[1];
|
if (!all_ok) return 0;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
/* stb_image_write - v1.15 - public domain - http://nothings.org/stb
|
/* stb_image_write - v1.16 - public domain - http://nothings.org/stb
|
||||||
writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015
|
writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015
|
||||||
no warranty implied; use at your own risk
|
no warranty implied; use at your own risk
|
||||||
|
|
||||||
@ -140,6 +140,7 @@ CREDITS:
|
|||||||
Ivan Tikhonov
|
Ivan Tikhonov
|
||||||
github:ignotion
|
github:ignotion
|
||||||
Adam Schackart
|
Adam Schackart
|
||||||
|
Andrew Kensler
|
||||||
|
|
||||||
LICENSE
|
LICENSE
|
||||||
|
|
||||||
@ -166,9 +167,9 @@ LICENSE
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations
|
#ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations
|
||||||
extern int stbi_write_tga_with_rle;
|
STBIWDEF int stbi_write_tga_with_rle;
|
||||||
extern int stbi_write_png_compression_level;
|
STBIWDEF int stbi_write_png_compression_level;
|
||||||
extern int stbi_write_force_png_filter;
|
STBIWDEF int stbi_write_force_png_filter;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef STBI_WRITE_NO_STDIO
|
#ifndef STBI_WRITE_NO_STDIO
|
||||||
@ -178,7 +179,7 @@ STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const
|
|||||||
STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
|
STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
|
||||||
STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality);
|
STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality);
|
||||||
|
|
||||||
#ifdef STBI_WINDOWS_UTF8
|
#ifdef STBIW_WINDOWS_UTF8
|
||||||
STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input);
|
STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
@ -285,7 +286,7 @@ static void stbi__stdio_write(void *context, void *data, int size)
|
|||||||
fwrite(data,1,size,(FILE*) context);
|
fwrite(data,1,size,(FILE*) context);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8)
|
#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8)
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
#define STBIW_EXTERN extern "C"
|
#define STBIW_EXTERN extern "C"
|
||||||
#else
|
#else
|
||||||
@ -303,16 +304,16 @@ STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const w
|
|||||||
static FILE *stbiw__fopen(char const *filename, char const *mode)
|
static FILE *stbiw__fopen(char const *filename, char const *mode)
|
||||||
{
|
{
|
||||||
FILE *f;
|
FILE *f;
|
||||||
#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8)
|
#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8)
|
||||||
wchar_t wMode[64];
|
wchar_t wMode[64];
|
||||||
wchar_t wFilename[1024];
|
wchar_t wFilename[1024];
|
||||||
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)))
|
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)))
|
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
#if _MSC_VER >= 1400
|
#if defined(_MSC_VER) && _MSC_VER >= 1400
|
||||||
if (0 != _wfopen_s(&f, wFilename, wMode))
|
if (0 != _wfopen_s(&f, wFilename, wMode))
|
||||||
f = 0;
|
f = 0;
|
||||||
#else
|
#else
|
||||||
@ -397,7 +398,7 @@ static void stbiw__putc(stbi__write_context *s, unsigned char c)
|
|||||||
|
|
||||||
static void stbiw__write1(stbi__write_context *s, unsigned char a)
|
static void stbiw__write1(stbi__write_context *s, unsigned char a)
|
||||||
{
|
{
|
||||||
if (s->buf_used + 1 > sizeof(s->buffer))
|
if ((size_t)s->buf_used + 1 > sizeof(s->buffer))
|
||||||
stbiw__write_flush(s);
|
stbiw__write_flush(s);
|
||||||
s->buffer[s->buf_used++] = a;
|
s->buffer[s->buf_used++] = a;
|
||||||
}
|
}
|
||||||
@ -405,7 +406,7 @@ static void stbiw__write1(stbi__write_context *s, unsigned char a)
|
|||||||
static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c)
|
static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c)
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
if (s->buf_used + 3 > sizeof(s->buffer))
|
if ((size_t)s->buf_used + 3 > sizeof(s->buffer))
|
||||||
stbiw__write_flush(s);
|
stbiw__write_flush(s);
|
||||||
n = s->buf_used;
|
n = s->buf_used;
|
||||||
s->buf_used = n+3;
|
s->buf_used = n+3;
|
||||||
@ -490,11 +491,22 @@ static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x,
|
|||||||
|
|
||||||
static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data)
|
static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data)
|
||||||
{
|
{
|
||||||
|
if (comp != 4) {
|
||||||
|
// write RGB bitmap
|
||||||
int pad = (-x*3) & 3;
|
int pad = (-x*3) & 3;
|
||||||
return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad,
|
return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad,
|
||||||
"11 4 22 4" "4 44 22 444444",
|
"11 4 22 4" "4 44 22 444444",
|
||||||
'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header
|
'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header
|
||||||
40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header
|
40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header
|
||||||
|
} else {
|
||||||
|
// RGBA bitmaps need a v4 header
|
||||||
|
// use BI_BITFIELDS mode with 32bpp and alpha mask
|
||||||
|
// (straight BI_RGB with alpha mask doesn't work in most readers)
|
||||||
|
return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *)data,1,0,
|
||||||
|
"11 4 22 4" "4 44 22 444444 4444 4 444 444 444 444",
|
||||||
|
'B', 'M', 14+108+x*y*4, 0, 0, 14+108, // file header
|
||||||
|
108, x,y, 1,32, 3,0,0,0,0,0, 0xff0000,0xff00,0xff,0xff000000u, 0, 0,0,0, 0,0,0, 0,0,0, 0,0,0); // bitmap V4 header
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
|
STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
|
||||||
@ -622,6 +634,8 @@ STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const
|
|||||||
|
|
||||||
#define stbiw__max(a, b) ((a) > (b) ? (a) : (b))
|
#define stbiw__max(a, b) ((a) > (b) ? (a) : (b))
|
||||||
|
|
||||||
|
#ifndef STBI_WRITE_NO_STDIO
|
||||||
|
|
||||||
static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
|
static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
|
||||||
{
|
{
|
||||||
int exponent;
|
int exponent;
|
||||||
@ -756,7 +770,7 @@ static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, f
|
|||||||
char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n";
|
char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n";
|
||||||
s->func(s->context, header, sizeof(header)-1);
|
s->func(s->context, header, sizeof(header)-1);
|
||||||
|
|
||||||
#ifdef __STDC_WANT_SECURE_LIB__
|
#ifdef __STDC_LIB_EXT1__
|
||||||
len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
|
len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
|
||||||
#else
|
#else
|
||||||
len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
|
len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
|
||||||
@ -777,7 +791,6 @@ STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x,
|
|||||||
return stbi_write_hdr_core(&s, x, y, comp, (float *) data);
|
return stbi_write_hdr_core(&s, x, y, comp, (float *) data);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef STBI_WRITE_NO_STDIO
|
|
||||||
STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)
|
STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)
|
||||||
{
|
{
|
||||||
stbi__write_context s = { 0 };
|
stbi__write_context s = { 0 };
|
||||||
@ -968,6 +981,23 @@ STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, i
|
|||||||
(void) stbiw__sbfree(hash_table[i]);
|
(void) stbiw__sbfree(hash_table[i]);
|
||||||
STBIW_FREE(hash_table);
|
STBIW_FREE(hash_table);
|
||||||
|
|
||||||
|
// store uncompressed instead if compression was worse
|
||||||
|
if (stbiw__sbn(out) > data_len + 2 + ((data_len+32766)/32767)*5) {
|
||||||
|
stbiw__sbn(out) = 2; // truncate to DEFLATE 32K window and FLEVEL = 1
|
||||||
|
for (j = 0; j < data_len;) {
|
||||||
|
int blocklen = data_len - j;
|
||||||
|
if (blocklen > 32767) blocklen = 32767;
|
||||||
|
stbiw__sbpush(out, data_len - j == blocklen); // BFINAL = ?, BTYPE = 0 -- no compression
|
||||||
|
stbiw__sbpush(out, STBIW_UCHAR(blocklen)); // LEN
|
||||||
|
stbiw__sbpush(out, STBIW_UCHAR(blocklen >> 8));
|
||||||
|
stbiw__sbpush(out, STBIW_UCHAR(~blocklen)); // NLEN
|
||||||
|
stbiw__sbpush(out, STBIW_UCHAR(~blocklen >> 8));
|
||||||
|
memcpy(out+stbiw__sbn(out), data+j, blocklen);
|
||||||
|
stbiw__sbn(out) += blocklen;
|
||||||
|
j += blocklen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// compute adler32 on input
|
// compute adler32 on input
|
||||||
unsigned int s1=1, s2=0;
|
unsigned int s1=1, s2=0;
|
||||||
@ -1598,6 +1628,10 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const
|
|||||||
#endif // STB_IMAGE_WRITE_IMPLEMENTATION
|
#endif // STB_IMAGE_WRITE_IMPLEMENTATION
|
||||||
|
|
||||||
/* Revision history
|
/* Revision history
|
||||||
|
1.16 (2021-07-11)
|
||||||
|
make Deflate code emit uncompressed blocks when it would otherwise expand
|
||||||
|
support writing BMPs with alpha channel
|
||||||
|
1.15 (2020-07-13) unknown
|
||||||
1.14 (2020-02-02) updated JPEG writer to downsample chroma channels
|
1.14 (2020-02-02) updated JPEG writer to downsample chroma channels
|
||||||
1.13
|
1.13
|
||||||
1.12
|
1.12
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user