first - simplest - actions

This commit is contained in:
Edward Emelianov 2023-03-28 17:25:53 +03:00
parent 1ca485bafe
commit 349d2616e3
22 changed files with 11852 additions and 0 deletions

86
CMakeLists.txt Normal file
View File

@ -0,0 +1,86 @@
cmake_minimum_required(VERSION 3.20)
set(PROJ improc)
set(MINOR_VERSION "1")
set(MID_VERSION "0")
set(MAJOR_VERSION "0")
set(VERSION "${MAJOR_VERSION}.${MID_VERSION}.${MINOR_VERSION}")
project(${PROJ} VERSION ${VERSION} LANGUAGES C)
message("VERSION: ${VERSION}")
# list of options
option(DEBUG "Compile in debug mode" OFF)
option(EXAMPLES "Compile also all examples" ON)
# default flags
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -W -Wextra -std=gnu99")
set(CMAKE_COLOR_MAKEFILE ON)
# here is one of two variants: all .c in directory or .c files in list
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} SOURCES)
# cmake -DDEBUG=yes -> debugging
if(DEBUG)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Og -g3 -ggdb -fno-builtin-strlen -Werror")
add_definitions(-DEBUG)
set(CMAKE_BUILD_TYPE DEBUG)
set(CMAKE_VERBOSE_MAKEFILE "ON")
else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -march=native -fdata-sections -ffunction-sections")
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
set(CMAKE_BUILD_TYPE RELEASE)
endif()
message("Build type: ${CMAKE_BUILD_TYPE}")
###### pkgconfig ######
# pkg-config modules (for pkg-check-modules)
set(MODULES usefull_macros)
# find packages:
find_package(PkgConfig REQUIRED)
pkg_check_modules(${PROJ} REQUIRED ${MODULES})
# external modules like OpenMP:
include(FindOpenMP)
if(OPENMP_FOUND)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
add_definitions(-DOMP_FOUND)
endif()
###### additional flags ######
#list(APPEND ${PROJ}_LIBRARIES "-lfftw3_threads")
# library
add_library(${PROJ} SHARED ${SOURCES})
# library header files
set(LIBHEADER "usefull_macros.h")
# -I
include_directories(${${PROJ}_INCLUDE_DIRS})
# -L
link_directories(${${PROJ}_LIBRARY_DIRS})
# -D
add_definitions(-D_XOPEN_SOURCE=1234 -D_DEFAULT_SOURCE -D_GNU_SOURCE -DPACKAGE_VERSION=\"${VERSION}\"
-DMINOR_VERSION=\"${MINOR_VERSION}\" -DMID_VERSION=\"${MID_VERSION}\"
-DMAJOR_VERSION=\"${MAJOR_VESION}\")
# -l
target_link_libraries(${PROJ} ${${PROJ}_LIBRARIES} -lm)
set(PCFILE "${CMAKE_BINARY_DIR}/${PROJ}.pc")
configure_file("${PROJ}.pc.in" ${PCFILE} @ONLY)
set_target_properties(${PROJ} PROPERTIES VERSION ${VERSION})
set_target_properties(${PROJ} PROPERTIES PUBLIC_HEADER ${LIBHEADER})
# Installation of the program
include(GNUInstallDirs)
install(TARGETS ${PROJ} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(FILES ${PCFILE} DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig)
# EXAMPLES
if(EXAMPLES)
add_subdirectory(examples)
endif()

295
draw.c Normal file
View File

@ -0,0 +1,295 @@
/*
* This file is part of the loccorr project.
* Copyright 2021 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// simplest interface to draw lines & ellipses
#include <usefull_macros.h>
#include <math.h>
#include <stdio.h>
#include "improclib.h"
#include "openmp.h"
// base colors:
const uint8_t
ilColor_red[3] = {255, 0, 0},
ilColor_green[3] = {0, 255, 0},
ilColor_blue[3] = {0, 0, 255},
ilColor_black[3] = {0, 0, 0},
ilColor_white[3] = {255,255,255};
ilImg3 *ilImg3_new(int w, int h){
if(w < 1 || h < 1) return NULL;
ilImg3 *o = MALLOC(ilImg3, 1);
if(!o) return NULL;
o->data = MALLOC(uint8_t, 3*w*h);
if(!o->data){
FREE(o);
return NULL;
}
o->width = w;
o->height = h;
return o;
}
void ilImg3_free(ilImg3 **I){
if(!I || !*I) return;
FREE((*I)->data);
FREE(*I);
}
ilPattern *ilPattern_new(int w, int h){
if(w < 1 || h < 1) return NULL;
ilPattern *o = MALLOC(ilPattern, 1);
if(!o) return NULL;
o->data = MALLOC(uint8_t, w*h);
if(!o->data){
FREE(o);
return NULL;
}
o->width = w;
o->height = h;
return o;
}
void ilPattern_free(ilPattern **I){
if(!I || !*I) return;
FREE((*I)->data);
FREE(*I);
}
// make a single-channel (opaque) mask for cross; allocated here!!!
ilPattern *ilPattern_cross(int w, int h){
int hmid = h/2, wmid = w/2;
ilPattern *p = ilPattern_new(w, h);
if(!p) return NULL;
uint8_t *ptr = &p->data[wmid];
for(int y = 0; y < h; ++y, ptr += w) *ptr = 255;
ptr = &p->data[hmid*w];
for(int x = 0; x < w; ++x, ++ptr) *ptr = 255;
return p;
}
// complicated cross
ilPattern *ilPattern_xcross(int w, int h){
int hmid = h/2, wmid = w/2;
ilPattern *p = ilPattern_new(w, h);
if(!p) return NULL;
uint8_t *data = p->data;
data[hmid*w + wmid] = 255; // point @ center
if(h < 7 || w < 7) return p;
int idxy1 = (hmid-3)*w, idxy2 = (hmid+3)*w;
int idxx1 = wmid-3, idxx2 = wmid+3;
for(int i = 0; i < wmid - 3; ++i){
data[idxy1+i] = data[idxy1+w-1-i] = 255;
data[idxy2+i] = data[idxy2+w-1-i] = 255;
}
for(int i = 0; i < hmid - 3; ++i){
data[idxx1 + i*w] = data[idxx1 + (h-1-i)*w] = 255;
data[idxx2 + i*w] = data[idxx2 + (h-1-i)*w] = 255;
}
return p;
}
#define DRAW_star(type, max) \
OMP_FOR() \
for(int y = 0; y < h; ++y){ \
double ry2 = (double)(y-h2); \
ry2 *= ry2; \
type *data = &((type*)(p->data))[y*w]; \
for(int x = 0; x < w; ++x, ++data){ \
double rx = (double)(x-w2); \
double Intens = max * pow(1. + (rx*rx + ry2)/theta2, -beta); \
*data = (type) Intens; \
} \
}
/**
* @brief ilPattern_star - create pseudo-star Moffat pattern with max ampl. 255 and given FWHM
* @param w - width
* @param h - height
* @param fwhm - FWHM
* @param beta - `beta` parameter of Moffat
* @return pattern or NULL if error
*/
ilPattern *ilPattern_star(int w, int h, double fwhm, double beta){
if(fwhm < 1.) return NULL;
ilPattern *p = ilPattern_new(w, h);
if(!p) return NULL;
int w2 = w/2, h2 = h/2; // center of image
double hwhm = fwhm / 2., theta2 = hwhm*hwhm;
DRAW_star(uint8_t, 255.);
return p;
}
/**
* @brief ilImage_star - generate subimage with 'star'; max amplitude for float and double == 1.
* @param type - image type
* @param w - image width
* @param h - height
* @param fwhm - 'star' FWHM
* @param beta - beta parameter
* @return
*/
ilImage *ilImage_star(ilimtype_t type, int w, int h, double fwhm, double beta){
if(fwhm < 1.) return NULL;
ilImage *p = ilImage_new(w, h, type);
if(!p) return NULL;
int w2 = w/2, h2 = h/2;
double hwhm = fwhm / 2., theta2 = hwhm*hwhm;
switch(type){
case IMTYPE_U8:
DRAW_star(uint8_t, UINT8_MAX);
break;
case IMTYPE_U16:
DRAW_star(uint16_t, UINT16_MAX);
break;
case IMTYPE_U32:
DRAW_star(uint32_t, UINT32_MAX);
break;
case IMTYPE_F:
DRAW_star(float, 1.);
break;
case IMTYPE_D:
DRAW_star(double, 1.);
break;
default:
ERRX("ilImage_star(): wrong image type");
}
return p;
}
/**
* @brief ilPattern_draw3 - draw pattern @ 3-channel image
* @param img (io) - image
* @param p (i) - the pattern
* @param xc, yc - coordinates of pattern center @ image
* @param color - color to draw pattern (when opaque == 255)
*/
void ilPattern_draw3(ilImg3 *img, const ilPattern *p, int xc, int yc, const uint8_t color[3]){
if(!img || !p) return;
int xul = xc - p->width/2, yul = yc - p->height/2;
int xdr = xul+p->width-1, ydr = yul+p->height-1;
int R = img->width, D = img->height; // right and down border coordinates + 1
if(ydr < 0 || xdr < 0 || xul > R-1 || yul > D-1) return; // box outside of image
int oxlow, oxhigh, oylow, oyhigh; // output limit coordinates
int ixlow, iylow; // intput limit coordinates
if(xul < 0){
oxlow = 0; ixlow = -xul;
}else{
oxlow = xul; ixlow = 0;
}
if(yul < 0){
oylow = 0; iylow = -yul;
}else{
oylow = yul; iylow = 0;
}
if(xdr < R){
oxhigh = xdr;
}else{
oxhigh = R;
}
if(ydr < D){
oyhigh = ydr;
}else{
oyhigh = D;
}
OMP_FOR()
for(int y = oylow; y < oyhigh; ++y){
uint8_t *in = &p->data[(iylow+y-oylow)*p->width + ixlow]; // opaque component
uint8_t *out = &img->data[(y*img->width + oxlow)*3]; // 3-colours
for(int x = oxlow; x < oxhigh; ++x, ++in, out += 3){
float opaque = ((float)*in)/255.;
for(int c = 0; c < 3; ++c){
out[c] = (uint8_t)(color[c] * opaque + out[c]*(1.-opaque));
}
}
}
}
#define ADD_subim(type, max) \
OMP_FOR() \
for(int y = oylow; y < oyhigh; ++y){ \
type *in = &((type*)(p->data))[(iylow+y-oylow)*p->width + ixlow]; \
type *out = &((type*)(img->data))[y*img->width + oxlow]; \
for(int x = oxlow; x < oxhigh; ++x, ++in, ++out){ \
double res = *in * weight + *out; \
if(max && res > max) res = max; \
*out = (type)res; \
} \
}
/**
* @brief iladd_subimage - draw subimage over given image (by sum)
* @param img (io) - image
* @param p (i) - subimage
* @param xc, yc - coordinates of pattern center @ image
* @param weight - img = img + p*weight
*/
void iladd_subimage(ilImage *img, const ilImage *p, int xc, int yc, double weight){
if(!img || !p) return;
if(img->type != p->type){
WARNX("iladd_subimage(): types of image and subimage must match");
return;
}
int xul = xc - p->width/2, yul = yc - p->height/2;
int xdr = xul+p->width-1, ydr = yul+p->height-1;
int R = img->width, D = img->height; // right and down border coordinates + 1
if(ydr < 0 || xdr < 0 || xul > R-1 || yul > D-1) return; // box outside of image
int oxlow, oxhigh, oylow, oyhigh; // output limit coordinates
int ixlow, iylow; // intput limit coordinates
if(xul < 0){
oxlow = 0; ixlow = -xul;
}else{
oxlow = xul; ixlow = 0;
}
if(yul < 0){
oylow = 0; iylow = -yul;
}else{
oylow = yul; iylow = 0;
}
if(xdr < R){
oxhigh = xdr;
}else{
oxhigh = R;
}
if(ydr < D){
oyhigh = ydr;
}else{
oyhigh = D;
}
switch(img->type){
case IMTYPE_U8:
ADD_subim(uint8_t, UINT8_MAX);
break;
case IMTYPE_U16:
ADD_subim(uint16_t, UINT16_MAX);
break;
case IMTYPE_U32:
ADD_subim(uint32_t, UINT32_MAX);
break;
case IMTYPE_F:
ADD_subim(float, 0);
break;
case IMTYPE_D:
ADD_subim(double, 0);
break;
default:
ERRX("iladd_subimage(): wrong image type");
}
}

11
examples/CMakeLists.txt Normal file
View File

@ -0,0 +1,11 @@
cmake_minimum_required(VERSION 3.20)
project(examples)
# common includes & library
include_directories(../)
link_libraries(usefull_macros improc m)
# exe list
add_executable(equalize equalize.c)
add_executable(generate generate.c)
add_executable(genu16 genu16.c)

19
examples/Readme.md Normal file
View File

@ -0,0 +1,19 @@
Examples
========
## equalize
Open given image file as 1-channel uint8_t, equalize histogram, plot two crosses (red at 30,30 and green at 150,50) ans save as output.jpg
## generate
Generate pseudo-star images with given Moffat parameters at given coordinates xi,yi (with amplitude ampi, ampi < 256)
Usage: %s [args] x1,y1[,amp1] x2,y2[,amp2] ... xn,yn[,amp3]
args:
- w - resulting image width (default: 1024)
- h - resulting image height (default: 1024)
- o - output file name (default: output.jpg)
- s - FWHM of 'star' images (default: 3.5)
- b - beta Moffat parameter of 'star' images (default: 1)
## genu16
The same as 'generate', but works with 16-bit image and save it as 1-channel png (`ampi` now is weight).

50
examples/equalize.c Normal file
View File

@ -0,0 +1,50 @@
/*
* This file is part of the improclib project.
* Copyright 2023 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "improclib.h"
#include <stdio.h>
#include <usefull_macros.h>
int main(int argc, char **argv){
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]);
return 1;
}
ilImage *I = ilImage_read(argv[1]);
if(!I){
fprintf(stderr, "Can't read %s\n", argv[1]);
return 2;
}
int w = I->width, h = I->height;
uint8_t *eq = ilequalize8(I, 3, 0.1);
ilImage_free(&I);
if(!eq) return 3;
ilImg3 *I3 = MALLOC(ilImg3, 1);
I3->data = eq;
I3->height = h;
I3->width = w;
ilPattern *cross = ilPattern_xcross(25, 25);
ilPattern_draw3(I3, cross, 30, 30, ilColor_red);
ilPattern_draw3(I3, cross, 150, 50, ilColor_green);
ilPattern_free(&cross);
int ret = ilImg3_jpg("output.jpg", I3, 95);
ilImg3_free(&I3);
if(!ret) return 4;
printf("File 'output.jpg' ready\n");
return 0;
}

103
examples/generate.c Normal file
View File

@ -0,0 +1,103 @@
/*
* This file is part of the improclib project.
* Copyright 2023 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "improclib.h"
#include <usefull_macros.h>
#include <stdio.h>
#include <string.h>
static int w = 1024, h = 1024, help = 0;
static double fwhm = 3.5, beta = 1.;
static char *outp = "output.jpg", *inp = NULL;
static ilPattern *star = NULL, *cross = NULL;
static myoption cmdlnopts[] = {
{"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)"},
{"height", NEED_ARG, NULL, 'h', arg_int, APTR(&h), "resulting image height (default: 1024)"},
{"output", NEED_ARG, NULL, 'o', arg_string, APTR(&outp), "output file name (default: output.jpg)"},
{"halfwidth",NEED_ARG, NULL, 's', arg_double, APTR(&fwhm), "FWHM of 'star' images (default: 3.5)"},
{"beta", NEED_ARG, NULL, 'b', arg_double, APTR(&beta), "beta Moffat parameter of 'star' images (default: 1)"},
{"input", NEED_ARG, NULL, 'i', arg_string, APTR(&inp), "input file with coordinates and amplitudes (comma separated)"},
end_option
};
static int getpars(const char *argv, int *x, int *y, int *a){
char *eptr, *start = (char*)argv;
long l;
l = strtol(start, &eptr, 0);
if(eptr == start || *eptr != ',' || l < 0 || l > INT_MAX) return FALSE;
*x = (int)l;
start = eptr + 1;
l = strtol(start, &eptr, 0);
if(eptr == start || l < 0 || l > INT_MAX) return FALSE;
*y = (int)l;
if(*eptr == ','){
start = eptr + 1;
l = strtol(start, &eptr, 0);
if(eptr == start || l < 0 || l > 255) return FALSE;
*a = (int)l;
}else *a = 255;
return TRUE;
}
static void addstar(ilImg3 *I, const char *str){
int x, y, a;
if(!getpars(str, &x, &y, &a)) return;
printf("Add 'star' at %d,%d (ampl=%d)\n", x,y,a);
uint8_t c[3] = {a,a,a};
ilPattern_draw3(I, star, x, y, c);
ilPattern_draw3(I, cross, x, y, ilColor_red);
}
static void addfromfile(ilImg3 *I){
FILE *f = fopen(inp, "r");
if(!f){
WARN("Can't open %s", inp);
return;
}
char *line = NULL;
size_t n = 0;
while(getline(&line, &n, f) > 0) addstar(I, line);
fclose(f);
}
int main(int argc, char **argv){
initial_setup();
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);
parseargs(&argc, &argv, cmdlnopts);
if(help) showhelp(-1, cmdlnopts);
if(w < 1 || h < 1) ERRX("Wrong image size");
if(argc == 0 && inp == NULL) ERRX("Point at least one coordinate pair or file name");
ilImg3 *I = ilImg3_new(w, h);
if(!I) ERRX("Can't create image %dx%d pixels", w, h);
int par = (int)(fwhm*25.);
star = ilPattern_star(par, par, fwhm, beta);
cross = ilPattern_xcross(25, 25);
for(int i = 0; i < argc; ++i) addstar(I, argv[i]);
if(inp) addfromfile(I);
ilPattern_free(&star);
int ret = ilImg3_jpg(outp, I, 95);
//int ret = ilImg3_png(outp, I);
ilImg3_free(&I);
if(!ret) return 4;
printf("File %s ready\n", outp);
return 0;
}

112
examples/genu16.c Normal file
View File

@ -0,0 +1,112 @@
/*
* This file is part of the improclib project.
* Copyright 2023 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "improclib.h"
#include <usefull_macros.h>
#include <stdio.h>
#include <string.h>
static int w = 1024, h = 1024, help = 0;
static double fwhm = 3.5, beta = 1.;
static char *outp = "output.png", *inp = NULL;
static ilImage *star = NULL;
static myoption cmdlnopts[] = {
{"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)"},
{"height", NEED_ARG, NULL, 'h', arg_int, APTR(&h), "resulting image height (default: 1024)"},
{"output", NEED_ARG, NULL, 'o', arg_string, APTR(&outp), "output file name (default: output.png)"},
{"halfwidth",NEED_ARG, NULL, 's', arg_double, APTR(&fwhm), "FWHM of 'star' images (default: 3.5)"},
{"beta", NEED_ARG, NULL, 'b', arg_double, APTR(&beta), "beta Moffat parameter of 'star' images (default: 1)"},
{"input", NEED_ARG, NULL, 'i', arg_string, APTR(&inp), "input file with coordinates and amplitudes (comma separated)"},
end_option
};
static int getpars(const char *argv, int *x, int *y, double *w){
char *eptr, *start = (char*)argv;
long l;
l = strtol(start, &eptr, 0);
if(eptr == start || *eptr != ',' || l < 0 || l > INT_MAX) return FALSE;
*x = (int)l;
start = eptr + 1;
l = strtol(start, &eptr, 0);
if(eptr == start || l < 0 || l > INT_MAX) return FALSE;
*y = (int)l;
if(*eptr == ','){
start = eptr + 1;
double d = strtod(start, &eptr);
if(eptr == start) return FALSE;
*w = d;
}else *w = 1.;
return TRUE;
}
static void addstar(ilImage *I, const char *str){
int x, y;
double w;
if(!getpars(str, &x, &y, &w)) return;
printf("Add 'star' at %d,%d (weight=%g)\n", x,y,w);
iladd_subimage(I, star, x, y, w);
}
static void addfromfile(ilImage *I){
FILE *f = fopen(inp, "r");
if(!f){
WARN("Can't open %s", inp);
return;
}
char *line = NULL;
size_t n = 0;
while(getline(&line, &n, f) > 0) addstar(I, line);
fclose(f);
}
int main(int argc, char **argv){
initial_setup();
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);
parseargs(&argc, &argv, cmdlnopts);
if(help) showhelp(-1, cmdlnopts);
if(w < 1 || h < 1) ERRX("Wrong image size");
if(argc == 0 && inp == NULL) ERRX("Point at least one coordinate pair or file name");
ilImage *I = ilImage_new(w, h, IMTYPE_U16);
if(!I) ERRX("Can't create image %dx%d pixels", w, h);
int par = (int)(fwhm*25.);
star = ilImage_star(IMTYPE_U16, par, par, fwhm, beta);
if(!star) ERRX("Can't create 'star' pattern");
for(int i = 0; i < argc; ++i) addstar(I, argv[i]);
if(inp) addfromfile(I);
ilImage_free(&star);
ilImage_putstring(I, "Hello, world!!", -10, 10);
ilImage_putstring(I, "0", 0, 1016);
ilImage_putstring(I, "Hello, world.!?\"'\nMore again", 50, 500);
ilImage_putstring(I, "Hello, world!", 950, 1018);
for(int _ = 0; _ < 1024; _ += 50){
char s[6];
snprintf(s, 6, "%d", _);
ilImage_putstring(I, s, _, 300);
}
uint8_t *bytes = ilImage2u8(I, 1);
int ret = ilwrite_png(outp, I->width, I->height, 1, bytes);
ilImage_free(&I);
FREE(bytes);
if(!ret) return 4;
printf("File %s ready\n", outp);
return 0;
}

937
imagefile.c Normal file
View File

@ -0,0 +1,937 @@
/*
* This file is part of the improclib project.
* Copyright 2023 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "stb/stb_image.h"
#include "stb/stb_image_write.h"
#include "improclib.h"
#include "openmp.h"
typedef struct{
const char signature[8];
uint8_t len;
ilInputType it;
} imsign;
const imsign signatures[] = {
{"BM", 2, T_BMP},
{"SIMPLE", 6, T_FITS},
{{0x1f, 0x8b, 0x08}, 3, T_GZIP},
{"GIF8", 4, T_GIF},
{{0xff, 0xd8, 0xff, 0xdb}, 4, T_JPEG},
{{0xff, 0xd8, 0xff, 0xe0}, 4, T_JPEG},
{{0xff, 0xd8, 0xff, 0xe1}, 4, T_JPEG},
{{0x89, 0x50, 0x4e, 0x47}, 4, T_PNG},
// {{0x49, 0x49, 0x2a, 0x00}, 4, T_TIFF},
{"", 0, T_WRONG}
};
#ifdef EBUG
static char *hexdmp(const char sig[8]){
static char buf[128];
char *bptr = buf;
bptr += sprintf(bptr, "[ ");
for(int i = 0; i < 7; ++i){
bptr += sprintf(bptr, "%02X ", (uint8_t)sig[i]);
}
bptr += sprintf(bptr, "]");
return buf;
}
#endif
const int bytes[IMTYPE_AMOUNT] = {
[IMTYPE_U8] = 1,
[IMTYPE_U16] = 2,
[IMTYPE_U32] = 4,
[IMTYPE_F] = sizeof(float),
[IMTYPE_D] = sizeof(double)
};
// return amount of bytes per pixel for given image type
int ilgetpixbytes(ilimtype_t type){
if(type >= IMTYPE_AMOUNT) return -1;
return bytes[type];
}
/**
* @brief imtype - check image type of given file
* @param f - opened image file structure
* @return image type or T_WRONG
*/
static ilInputType imtype(FILE *f){
char signature[8];
int x = fread(signature, 1, 7, f);
DBG("x=%d", x);
if(7 != x){
WARN("Can't read file signature");
return T_WRONG;
}
signature[7] = 0;
const imsign *s = signatures;
DBG("Got signature: %s (%s)", hexdmp(signature), signature);
while(s->len){
DBG("Check %s", s->signature);
if(0 == memcmp(s->signature, signature, s->len)){
DBG("Found signature %s", s->signature);
return s->it;
}
++s;
}
return T_WRONG;
}
/**
* @brief ilchkinput - check file/directory name
* @param name - name of file or directory
* @return type of `name`
*/
ilInputType ilchkinput(const char *name){
DBG("input name: %s", name);
struct stat fd_stat;
stat(name, &fd_stat);
if(S_ISDIR(fd_stat.st_mode)){
DBG("%s is a directory", name);
DIR *d = opendir(name);
if(!d){
WARN("Can't open directory %s", name);
return T_WRONG;
}
closedir(d);
return T_DIRECTORY;
}
FILE *f = fopen(name, "r");
if(!f){
WARN("Can't open file %s", name);
return T_WRONG;
}
ilInputType tp = imtype(f);
DBG("Image type of %s is %d", name, tp);
fclose(f);
return tp;
}
/**
* @brief ilu8toImage - convert uint8_t data to Image structure
* @param data - original image data
* @param width - image width
* @param height - image height
* @param stride - image width with alignment
* @return Image structure (fully allocated, you can FREE(data) after it)
*/
ilImage *ilu8toImage(const uint8_t *data, int width, int height){
FNAME();
ilImage *outp = ilImage_new(width, height, IMTYPE_U8);
memcpy(outp->data, data, width*height);
ilImage_minmax(outp);
return outp;
}
/**
* @brief im_loadmono - load image file
* @param name - filename
* @return Image structure or NULL
*/
static inline ilImage *im_loadmono(const char *name){
int width, height, channels;
uint8_t *img = stbi_load(name, &width, &height, &channels, 1);
if(!img){
WARNX("Error in loading the image %s\n", name);
return NULL;
}
ilImage *I = MALLOC(ilImage, 1);
I->data = img;
I->width = width;
I->height = height;
I->type = IMTYPE_U8;
I->pixbytes = 1;
ilImage_minmax(I);
return I;
}
/**
* @brief ilImage_read - read image from any supported file type
* @param name - path to image
* @return image or NULL if failed
*/
ilImage *ilImage_read(const char *name){
ilInputType tp = ilchkinput(name);
if(tp == T_DIRECTORY || tp == T_WRONG){
WARNX("Bad file type to read");
return NULL;
}
ilImage *outp = im_loadmono(name);
return outp;
}
/**
* @brief ilImg3_read - read color image from file 'name'
* @param name - input file name
* @return image read or NULL if error
*/
ilImg3 *ilImg3_read(const char *name){
ilInputType tp = ilchkinput(name);
if(tp == T_DIRECTORY || tp == T_WRONG){
WARNX("Bad file type to read");
return NULL;
}
ilImg3 *I = MALLOC(ilImg3, 1);
int channels;
I->data = stbi_load(name, &I->width, &I->height, &channels, 3);
if(!I->data){
FREE(I);
return NULL;
}
return I;
}
/**
* @brief ilImage_new - allocate memory for new struct Image & Image->data
* @param w, h - image size
* @return data allocated here
*/
ilImage *ilImage_new(int w, int h, ilimtype_t type){
if(w < 1 || h < 1) return NULL;
if(type >= IMTYPE_AMOUNT) return NULL;
ilImage *o = MALLOC(ilImage, 1);
o->width = w;
o->height = h;
o->type = type;
o->pixbytes = ilgetpixbytes(type);
o->data = calloc(w*h, o->pixbytes);
if(!o->data) ERR("calloc()");
return o;
}
/**
* @brief ilImage_sim - allocate memory for new empty Image with similar size & data type
* @param i - sample image
* @return data allocated here (with empty keylist & zeros in data)
*/
ilImage *ilImage_sim(const ilImage *i){
if(!i) return NULL;
ilImage *outp = ilImage_new(i->width, i->height, i->type);
return outp;
}
// free image data
void ilImage_free(ilImage **img){
if(!img || !*img) return;
FREE((*img)->data);
FREE(*img);
}
/**
* @brief ilhistogram8 - calculate image histogram for 8-bit image
* @param I - orig
* @return 256 byte array
*/
size_t *ilhistogram8(const ilImage *I){
if(!I || !I->data || I->type != IMTYPE_U8) return NULL;
size_t *histogram = MALLOC(size_t, 256);
int wh = I->width * I->height;
uint8_t *data = (uint8_t*)I->data;
#pragma omp parallel
{
size_t histogram_private[256] = {0};
#pragma omp for nowait
for(int i = 0; i < wh; ++i){
++histogram_private[data[i]];
}
#pragma omp critical
{
for(int i = 0; i < 256; ++i) histogram[i] += histogram_private[i];
}
}
return histogram;
}
/**
* @brief ilhistogram16 - calculate image histogram for 16-bit image
* @param I - orig
* @return 65536 byte array
*/
size_t *ilhistogram16(const ilImage *I){
if(!I || !I->data || I->type != IMTYPE_U16) return NULL;
size_t *histogram = MALLOC(size_t, 65536);
int wh = I->width * I->height;
uint16_t *data = (uint16_t*)I->data;
#pragma omp parallel
{
size_t histogram_private[65536] = {0};
#pragma omp for nowait
for(int i = 0; i < wh; ++i){
++histogram_private[data[i]];
}
#pragma omp critical
{
for(int i = 0; i < 65536; ++i) histogram[i] += histogram_private[i];
}
}
return histogram;
}
/**
* @brief calc_background - Simple background calculation by histogram
* @param img (i) - input image (here will be modified its top2proc field)
* @param bk (o) - background value
* @return 0 if error
*/
int ilImage_background(ilImage *img, double *bkg){
if(!img || !img->data || !bkg) return FALSE;
ilImage_minmax(img);
if(img->maxval == img->minval){
WARNX("Zero or overilluminated image!");
return FALSE;
}
size_t *histogram = NULL;
int histosize = 0;
switch(img->type){
case IMTYPE_U8:
histogram = ilhistogram8(img);
histosize = 256;
break;
case IMTYPE_U16:
histogram = ilhistogram16(img);
histosize = 65536;
break;
default:
break;
}
if(!histogram){
WARNX("calc_background() supported only 8- and 16-bit images");
return FALSE;
}
size_t modeidx = 0, modeval = 0;
for(int i = 0; i < histosize; ++i)
if(modeval < histogram[i]){
modeval = histogram[i];
modeidx = i;
}
//DBG("Mode=%g @ idx%d (N=%d)", ((Imtype)modeidx / 255.)*ampl, modeidx, modeval);
ssize_t *diff2 = MALLOC(ssize_t, histosize);
int lastidx = histosize - 1;
OMP_FOR()
for(int i = 2; i < lastidx; ++i)
diff2[i] = (histogram[i+2]+histogram[i-2]-2*histogram[i])/4;
//green("HISTO:\n");
//for(int i = 0; i < 256; ++i) printf("%d:\t%d\t%d\n", i, histogram[i], diff2[i]);
FREE(histogram);
if(modeidx < 2) modeidx = 2;
if((int)modeidx > lastidx-1){
WARNX("Overilluminated image");
FREE(diff2);
return FALSE; // very bad image: overilluminated
}
size_t borderidx = modeidx;
for(int i = modeidx; i < lastidx; ++i){ // search bend-point by second derivate
if(diff2[i] <= 0 && diff2[i+1] <= 0){
borderidx = i; break;
}
}
//DBG("borderidx=%d -> %d", borderidx, (borderidx+modeidx)/2);
//*bk = (borderidx + modeidx) / 2;
*bkg = borderidx;
FREE(diff2);
return TRUE;
}
// transformation functions for Im2u8
#define TRANSMACRO(datatype) \
int height = I->height, width = I->width, stride = width * nchannels; \
uint8_t *outp = MALLOC(uint8_t, height * stride); \
double min = I->minval, max = I->maxval, W = 255./(max - min); \
datatype *Idata = (datatype*) I->data; \
if(nchannels == 3){ \
OMP_FOR() \
for(int y = 0; y < height; ++y){ \
uint8_t *Out = &outp[y*stride]; \
datatype *In = &Idata[y*width]; \
for(int x = 0; x < width; ++x){ \
Out[0] = Out[1] = Out[2] = (uint8_t)(W*((double)(*In++) - min)); \
Out += 3; \
} \
} \
}else{ \
OMP_FOR() \
for(int y = 0; y < height; ++y){ \
uint8_t *Out = &outp[y*stride]; \
datatype *In = &Idata[y*width]; \
for(int x = 0; x < width; ++x){ \
*Out++ = (uint8_t)(W*((double)(*In++) - min)); \
} \
} \
}
static uint8_t *Iu8(const ilImage *I, int nchannels){
TRANSMACRO(uint8_t);
return outp;
}
static uint8_t *Iu16(const ilImage *I, int nchannels){
TRANSMACRO(uint16_t);
return outp;
}
static uint8_t *Iu32(const ilImage *I, int nchannels){
TRANSMACRO(uint32_t);
return outp;
}
static uint8_t *If(const ilImage *I, int nchannels){
TRANSMACRO(float);
return outp;
}
static uint8_t *Id(const ilImage *I, int nchannels){
TRANSMACRO(double);
return outp;
}
/**
* @brief ilImage2u8 - linear transform for preparing file to save as JPEG or other type
* @param I - input image
* @param nchannels - 1 or 3 colour channels
* @return allocated here image for jpeg/png storing
*/
uint8_t *ilImage2u8(ilImage *I, int nchannels){ // only 1 and 3 channels supported!
if(!I || !I->data || (nchannels != 1 && nchannels != 3)) return NULL;
ilImage_minmax(I);
//DBG("make linear transform %dx%d, %d channels", I->width, I->height, nchannels);
switch(I->type){
case IMTYPE_U8:
return Iu8(I, nchannels);
break;
case IMTYPE_U16:
return Iu16(I, nchannels);
break;
case IMTYPE_U32:
return Iu32(I, nchannels);
break;
case IMTYPE_F:
return If(I, nchannels);
break;
case IMTYPE_D:
return Id(I, nchannels);
break;
default:
WARNX("Im2u8: unsupported image type %d", I->type);
}
return NULL;
}
/**
* @brief equalize8 - 8bit image hystogram equalization
* @param I - input image
* @param nchannels - 1 or 3 colour channels
* @param throwpart - which part of black pixels (from all amount) to throw away
* @return allocated here image for jpeg/png storing
*/
uint8_t *ilequalize8(ilImage *I, int nchannels, double throwpart){
if(!I || !I->data || (nchannels != 1 && nchannels != 3)) return NULL;
ilImage_minmax(I);
int width = I->width, height = I->height;
size_t stride = width*nchannels, S = height*stride;
size_t *orig_histo = ilhistogram8(I); // original hystogram (linear)
if(!orig_histo) return NULL;
uint8_t *outp = MALLOC(uint8_t, S);
uint8_t eq_levls[256] = {0}; // levels to convert: newpix = eq_levls[oldpix]
int s = width*height;
int Nblack = 0, bpart = (int)(throwpart * (double)s);
int startidx;
// remove first part of black pixels
for(startidx = 0; startidx < 256; ++startidx){
Nblack += orig_histo[startidx];
if(Nblack >= bpart) break;
}
++startidx;
//DBG("Throw %d (real: %d black) pixels, startidx=%d", bpart, Nblack, startidx);
double part = (double)(s + 1. - Nblack) / 256., N = 0.;
for(int i = startidx; i < 256; ++i){
N += orig_histo[i];
eq_levls[i] = (uint8_t)(N/part);
}
//for(int i = stopidx; i < 256; ++i) eq_levls[i] = 255;
#if 0
DBG("Original / new histogram");
for(int i = 0; i < 256; ++i) printf("%d\t%d\t%d\n", i, orig_hysto[i], eq_levls[i]);
#endif
uint8_t *Idata = (uint8_t*)I->data;
if(nchannels == 3){
OMP_FOR()
for(int y = 0; y < height; ++y){
uint8_t *Out = &outp[y*stride];
uint8_t *In = &Idata[y*width];
for(int x = 0; x < width; ++x){
Out[0] = Out[1] = Out[2] = eq_levls[*In++];
Out += 3;
}
}
}else{
OMP_FOR()
for(int y = 0; y < height; ++y){
uint8_t *Out = &outp[y*width];
uint8_t *In = &Idata[y*width];
for(int x = 0; x < width; ++x){
*Out++ = eq_levls[*In++];
}
}
}
FREE(orig_histo);
return outp;
}
/**
* @brief equalize16 - 16bit image hystogram equalization
* @param I - input image
* @param nchannels - 1 or 3 colour channels
* @param throwpart - which part of black pixels (from all amount) to throw away
* @return allocated here image for jpeg/png storing
*/
uint8_t *ilequalize16(ilImage *I, int nchannels, double throwpart){
if(!I || !I->data || (nchannels != 1 && nchannels != 3)) return NULL;
ilImage_minmax(I);
int width = I->width, height = I->height;
size_t stride = width*nchannels, S = height*stride;
size_t *orig_histo = ilhistogram8(I); // original hystogram (linear)
if(!orig_histo) return NULL;
uint8_t *outp = MALLOC(uint8_t, S);
uint16_t *eq_levls = MALLOC(uint16_t, 65536); // levels to convert: newpix = eq_levls[oldpix]
int s = width*height;
int Nblack = 0, bpart = (int)(throwpart * (double)s);
int startidx;
// remove first part of black pixels
for(startidx = 0; startidx < 65536; ++startidx){
Nblack += orig_histo[startidx];
if(Nblack >= bpart) break;
}
++startidx;
//DBG("Throw %d (real: %d black) pixels, startidx=%d", bpart, Nblack, startidx);
double part = (double)(s + 1. - Nblack) / 65536., N = 0.;
for(int i = startidx; i < 65536; ++i){
N += orig_histo[i];
eq_levls[i] = (uint8_t)(N/part);
}
uint8_t *Idata = (uint8_t*)I->data;
if(nchannels == 3){
OMP_FOR()
for(int y = 0; y < height; ++y){
uint8_t *Out = &outp[y*stride];
uint8_t *In = &Idata[y*width];
for(int x = 0; x < width; ++x){
Out[0] = Out[1] = Out[2] = eq_levls[*In++];
Out += 3;
}
}
}else{
OMP_FOR()
for(int y = 0; y < height; ++y){
uint8_t *Out = &outp[y*width];
uint8_t *In = &Idata[y*width];
for(int x = 0; x < width; ++x){
*Out++ = eq_levls[*In++];
}
}
}
FREE(orig_histo);
FREE(eq_levls);
return outp;
}
static void u8minmax(ilImage *I){
uint8_t *data = (uint8_t*)I->data;
double min = *data, max = min;
int wh = I->width * I->height;
#pragma omp parallel shared(min, max)
{
double min_p = min, max_p = max;
#pragma omp for nowait
for(int i = 0; i < wh; ++i){
double pixval = (double)data[i];
if(pixval < min_p) min_p = pixval;
else if(pixval > max_p) max_p = pixval;
}
#pragma omp critical
{
if(min > min_p) min = min_p;
if(max < max_p) max = max_p;
}
}
I->maxval = max;
I->minval = min;
}
static void u16minmax(ilImage *I){
uint16_t *data = (uint16_t*)I->data;
double min = *data, max = min;
int wh = I->width * I->height;
#pragma omp parallel shared(min, max)
{
double min_p = min, max_p = max;
#pragma omp for nowait
for(int i = 0; i < wh; ++i){
double pixval = (double)data[i];
if(pixval < min_p) min_p = pixval;
else if(pixval > max_p) max_p = pixval;
}
#pragma omp critical
{
if(min > min_p) min = min_p;
if(max < max_p) max = max_p;
}
}
I->maxval = max;
I->minval = min;
}
static void u32minmax(ilImage *I){
uint32_t *data = (uint32_t*)I->data;
double min = *data, max = min;
int wh = I->width * I->height;
#pragma omp parallel shared(min, max)
{
double min_p = min, max_p = max;
#pragma omp for nowait
for(int i = 0; i < wh; ++i){
double pixval = (double)data[i];
if(pixval < min_p) min_p = pixval;
else if(pixval > max_p) max_p = pixval;
}
#pragma omp critical
{
if(min > min_p) min = min_p;
if(max < max_p) max = max_p;
}
}
I->maxval = max;
I->minval = min;
}
static void fminmax(ilImage *I){
float *data = (float*)I->data;
double min = *data, max = min;
int wh = I->width * I->height;
#pragma omp parallel shared(min, max)
{
double min_p = min, max_p = max;
#pragma omp for nowait
for(int i = 0; i < wh; ++i){
double pixval = (double)data[i];
if(pixval < min_p) min_p = pixval;
else if(pixval > max_p) max_p = pixval;
}
#pragma omp critical
{
if(min > min_p) min = min_p;
if(max < max_p) max = max_p;
}
}
I->maxval = max;
I->minval = min;
}
static void dminmax(ilImage *I){
double *data = (double*)I->data;
double min = *data, max = min;
int wh = I->width * I->height;
#pragma omp parallel shared(min, max)
{
double min_p = min, max_p = max;
#pragma omp for nowait
for(int i = 0; i < wh; ++i){
double pixval = (double)data[i];
if(pixval < min_p) min_p = pixval;
else if(pixval > max_p) max_p = pixval;
}
#pragma omp critical
{
if(min > min_p) min = min_p;
if(max < max_p) max = max_p;
}
}
I->maxval = max;
I->minval = min;
}
// calculate extremal values of image data and store them in it
void ilImage_minmax(ilImage *I){
if(!I || !I->data) return;
#ifdef EBUG
double t0 = dtime();
#endif
switch(I->type){
case IMTYPE_U8:
u8minmax(I);
break;
case IMTYPE_U16:
u16minmax(I);
break;
case IMTYPE_U32:
u32minmax(I);
break;
case IMTYPE_F:
fminmax(I);
break;
case IMTYPE_D:
dminmax(I);
break;
default:
return;
}
DBG("Image_minmax(): Min=%g, Max=%g, time: %gms", I->minval, I->maxval, (dtime()-t0)*1e3);
}
/*
* =================== CONVERT IMAGE TYPES ===================>
*/
/**
* @brief bin2Im - convert binarized image into uint8t
* @param image - binarized image
* @param W, H - its size (in pixels!)
* @return Image structure
*/
ilImage *ilbin2Image(const uint8_t *image, int W, int H){
ilImage *ret = ilImage_new(W, H, IMTYPE_U8);
int stride = (W + 7) / 8, s1 = (stride*8 == W) ? stride : stride - 1;
uint8_t *data = (uint8_t*) ret->data;
OMP_FOR()
for(int y = 0; y < H; y++){
uint8_t *optr = &data[y*W];
const uint8_t *iptr = &image[y*stride];
for(int x = 0; x < s1; x++){
register uint8_t inp = *iptr++;
for(int i = 0; i < 8; ++i){
*optr++ = (inp & 0x80) ? 255 : 0;
inp <<= 1;
}
}
int rest = W - s1*8;
if(rest){
register uint8_t inp = *iptr;
for(int i = 0; i < rest; ++i){
*optr++ = (inp & 0x80) ? 255 : 0;
inp <<= 1;
}
}
}
ret->minval = 0;
ret->maxval = 255;
return ret;
}
/**
* Convert image into pseudo-packed (1 char == 8 pixels), all values > bk will be 1, else - 0
* @param im (i) - image to convert
* @param stride (o) - new width of image
* @param bk - background level (all values < bk will be 0, other will be 1)
* @return allocated memory area with "packed" image
*/
uint8_t *ilImage2bin(const ilImage *im, double bk){
if(!im) return NULL;
if(im->type != IMTYPE_U8){
WARNX("ilImage2bin(): supported only 8-bit images");
return NULL;
}
int W = im->width, H = im->height;
if(W < 2 || H < 2) return NULL;
int y, W0 = (W + 7) / 8, s1 = (W/8 == W0) ? W0 : W0 - 1;
uint8_t *ret = MALLOC(uint8_t, W0 * H);
uint8_t *data = (uint8_t*) im->data;
OMP_FOR()
for(y = 0; y < H; ++y){
uint8_t *iptr = &data[y*W];
uint8_t *optr = &ret[y*W0];
for(int x = 0; x < s1; ++x){
register uint8_t o = 0;
for(int i = 0; i < 8; ++i){
o <<= 1;
if(*iptr++ > bk) o |= 1;
}
*optr++ = o;
}
int rest = W - s1*8;
if(rest){
register uint8_t o = 0;
for(int x = 0; x < rest; ++x){
o <<= 1;
if(*iptr++ > bk) o |= 1;
}
*optr = o << (8 - rest);
}
}
return ret;
}
#if 0
UNUSED function! Need to be refactored
// convert size_t labels into Image
Image *ST2Im(const size_t *image, int W, int H){
Image *ret = Image_new(W, H);
OMP_FOR()
for(int y = 0; y < H; ++y){
Imtype *optr = &ret->data[y*W];
const size_t *iptr = &image[y*W];
for(int x = 0; x < W; ++x){
*optr++ = (Imtype)*iptr++;
}
}
Image_minmax(ret);
return ret;
}
#endif
/**
* Convert "packed" image into size_t array for conncomp procedure
* @param image (i) - input image
* @param W, H - size of image in pixels
* @return allocated memory area with copy of an image
*/
size_t *ilbin2sizet(const uint8_t *image, int W, int H){
size_t *ret = MALLOC(size_t, W * H);
int W0 = (W + 7) / 8, s1 = W0 - 1;
OMP_FOR()
for(int y = 0; y < H; y++){
size_t *optr = &ret[y*W];
const uint8_t *iptr = &image[y*W0];
for(int x = 0; x < s1; ++x){
register uint8_t inp = *iptr++;
for(int i = 0; i < 8; ++i){
*optr++ = (inp & 0x80) ? 1 : 0;
inp <<= 1;
}
}
int rest = W - s1*8;
if(rest){
register uint8_t inp = *iptr;
for(int i = 0; i < rest; ++i){
*optr++ = (inp & 0x80) ? 1 : 0;
inp <<= 1;
}
}
}
return ret;
}
/*
* <=================== CONVERT IMAGE TYPES ===================
*/
/*
* =================== SAVE IMAGES ===========================>
*/
/**
* @brief write_jpg - write jpeg file
* @param name - filename
* @param w - width
* @param h - height
* @param ncolors - 1 or 3 (mono/color)
* @param bytes - image data
* @param quality - jpeg quality
* @return FALSE if failed
*/
int ilwrite_jpg(const char *name, int w, int h, int ncolors, uint8_t *bytes, int quality){
if(!bytes || !name || quality < 5 || quality > 100 || (ncolors != 1 && ncolors != 3) || w < 1 || h < 1) return FALSE;
char *tmpnm = MALLOC(char, strlen(name) + 10);
sprintf(tmpnm, "%s-tmp.jpg", name);
int r = stbi_write_jpg(tmpnm, w, h, ncolors, bytes, quality);
if(r){
if(rename(tmpnm, name)){
WARN("rename()");
r = FALSE;
}
}
FREE(tmpnm);
return r;
}
/**
* @brief ilImg3_jpg - save Img3 as jpeg
* @param name - output file name
* @param I3 - image
* @param quality - jpeg quality
* @return FALSE if failed
*/
int ilImg3_jpg(const char *name, ilImg3 *I3, int quality){
if(!name || quality < 5 || quality > 100 || !I3 || !I3->data || I3->width < 1 || I3->height < 1) return FALSE;
char *tmpnm = MALLOC(char, strlen(name) + 10);
sprintf(tmpnm, "%s-tmp.jpg", name);
int r = stbi_write_jpg(tmpnm, I3->width, I3->height, 3, I3->data, quality);
if(r){
if(rename(tmpnm, name)){
WARN("rename()");
r = FALSE;
}
}
FREE(tmpnm);
return r;
}
/**
* @brief write_png - write png file
* @param name - filename
* @param w - width
* @param h - height
* @param ncolors - 1 or 3 (mono/color)
* @param bytes - image data
* @return FALSE if failed
*/
int ilwrite_png(const char *name, int w, int h, int ncolors, uint8_t *bytes){
if(!bytes || !name || (ncolors != 1 && ncolors != 3) || w < 1 || h < 1) return FALSE;
char *tmpnm = MALLOC(char, strlen(name) + 10);
sprintf(tmpnm, "%s-tmp.jpg", name);
int r = stbi_write_png(tmpnm, w, h, ncolors, bytes, w);
if(r){
if(rename(tmpnm, name)){
WARN("rename()");
r = FALSE;
}
}
FREE(tmpnm);
return r;
}
/**
* @brief ilImg3_png - save Img3 as jpeg
* @param name - output file name
* @param I3 - image
* @param quality - jpeg quality
* @return FALSE if failed
*/
int ilImg3_png(const char *name, ilImg3 *I3){
if(!name || !I3 || !I3->data || I3->width < 1 || I3->height < 1) return FALSE;
char *tmpnm = MALLOC(char, strlen(name) + 10);
sprintf(tmpnm, "%s-tmp.png", name);
int r = stbi_write_png(tmpnm, I3->width, I3->height, 3, I3->data, 0);
if(r){
if(rename(tmpnm, name)){
WARN("rename()");
r = FALSE;
}
}
FREE(tmpnm);
return r;
}
/*
* <=================== SAVE IMAGES ===========================
*/

10
improc.pc.in Normal file
View File

@ -0,0 +1,10 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
Name: @PROJ@
Description: Simplest image processing library
Version: @VERSION@
Libs: -L${libdir} -l@PROJ@
Cflags: -I${includedir}

1
improclib.cflags Normal file
View File

@ -0,0 +1 @@
-std=c17

5
improclib.config Normal file
View File

@ -0,0 +1,5 @@
// Add predefined macros for your project here. For example:
// #define THE_ANSWER 42
#define EBUG
#define _GNU_SOURCE
#define OMP_FOUND

1
improclib.creator Normal file
View File

@ -0,0 +1 @@
[General]

160
improclib.creator.user Normal file
View File

@ -0,0 +1,160 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 8.0.2, 2023-03-27T14:51:54. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
<value type="QByteArray">{cf63021e-ef53-49b0-b03b-2f2570cdf3b6}</value>
</data>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="int">0</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
<valuemap type="QVariantMap">
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
<value type="QString" key="language">Cpp</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
</valuemap>
</valuemap>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
<value type="QString" key="language">QmlJS</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
</valuemap>
</valuemap>
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
<value type="QByteArray" key="EditorConfiguration.Codec">KOI8-R</value>
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
<value type="int" key="EditorConfiguration.IndentSize">4</value>
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
<value type="bool" key="EditorConfiguration.PreferSingleLineComments">false</value>
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">false</value>
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">1</value>
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
<value type="int" key="EditorConfiguration.TabSize">8</value>
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
<value type="bool" key="EditorConfiguration.UseIndenter">false</value>
<value type="int" key="EditorConfiguration.Utf8BomBehavior">2</value>
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
<value type="QString" key="EditorConfiguration.ignoreFileTypes">*.md, *.MD, Makefile</value>
<value type="bool" key="EditorConfiguration.inEntireDocument">true</value>
<value type="bool" key="EditorConfiguration.skipTrailingWhitespace">true</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.PluginSettings</variable>
<valuemap type="QVariantMap">
<valuemap type="QVariantMap" key="ClangTools">
<value type="bool" key="ClangTools.AnalyzeOpenFiles">true</value>
<value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value>
<value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value>
<value type="int" key="ClangTools.ParallelJobs">4</value>
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
<value type="bool" key="ClangTools.UseGlobalSettings">true</value>
</valuemap>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<value type="QString" key="DeviceType">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{91347f2c-5221-46a7-80b1-0a054ca02f79}</value>
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<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>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
<value type="QString">all</value>
</valuelist>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Сборка</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Сборка</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
<value type="QString">clean</value>
</valuelist>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Очистка</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Очистка</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">По умолчанию</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Развёртывание</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Развёртывание</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<valuelist type="QVariantList" key="CustomOutputParsers"/>
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey"></value>
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.TargetCount</variable>
<value type="int">1</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
<value type="int">22</value>
</data>
<data>
<variable>Version</variable>
<value type="int">22</value>
</data>
</qtcreator>

1
improclib.cxxflags Normal file
View File

@ -0,0 +1 @@
-std=c++17

11
improclib.files Normal file
View File

@ -0,0 +1,11 @@
draw.c
examples/equalize.c
examples/generate.c
examples/genu16.c
imagefile.c
improclib.h
letters.c
openmp.h
stb/stb_image.h
stb/stb_image_write.h
stbimpl.c

135
improclib.h Normal file
View File

@ -0,0 +1,135 @@
/*
* This file is part of the improclib project.
* Copyright 2023 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stdint.h>
#include <stdlib.h> // size_t
/*================================================================================*
* basic types *
*================================================================================*/
// 3-channel image for saving into jpg/png
typedef struct{
uint8_t *data; // image data
int width; // width
int height; // height
} ilImg3;
// 1-channel image - pattern
typedef struct{
uint8_t *data; // image data
int width; // width
int height; // height
} ilPattern;
typedef enum{
IMTYPE_U8, // uint8_t
IMTYPE_U16, // uint16_t
IMTYPE_U32, // uint32_t
IMTYPE_F, // float
IMTYPE_D, // double
IMTYPE_AMOUNT
} ilimtype_t;
typedef struct{
int width; // width
int height; // height
ilimtype_t type; // data type
int pixbytes; // size of one pixel data (bytes)
void *data; // picture data
double minval; // extremal data values
double maxval;
} ilImage;
// input file/directory type
typedef enum{
T_WRONG,
T_DIRECTORY,
T_BMP,
T_GIF,
T_JPEG,
T_PNG,
T_FITS, // only to check type: FITS are supported in fitsmaniplib
T_GZIP,
T_AMOUNT
} ilInputType;
/*================================================================================*
* draw.c *
*================================================================================*/
extern const uint8_t ilColor_red[3], ilColor_green[3], ilColor_blue[3], ilColor_black[3], ilColor_white[3];
ilPattern *ilPattern_new(int w, int h);
void ilPattern_free(ilPattern **I);
ilImg3 *ilImg3_new(int w, int h);
void ilImg3_free(ilImg3 **I3);
ilPattern *ilPattern_cross(int w, int h);
ilPattern *ilPattern_xcross(int w, int h);
ilPattern *ilPattern_star(int w, int h, double fwhm, double beta);
ilImage *ilImage_star(ilimtype_t type, int w, int h, double fwhm, double beta);
void ilPattern_draw3(ilImg3 *img, const ilPattern *p, int xc, int yc, const uint8_t color[3]);
void iladd_subimage(ilImage *img, const ilImage *p, int xc, int yc, double weight);
/*================================================================================*
* imagefile.c *
*================================================================================*/
int ilgetpixbytes(ilimtype_t type);
void ilImage_minmax(ilImage *I);
uint8_t *ilImage2u8(ilImage *I, int nchannels);
uint8_t *ilequalize8(ilImage *I, int nchannels, double throwpart);
uint8_t *ilequalize16(ilImage *I, int nchannels, double throwpart);
ilInputType ilchkinput(const char *name);
ilImage *ilImage_read(const char *name);
ilImage *ilImage_new(int w, int h, ilimtype_t type);
ilImage *ilImage_sim(const ilImage *i);
void ilImage_free(ilImage **I);
size_t *ilhistogram8(const ilImage *I);
size_t *ilhistogram16(const ilImage *I);
int ilImage_background(ilImage *img, double *bkg);
ilImage *ilu8toImage(const uint8_t *data, int width, int height);
ilImage *ilbin2Image(const uint8_t *image, int W, int H);
uint8_t *ilImage2bin(const ilImage *im, double bk);
size_t *ilbin2sizet(const uint8_t *image, int W, int H);
ilImg3 *ilImg3_read(const char *name);
int ilImg3_jpg(const char *name, ilImg3 *I3, int quality);
int ilImg3_png(const char *name, ilImg3 *I3);
int ilwrite_jpg(const char *name, int w, int h, int ncolors, uint8_t *bytes, int quality);
int ilwrite_png(const char *name, int w, int h, int ncolors, uint8_t *bytes);
/*================================================================================*
* letters.c *
*================================================================================*/
int ilImage_putstring(ilImage *I, const char *str, int x, int y);
/*================================================================================*
* *
*================================================================================*/
/*================================================================================*
* *
*================================================================================*/

3
improclib.includes Normal file
View File

@ -0,0 +1,3 @@
.
stb
examples

172
letters.c Normal file
View File

@ -0,0 +1,172 @@
/*
* This file is part of the improclib project.
* Copyright 2023 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "improclib.h"
#include <stdio.h>
#include <usefull_macros.h>
static const uint8_t letters[95][13] = {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},// space :32
{0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18},// ! :33
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36},// "
{0x00, 0x00, 0x00, 0x66, 0x66, 0xff, 0x66, 0x66, 0xff, 0x66, 0x66, 0x00, 0x00},// #
{0x00, 0x00, 0x18, 0x7e, 0xff, 0x1b, 0x1f, 0x7e, 0xf8, 0xd8, 0xff, 0x7e, 0x18},// $
{0x00, 0x00, 0x0e, 0x1b, 0xdb, 0x6e, 0x30, 0x18, 0x0c, 0x76, 0xdb, 0xd8, 0x70},// %
{0x00, 0x00, 0x7f, 0xc6, 0xcf, 0xd8, 0x70, 0x70, 0xd8, 0xcc, 0xcc, 0x6c, 0x38},// &
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1c, 0x0c, 0x0e},// '
{0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c},// (
{0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30},// )
{0x00, 0x00, 0x00, 0x00, 0x99, 0x5a, 0x3c, 0xff, 0x3c, 0x5a, 0x99, 0x00, 0x00},// *
{0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00},// +
//{0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},// ,
{0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},// ,
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00},// -
{0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},// .
{0x00, 0x60, 0x60, 0x30, 0x30, 0x18, 0x18, 0x0c, 0x0c, 0x06, 0x06, 0x03, 0x03},
{0x00, 0x00, 0x3c, 0x66, 0xc3, 0xe3, 0xf3, 0xdb, 0xcf, 0xc7, 0xc3, 0x66, 0x3c},
{0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x38, 0x18},
{0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0xe7, 0x7e},
{0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0x07, 0x03, 0x03, 0xe7, 0x7e},
{0x00, 0x00, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xff, 0xcc, 0x6c, 0x3c, 0x1c, 0x0c},
{0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xff},
{0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e},
{0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x03, 0x03, 0xff},
{0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e},
{0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x03, 0x7f, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e},
{0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06},
{0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60},
{0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x18, 0x0c, 0x06, 0x03, 0xc3, 0xc3, 0x7e},
{0x00, 0x00, 0x3f, 0x60, 0xcf, 0xdb, 0xd3, 0xdd, 0xc3, 0x7e, 0x00, 0x00, 0x00},
{0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18},
{0x00, 0x00, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe},
{0x00, 0x00, 0x7e, 0xe7, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e},
{0x00, 0x00, 0xfc, 0xce, 0xc7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc7, 0xce, 0xfc},
{0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0, 0xff},
{0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xff},
{0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xcf, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e},
{0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3},
{0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e},
{0x00, 0x00, 0x7c, 0xee, 0xc6, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06},
{0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xe0, 0xf0, 0xd8, 0xcc, 0xc6, 0xc3},
{0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0},
{0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xff, 0xff, 0xe7, 0xc3},
{0x00, 0x00, 0xc7, 0xc7, 0xcf, 0xcf, 0xdf, 0xdb, 0xfb, 0xf3, 0xf3, 0xe3, 0xe3},
{0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xe7, 0x7e},
{0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe},
{0x00, 0x00, 0x3f, 0x6e, 0xdf, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c},
{0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe},
{0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0xe0, 0xc0, 0xc0, 0xe7, 0x7e},
{0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff},
{0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3},
{0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3},
{0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3},
{0x00, 0x00, 0xc3, 0x66, 0x66, 0x3c, 0x3c, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3},
{0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3},
{0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x7e, 0x0c, 0x06, 0x03, 0x03, 0xff},
{0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c},
{0x00, 0x03, 0x03, 0x06, 0x06, 0x0c, 0x0c, 0x18, 0x18, 0x30, 0x30, 0x60, 0x60},
{0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18},
{0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x30, 0x70},
{0x00, 0x00, 0x7f, 0xc3, 0xc3, 0x7f, 0x03, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0},
{0x00, 0x00, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x03, 0x03, 0x03, 0x03, 0x03},
{0x00, 0x00, 0x7f, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x33, 0x1e},
{0x7e, 0xc3, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0},
{0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00},
{0x38, 0x6c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x0c, 0x00},
{0x00, 0x00, 0xc6, 0xcc, 0xf8, 0xf0, 0xd8, 0xcc, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0},
{0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78},
{0x00, 0x00, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xfe, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xfc, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00},
{0xc0, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0x00, 0x00, 0x00, 0x00},
{0x03, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, 0xfe, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0xfe, 0x03, 0x03, 0x7e, 0xc0, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x1c, 0x36, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x00},
{0x00, 0x00, 0x7e, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0xc3, 0xe7, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00},
{0xc0, 0x60, 0x60, 0x30, 0x18, 0x3c, 0x66, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0xff, 0x60, 0x30, 0x18, 0x0c, 0x06, 0xff, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x0f, 0x18, 0x18, 0x18, 0x38, 0xf0, 0x38, 0x18, 0x18, 0x18, 0x0f},
{0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18},
{0x00, 0x00, 0xf0, 0x18, 0x18, 0x18, 0x1c, 0x0f, 0x1c, 0x18, 0x18, 0x18, 0xf0},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x8f, 0xf1, 0x60, 0x00, 0x00, 0x00} // :126
};
#define PUTL(type, max) \
for(int cury = y; cury > y-13; --cury, ++letter){ if(cury >= I->height) continue; if(cury < 0) break; \
type *data = &((type*)I->data)[I->width * cury + x]; \
uint8_t l = *letter; \
for(int curx = x; curx < x+8; ++curx, ++data, l <<= 1){ if(curx >= I->width) break; if(curx < 0) continue; \
if(l & 0x80){ *data = max; \
}else{ *data = 0; } \
} \
}
int ilImage_putstring(ilImage *I, const char *str, int x, int y){
int c;
if(x >= I->width || y < 1 || y > I->height + 12) return FALSE;
int startx = x;
while((c = (int)*str)){
if(c == '\n'){ // newline
y += 14;
if(y > I->height+7) break;
++str;
x = startx;
continue;
}
c -= 32;
if(c < 0 || c > 94) continue;
if(x > I->width) break;
const uint8_t *letter = letters[c];
switch(I->type){
case IMTYPE_U8:
PUTL(uint8_t, UINT8_MAX);
break;
case IMTYPE_U16:
PUTL(uint16_t, UINT16_MAX);
break;
case IMTYPE_U32:
PUTL(uint32_t, UINT32_MAX);
break;
case IMTYPE_F:
PUTL(float, 1.f);
break;
case IMTYPE_D:
PUTL(double, 1.);
break;
default:
return FALSE;
}
++str;
x += 9;
}
return TRUE;
}

34
openmp.h Normal file
View File

@ -0,0 +1,34 @@
/*
* This file is part of the improclib project.
* Copyright 2023 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <usefull_macros.h>
#ifdef OMP_FOUND
#include <omp.h>
#ifndef OMP_FOR
#ifndef Stringify
#define Stringify(x) #x
#endif
#define OMP_FOR(x) _Pragma(Stringify(omp parallel for x))
#endif
#else
#define OMP_FOR(x)
#endif

7987
stb/stb_image.h Normal file

File diff suppressed because it is too large Load Diff

1690
stb/stb_image_write.h Normal file

File diff suppressed because it is too large Load Diff

29
stbimpl.c Normal file
View File

@ -0,0 +1,29 @@
/*
* This file is part of the improclib project.
* Copyright 2023 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// implementation of STB library (to accelerate compilation)
#define STBI_NO_PSD
#define STBI_NO_TGA
#define STBI_NO_HDR
#define STBI_NO_PIC
#define STBI_NO_PNM
#define STB_IMAGE_IMPLEMENTATION
#include <stb/stb_image.h>
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include <stb/stb_image_write.h>