diff --git a/draw.c b/draw.c index 5d4548d..d0f75dc 100644 --- a/draw.c +++ b/draw.c @@ -25,6 +25,10 @@ #include "improclib.h" #include "openmp.h" +#ifndef ABS +#define ABS(x) (((x) > 0) ? (x) : -(x)) +#endif + // base colors: const uint8_t ilColor_red[3] = {255, 0, 0}, @@ -171,6 +175,7 @@ ilImage *ilImage_star(ilimtype_t type, int w, int h, double fwhm, double beta){ } return p; } +#undef DRAW_star /** * @brief ilPattern_draw3 - draw pattern @ 3-channel image @@ -179,7 +184,7 @@ ilImage *ilImage_star(ilimtype_t type, int w, int h, double fwhm, double beta){ * @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]){ +void ilImg3_drawpattern(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; @@ -240,7 +245,7 @@ void ilPattern_draw3(ilImg3 *img, const ilPattern *p, int xc, int yc, const uint * @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){ +void ilImage_addsub(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"); @@ -293,3 +298,196 @@ void iladd_subimage(ilImage *img, const ilImage *p, int xc, int yc, double weigh ERRX("iladd_subimage(): wrong image type"); } } +#undef ADD_subim + +#define PUTP(type) do{((type*)I->data)[I->width*y+x] = *((type*)val);}while(0) +/** + * @brief ilImage_drawpix - put pixel @(x,y) + * @param I - image + * @param x - point coordinates + * @param y + * @param val - data value to set (the same type as I->data) + */ +void ilImage_drawpix(ilImage *I, int x, int y, const void *val){ + if(x < 0 || x >= I->width || y < 0 || y >= I->height) return; + switch(I->type){ + case IMTYPE_U8: + PUTP(uint8_t); + break; + case IMTYPE_U16: + PUTP(uint16_t); + break; + case IMTYPE_U32: + PUTP(uint32_t); + break; + case IMTYPE_F: + PUTP(float); + break; + case IMTYPE_D: + PUTP(double); + break; + default: + ERRX("ilImage_drawpix(): wrong image type"); + } +} +#undef PUTP + +static void plotLineLow(ilImage *I, int x0, int y0, int x1, int y1, const void *val){ + int dx = x1 - x0, dy = y1 - y0, yi = 1; + if(dy < 0){ yi = -1; dy = -dy; } + int D = (2 * dy) - dx, y = y0; + for(int x = x0; x <= x1; ++x){ + ilImage_drawpix(I, x, y, val); + if(D > 0){ + y += yi; + D += 2 * (dy - dx); + }else{ + D += 2*dy; + } + } +} +static void plotLineHigh(ilImage *I, int x0, int y0, int x1, int y1, const void *val){ + int dx = x1 - x0, dy = y1 - y0, xi = 1; + if(dx < 0){ xi = -1; dx = -dx; } + int D = (2 * dx) - dy, x = x0; + for(int y = y0; y <= y1; ++y){ + ilImage_drawpix(I, x, y, val); + if(D > 0){ + x += xi; + D += 2 * (dx - dy); + }else{ + D += 2*dx; + } + } +} +/** + * @brief ilImage_drawline - Bresenham's line drawing on Image + * @param I - image + * @param x0 - first point + * @param y0 + * @param x1 - last point + * @param y1 + * @param val - value to put + */ +void ilImage_drawline(ilImage *I, int x0, int y0, int x1, int y1, const void *val){ + if(!I || !I->data) return; + if(ABS(y1 - y0) < ABS(x1 - x0)){ + if(x0 > x1) plotLineLow(I, x1, y1, x0, y0, val); + else plotLineLow(I, x0, y0, x1, y1, val); + }else{ + if(y0 > y1) plotLineHigh(I, x1, y1, x0, y0, val); + else plotLineHigh(I, x0, y0, x1, y1, val); + } +} + +/** + * @brief ilImage_drawcircle - Bresenham's circle drawing on Image + * @param I - image + * @param x0- circle center + * @param y0 + * @param R - circle radius + * @param val - value to put + */ +void ilImage_drawcircle(ilImage *I, int x0, int y0, int R, const void *val){ + int x = R; + int y = 0; + int radiusError = 1-x; + while(x >= y){ + ilImage_drawpix(I, x + x0, y + y0, val); + ilImage_drawpix(I, y + x0, x + y0, val); + ilImage_drawpix(I, -x + x0, y + y0, val); + ilImage_drawpix(I, -y + x0, x + y0, val); + ilImage_drawpix(I, -x + x0, -y + y0, val); + ilImage_drawpix(I, -y + x0, -x + y0, val); + ilImage_drawpix(I, x + x0, -y + y0, val); + ilImage_drawpix(I, y + x0, -x + y0, val); + y++; + if (radiusError < 0){ + radiusError += 2 * y + 1; + }else{ + x--; + radiusError += 2 * (y - x) + 1; + } + } + +} + +/** + * @brief ilImg3_setcolor - set image pixel to given color or its negative (if original color is near to target) + * @param impixel - pixel to change + * @param color - desired color + */ +void ilImg3_setcolor(uint8_t impixel[3], const uint8_t color[3]){ + int invert = 0; + for(int i = 0; i < 3; ++i) + if(impixel[i] > color[i]){ + if(impixel[i] - color[i] < 127) ++invert; + }else if(color[i] - impixel[i] < 127) ++invert; + if(invert == 3) for(int i = 0; i < 3; ++i) impixel[i] = ~color[i]; + else for(int i = 0; i < 3; ++i) impixel[i] = color[i]; +} + +/** + * @brief ilImg3_drawpix - draw pixel with `color` or its negative on coloured image + * @param I - image + * @param x - point coordinates + * @param y + * @param color - desired color + */ +void ilImg3_drawpix(ilImg3 *I, int x, int y, const uint8_t color[3]){ + if(!I || !I->data) return; + if(x < 0 || x >= I->width) return; + if(y < 0 || y >= I->height) return; + ilImg3_setcolor(I->data + 3*(I->width*y+x), color); +} + +static void plotLineLow3(ilImg3 *I, int x0, int y0, int x1, int y1, const uint8_t color[3]){ + int dx = x1 - x0, dy = y1 - y0, yi = 1; + if(dy < 0){ yi = -1; dy = -dy; } + int D = (2 * dy) - dx, y = y0; + for(int x = x0; x <= x1; ++x){ + ilImg3_drawpix(I, x, y, color); + if(D > 0){ + y += yi; + D += 2 * (dy - dx); + }else{ + D += 2*dy; + } + } +} + +static void plotLineHigh3(ilImg3 *I, int x0, int y0, int x1, int y1, const uint8_t color[3]){ + int dx = x1 - x0, dy = y1 - y0, xi = 1; + if(dx < 0){ xi = -1; dx = -dx; } + int D = (2 * dx) - dy, x = x0; + for(int y = y0; y <= y1; ++y){ + ilImg3_drawpix(I, x, y, color); + if(D > 0){ + x += xi; + D += 2 * (dx - dy); + }else{ + D += 2*dx; + } + } +} + +/** + * @brief ilImg3_drawline - Bresenham's line drawing on Img3 + * @param I - image + * @param x0 - first point + * @param y0 + * @param x1 - last point + * @param y1 + * @param color - drawing color + */ +void ilImg3_drawline(ilImg3 *I, int x0, int y0, int x1, int y1, const uint8_t color[3]){ + if(!I || !I->data) return; + if(ABS(y1 - y0) < ABS(x1 - x0)){ + if(x0 > x1) plotLineLow3(I, x1, y1, x0, y0, color); + else plotLineLow3(I, x0, y0, x1, y1, color); + }else{ + if(y0 > y1) plotLineHigh3(I, x1, y1, x0, y0, color); + else plotLineHigh3(I, x0, y0, x1, y1, color); + } +} + diff --git a/examples/Readme.md b/examples/Readme.md index fbea46d..8edbab8 100644 --- a/examples/Readme.md +++ b/examples/Readme.md @@ -5,15 +5,22 @@ Examples 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: +Generate pseudo-star images with given Moffat parameters at given coordinates xi,yi (with amplitude ampi, ampi < 256). +Also draw different primitives and text. + +Usage: genu16 [args] x1,y1[,w1] x2,y2[,w2] ... xn,yn[,w3] - draw 'stars' at coords xi,yi with weight wi (default: 1.) + + Where args are: + + -?, --help show this help + -b, --beta=arg beta Moffat parameter of 'star' images (default: 1) + -h, --height=arg resulting image height (default: 1024) + -i, --input=arg input file with coordinates and amplitudes (comma separated) + -o, --output=arg output file name (default: output.png) + -s, --halfwidth=arg FWHM of 'star' images (default: 3.5) + -w, --width=arg resulting image width (default: 1024) -- 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). + diff --git a/examples/equalize.c b/examples/equalize.c index 7356a4c..64b9026 100644 --- a/examples/equalize.c +++ b/examples/equalize.c @@ -39,8 +39,8 @@ int main(int argc, char **argv){ 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); + ilImg3_drawpattern(I3, cross, 30, 30, ilColor_red); + ilImg3_drawpattern(I3, cross, 150, 50, ilColor_green); ilPattern_free(&cross); int ret = ilImg3_jpg("output.jpg", I3, 95); ilImg3_free(&I3); diff --git a/examples/generate.c b/examples/generate.c index 5b2b679..1af9087 100644 --- a/examples/generate.c +++ b/examples/generate.c @@ -62,8 +62,8 @@ static void addstar(ilImg3 *I, const char *str){ 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); + ilImg3_drawpattern(I, star, x, y, c); + ilImg3_drawpattern(I, cross, x, y, ilColor_red); } static void addfromfile(ilImg3 *I){ @@ -94,6 +94,10 @@ int main(int argc, char **argv){ for(int i = 0; i < argc; ++i) addstar(I, argv[i]); if(inp) addfromfile(I); ilPattern_free(&star); + uint8_t color[] = {255, 0, 100}; + //uint8_t color[] = {0, 0, 0}; + ilImg3_putstring(I, "Test string", 450, 520, color); + ilImg3_drawline(I, -10,900, 1600,1050, color); int ret = ilImg3_jpg(outp, I, 95); //int ret = ilImg3_png(outp, I); ilImg3_free(&I); diff --git a/examples/genu16.c b/examples/genu16.c index a91e032..91df59a 100644 --- a/examples/genu16.c +++ b/examples/genu16.c @@ -62,7 +62,7 @@ static void addstar(ilImage *I, const char *str){ 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); + ilImage_addsub(I, star, x, y, w); } static void addfromfile(ilImage *I){ @@ -97,6 +97,10 @@ int main(int argc, char **argv){ ilImage_putstring(I, "0", 0, 1016); ilImage_putstring(I, "Hello, world.!?\"'\nMore again", 50, 500); ilImage_putstring(I, "Hello, world!", 950, 1018); + uint16_t v = 50000; + ilImage_drawline(I, -100,-1000, 1000, 1200, &v); + ilImage_drawcircle(I, 1000,1000, 1000, &v); + ilImage_drawcircle(I, 512,512, 512, &v); for(int _ = 0; _ < 1024; _ += 50){ char s[6]; snprintf(s, 6, "%d", _); diff --git a/imagefile.c b/imagefile.c index 0a243e7..eb3f1c3 100644 --- a/imagefile.c +++ b/imagefile.c @@ -110,7 +110,10 @@ static ilInputType imtype(FILE *f){ ilInputType ilchkinput(const char *name){ DBG("input name: %s", name); struct stat fd_stat; - stat(name, &fd_stat); + if(stat(name, &fd_stat)){ + WARN("Can't stat() %s", name); + return T_WRONG; + } if(S_ISDIR(fd_stat.st_mode)){ DBG("%s is a directory", name); DIR *d = opendir(name); diff --git a/improclib.h b/improclib.h index 26048b4..713200d 100644 --- a/improclib.h +++ b/improclib.h @@ -81,12 +81,21 @@ 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); + +void ilImage_addsub(ilImage *img, const ilImage *p, int xc, int yc, double weight); +void ilImage_drawpix(ilImage *I, int x, int y, const void *val); +void ilImage_drawline(ilImage *I, int x0, int y0, int x1, int y1, const void *val); +void ilImage_drawcircle(ilImage *I, int x0, int y0, int R, const void *val); + +void ilImg3_drawpattern(ilImg3 *img, const ilPattern *p, int xc, int yc, const uint8_t color[3]); +void ilImg3_setcolor(uint8_t impixel[3], const uint8_t color[3]); +void ilImg3_drawpix(ilImg3 *img, int x, int y, const uint8_t color[3]); +void ilImg3_drawline(ilImg3 *img, int x0, int y0, int x1, int y1, const uint8_t color[3]); /*================================================================================* * imagefile.c * @@ -123,7 +132,7 @@ 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); - +int ilImg3_putstring(ilImg3 *I, const char *str, int x, int y, const uint8_t color[3]); /*================================================================================* diff --git a/letters.c b/letters.c index d1c4ef3..69f3911 100644 --- a/letters.c +++ b/letters.c @@ -16,10 +16,12 @@ * along with this program. If not, see . */ -#include "improclib.h" #include #include +#include "improclib.h" +#include "openmp.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 @@ -130,6 +132,14 @@ static const uint8_t letters[95][13] = { } \ } +/** + * @brief ilImage_putstring - print text string over image + * @param I - image + * @param str - zero-terminated sring + * @param x - x coordinate of left bottom text angle + * @param y - y (upside down) + * @return + */ 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; @@ -170,3 +180,35 @@ int ilImage_putstring(ilImage *I, const char *str, int x, int y){ } return TRUE; } + +// the same as ilImage_putstring but with given color +int ilImg3_putstring(ilImg3 *I, const char *str, int x, int y, const uint8_t color[3]){ + 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]; + for(int cury = y; cury > y-13; --cury, ++letter){ if(cury >= I->height) continue; if(cury < 0) break; + uint8_t *data = &((uint8_t*)I->data)[3 * (I->width * cury + x)]; + uint8_t l = *letter; + for(int curx = x; curx < x+8; ++curx, data+=3, l <<= 1){ if(curx >= I->width) break; if(curx < 0) continue; + if(l & 0x80){ // foreground - set to it given color or its negative + ilImg3_setcolor(data, color); + } + } + } + ++str; + x += 9; + } + return TRUE; +}