convert for usage with libusefull_macros v0.3.2

This commit is contained in:
Edward Emelianov 2025-04-16 09:21:34 +03:00
parent 34de5183c9
commit 97a0366582
12 changed files with 301 additions and 248 deletions

View File

@ -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}")

View File

@ -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

View File

@ -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);

View File

@ -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");

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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);
} }
/* /*

View File

@ -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>

View File

@ -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,9 +4244,20 @@ 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) {
@ -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,29 +4650,56 @@ 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)
{ {
int bytes = (depth == 16? 2 : 1); int bytes = (depth == 16 ? 2 : 1);
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,189 +4723,137 @@ 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");
// Allocate two scan lines worth of filter workspace buffer.
filter_buf = (stbi_uc *) stbi__malloc_mad2(img_width_bytes, 2, 0);
if (!filter_buf) return stbi__err("outofmem", "Out of memory");
// Filtering for low-bit-depth images
if (depth < 8) {
filter_bytes = 1;
width = img_width_bytes;
}
for (j=0; j < y; ++j) { for (j=0; j < y; ++j) {
stbi_uc *cur = a->out + stride*j; // cur/prior filter buffers alternate
stbi_uc *prior; 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++; int filter = *raw++;
if (filter > 4) // check filter type
return stbi__err("invalid filter","Corrupt PNG"); if (filter > 4) {
all_ok = stbi__err("invalid filter","Corrupt PNG");
if (depth < 8) { break;
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;
width = img_width_bytes;
} }
prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above
// 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:
case STBI__F_none : cur[k] = raw[k]; break; memcpy(cur, raw, nk);
case STBI__F_sub : cur[k] = raw[k]; break; break;
case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; case STBI__F_sub:
case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; memcpy(cur, raw, filter_bytes);
case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break; for (k = filter_bytes; k < nk; ++k)
case STBI__F_avg_first : cur[k] = raw[k]; break; cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]);
case STBI__F_paeth_first: cur[k] = raw[k]; break; break;
} case STBI__F_up:
for (k = 0; k < nk; ++k)
cur[k] = STBI__BYTECAST(raw[k] + prior[k]);
break;
case STBI__F_avg:
for (k = 0; k < filter_bytes; ++k)
cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1));
for (k = filter_bytes; k < nk; ++k)
cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1));
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;
} }
if (depth == 8) { raw += nk;
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 // expand decoded bits in cur to dest, also adding an extra alpha channel if desired
if (depth < 8 || img_n == out_n) { if (depth < 8) {
int nk = (width - 1)*filter_bytes;
#define STBI__CASE(f) \
case f: \
for (k=0; k < nk; ++k)
switch (filter) {
// "none" filter turns into a memcpy here; make that explicit.
case STBI__F_none: memcpy(cur, raw, nk); break;
STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_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-filter_bytes])>>1)); } break;
STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break;
STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break;
STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break;
}
#undef STBI__CASE
raw += nk;
} else {
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 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;
// note that the final byte might overshoot and write more data than desired. // expand bits to bytes first
// 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) { if (depth == 4) {
for (k=x*img_n; k >= 2; k-=2, ++in) { for (i=0; i < nsmp; ++i) {
*cur++ = scale * ((*in >> 4) ); if ((i & 1) == 0) inb = *in++;
*cur++ = scale * ((*in ) & 0x0f); *out++ = scale * (inb >> 4);
inb <<= 4;
} }
if (k > 0) *cur++ = scale * ((*in >> 4) );
} else if (depth == 2) { } else if (depth == 2) {
for (k=x*img_n; k >= 4; k-=4, ++in) { for (i=0; i < nsmp; ++i) {
*cur++ = scale * ((*in >> 6) ); if ((i & 3) == 0) inb = *in++;
*cur++ = scale * ((*in >> 4) & 0x03); *out++ = scale * (inb >> 6);
*cur++ = scale * ((*in >> 2) & 0x03); inb <<= 2;
*cur++ = scale * ((*in ) & 0x03);
} }
if (k > 0) *cur++ = scale * ((*in >> 6) ); } else {
if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03); STBI_ASSERT(depth == 1);
if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03); for (i=0; i < nsmp; ++i) {
} else if (depth == 1) { if ((i & 7) == 0) inb = *in++;
for (k=x*img_n; k >= 8; k-=8, ++in) { *out++ = scale * (inb >> 7);
*cur++ = scale * ((*in >> 7) ); inb <<= 1;
*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 values if desired
// insert alpha = 255 if (img_n != out_n)
cur = a->out + stride*j; 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 {
STBI_ASSERT(img_n+1 == out_n);
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) {
*cur16 = (cur[0] << 8) | cur[1];
}
} }
STBI_FREE(filter_buf);
if (!all_ok) return 0;
return 1; return 1;
} }

View File

@ -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
@ -296,25 +297,25 @@ STBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned in
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)
{ {
return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL);
} }
#endif #endif
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
f = _wfopen(wFilename, wMode); f = _wfopen(wFilename, wMode);
#endif #endif
@ -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)
{ {
int pad = (-x*3) & 3; if (comp != 4) {
return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad, // write RGB bitmap
"11 4 22 4" "4 44 22 444444", int pad = (-x*3) & 3;
'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad,
40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header "11 4 22 4" "4 44 22 444444",
'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
} 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
@ -1635,7 +1669,7 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const
add HDR output add HDR output
fix monochrome BMP fix monochrome BMP
0.95 (2014-08-17) 0.95 (2014-08-17)
add monochrome TGA output add monochrome TGA output
0.94 (2014-05-31) 0.94 (2014-05-31)
rename private functions to avoid conflicts with stb_image.h rename private functions to avoid conflicts with stb_image.h
0.93 (2014-05-27) 0.93 (2014-05-27)