/* fonctions de bases pour la librairie 'libtthimage' -------------------------------------------------- (g) 1992,2003 - Thierry Boudet - aka Oulala */ #include #include #include #include "../tthimage.h" /*::------------------------------------------------------------------::*/ void Image_print_version(int flag) { char *ptr; fflush(stdout); fprintf(stderr, "-+- This is the `tthimage' library v%s (wtfyw 2024) tTh\n", IMAGE_VERSION_STRING); if (flag) { /* this information is only correct IF you touch image.c before * running 'make' utility */ fprintf(stderr, " + compiled : %s, %s\n", __DATE__, __TIME__); } if (flag > 1) { fprintf(stderr, " + DESTDIR = %s\n", DESTDIR); fprintf(stderr, " + SHAREDIR = %s\n", SHAREDIR); fprintf(stderr, " + CC OPTS = %s\n", CC_OPTS); } fflush(stdout); /* OMFG, this is a gnuism ! */ if ( (ptr=getenv("MALLOC_CHECK_")) != NULL) { fprintf(stderr, "-+- libtthimage: malloc check is set to %s\n", ptr); } #if DEBUG_LEVEL fprintf(stderr, "Warning! this version of libtthimage is compiled with DEBUG_LEVEL=%d\n", DEBUG_LEVEL); #if FORCE_ABORT fprintf(stderr, "Warning! this version of libtthimage is compiled with FORCE_ABORT!\n"); #endif #endif } /*::------------------------------------------------------------------::*/ /* * This function create a new channel for an image. * Before version 0.4.9 it was a private function, but * the module 'alpha.c' need access to it. * * ... So I make it "semi-public" ... */ int Image_alloc_pixels(unsigned char ***pix, int w, int h); /* * pour le moment, pas de code retour en cas * d'erreur, mais un exit(1) brutal. */ int Image_alloc_pixels(unsigned char ***pix, int w, int h) { int foo; unsigned char **lignes, *ptr; lignes = (unsigned char **)malloc(sizeof(unsigned char *) * h); #if DEBUG_LEVEL > 1 fprintf(stderr, " alloc pixels for plane @ %p -> %p\n", pix, lignes); #endif *pix = lignes; /* setting the indirected return value here so we can use 'lignes' in the loop. */ for (foo=0; foo don't "free" this pointer, please. */ Image_Desc * Image_alloc(int width, int height, int type) { Image_Desc *header; int foo; #if DEBUG_LEVEL > 1 fprintf(stderr, "allocation for an image %dx%d, type:%d\n", width, height, type); #endif if ( (header=(Image_Desc *)calloc(sizeof(Image_Desc), 1)) == NULL ) { fprintf(stderr, "Image_Alloc (%s) err malloc header\n", __FILE__); exit(1); } #if DEBUG_LEVEL > 1 fprintf(stderr, " header is at @ %p\n", header); #endif strcpy(header->name, ""); header->nb_planes = type; header->width = width; header->height = height; #if IMGCOMMENT strcpy(header->comment, "* libimg is (dwtfywl) tontonTh 2022 *"); #else /* * The old 'Xv' image viewer does not like .TGA with a comment. */ strcpy(header->comment, ""); #endif header->type = type; header->Rpix = header->Gpix = header->Bpix = header->Apix = NULL; header->magic = MAGIC_OF_IMAGE; header->nbcols = 0; header->idx_palette = 0; header->errmsg = header->modified = 0; /* nouveau 18 Sept 2001 */ header->fx = header->fy = 0.0; header->fw = (double)width; header->fh = (double)height; /* new 12 Nov 2001 - see 'turtle.c' */ header->rt = header->gt = header->bt = 42; header->xt = (double)width / 2.0; header->yt = (double)height / 2.0; header->at = 0; /* canal alpha, 0 est-il la bonne valeur ? */ switch (type) { case IMAGE_GREY: Image_alloc_pixels(&header->Rpix, width, height); for (foo=0; foo<256; foo++) { header->palette[0][foo] = foo; header->palette[1][foo] = foo; header->palette[2][foo] = foo; } break; case IMAGE_RGB: Image_alloc_pixels(&header->Rpix, width, height); Image_alloc_pixels(&header->Gpix, width, height); Image_alloc_pixels(&header->Bpix, width, height); break; case IMAGE_RGBA: #if DEBUG_LEVEL fprintf(stderr, "WARNING! allocating an image with alpha channel,\n"); #endif Image_alloc_pixels(&header->Rpix, width, height); Image_alloc_pixels(&header->Gpix, width, height); Image_alloc_pixels(&header->Bpix, width, height); Image_alloc_pixels(&header->Apix, width, height); break; default: fprintf(stderr, "***** %s alloc image: %d is an unknow type *****\n", __FILE__, type); return NULL; } if (getenv("MALLOC_CHECK_") != NULL) { fprintf(stderr, "-+- libtthimage %s %d: alloc %p\n", __FILE__, __LINE__, header); } return header; } /*::------------------------------------------------------------------::*/ /* This fonction build another image from a model. */ Image_Desc * Image_clone (Image_Desc *src, int copy) { Image_Desc *image; if ( NULL == src ) { fprintf(stderr, "Image_clone: source descriptor is NULL\n"); exit(5); } image = Image_alloc(src->width, src->height, src->type); if ( NULL == image ) { fprintf(stderr, "Image_clone: cloned descriptor is NULL\n"); exit(5); } /* * we have to transfer a few attributes ... */ #if DEBUG_LEVEL > 1 fprintf(stderr, "clone %p to %p, no copy of attributes ?\n", src, image); #endif image->fx = src->fx; image->fy = src->fy; image->fw = src->fw; image->fh = src->fh; if (copy == 1) { Image_copy(src, image); } image->modified = 0; /* 8 Fev 01 */ return image; } /*::------------------------------------------------------------------::*/ int Image_copy_comment(Image_Desc *s, Image_Desc *d) { #if DEBUG_LEVEL fprintf(stderr, "%s ( %p -> %p )\n", __func__, s, d); #endif /* TODO check the validity of the comment, there _must_ be a '\0' inside */ memcpy(d->comment, s->comment, IMG_OBJCOMMENT_LEN); return FUNC_IS_ALPHA; } /*::------------------------------------------------------------------::*/ /* * Helas, cette fonction ne marche que sur les images RGB * et comment la rendre compatible tout-types sans tout casser ? */ int Image_clear( Image_Desc *image, int r, int g, int b ) { int x, y; if (image->type == IMAGE_RGB) { for (y=0; yheight; y++) { /* * XXX here we can go faster with a few memset */ for (x=0; xwidth; x++) { (image->Rpix[y])[x] = r; (image->Gpix[y])[x] = g; (image->Bpix[y])[x] = b; /* Bon, et le canal Alpha, il devient quoi ? */ } } return 0; /* ok, this 'return' here is a "spleyterie" :) */ } if (image->type == IMAGE_RGBA) { for (y=0; yheight; y++) { for (x=0; xwidth; x++) { (image->Rpix[y])[x] = r; (image->Gpix[y])[x] = g; (image->Bpix[y])[x] = b; (image->Apix[y])[x] = 0; } } return 0; /* ok, this 'return' here is a "spleyterie" :) */ } fprintf(stderr, "%s : invalid image type %d : %s\n", __func__, image->type, Image_type2str(image->type)); return IMAGE_BAD_TYPE; } /*::------------------------------------------------------------------::*/ /* new: Sat Sep 23 19:07:03 UTC 2023 * */ int Image_set_rgb(Image_Desc *img, RGBA *rgba) { int x, y; #if DEBUG_LEVEL fprintf(stderr, ">>> %s ( %p %p ) %d %d %d\n", __func__, img, rgba, rgba->r, rgba->g, rgba->b); #endif if (IMAGE_RGB != img->type) { fprintf(stderr, "%s : invalid image type %d : %s\n", __func__, img->type, Image_type2str(img->type)); return IMAGE_BAD_TYPE; } for (y=0; yheight; y++) { for (x=0; xwidth; x++) { /* please, use memset here */ (img->Rpix[y])[x] = rgba->r; (img->Gpix[y])[x] = rgba->g; (img->Bpix[y])[x] = rgba->b; } } return FUNC_IS_BETA; } /*::------------------------------------------------------------------::*/ /* * every image in memory have a comment field, who is writen * in TGA and PNM file when image is saved. */ int Image_set_comment(Image_Desc *image, char *text) { if (strlen(text) > IMG_OBJCOMMENT_LEN) return STRING_TOO_LONG; strcpy(image->comment, text); return OLL_KORRECT; } /* 10 nov 2001: no #define for this not-so-magic 254 value ? */ /*::------------------------------------------------------------------::*/ int Image_plot_gray(Image_Desc *img, int x, int y, int v) { if ( x<0 || y<0 || x>=img->width || y>=img->height ) { fprintf(stderr, "ERRPLOT X %4d Y %4d %d\n", x, y, v); return OUT_OF_IMAGE; } (img->Rpix[y])[x] = (uint8_t)v; /* POURQUOI on ne plotte qu'une composante ? XXX */ return OLL_KORRECT; } int Image_plotRGB(Image_Desc *img, int x, int y, int r, int g, int b) { #if DEBUG_LEVEL > 2 fprintf(stderr, "PLOTRGB %d %d\n", x, y); #endif if ( x<0 || y<0 || x>=img->width || y>=img->height ) { fprintf(stderr, "Errplot RGB X=%d, Y=%d %d, %d, %d\n", x, y, r, g, b); #if FORCE_ABORT abort(); #endif return OUT_OF_IMAGE; } (img->Rpix[y])[x] = (uint8_t)(r&0xff); (img->Gpix[y])[x] = (uint8_t)(g&0xff); (img->Bpix[y])[x] = (uint8_t)(b&0xff); return OLL_KORRECT; } int Image_plotRGBA(Image_Desc *img, int x, int y, int r, int g, int b, int a) { if ( x<0 || y<0 || x>=img->width || y>=img->height ) { /* may be an #if DEBUG_LEVEL here ? */ fprintf(stderr, "Errplot RGBA X %4d Y %4d %d, %d, %d, %d\n", x, y, r, g, b, a); #if FORCE_ABORT abort(); #endif return OUT_OF_IMAGE; } (img->Rpix[y])[x] = (uint8_t)(r&0xff); (img->Gpix[y])[x] = (uint8_t)(g&0xff); (img->Bpix[y])[x] = (uint8_t)(b&0xff); (img->Apix[y])[x] = (uint8_t)(a&0xff); return OLL_KORRECT; } /*::------------------------------------------------------------------::*/ int Image_getRGB(Image_Desc *img, int x, int y, int *pr, int *pg, int *pb) { if ( x<0 || y<0 || x>=img->width || y>=img->height ) { /* may be an #if DEBUG_LEVEL here ? */ fprintf(stderr, "ERR GETRGB X %4d Y %4d\n", x, y); #if FORCE_ABORT abort(); #endif return OUT_OF_IMAGE; } *pr = (int)((img->Rpix[y])[x]); *pg = (int)((img->Gpix[y])[x]); *pb = (int)((img->Bpix[y])[x]); return OLL_KORRECT; } /*::------------------------------------------------------------------::*/ int Image_getRGBA(Image_Desc *img, int x, int y, int *pr, int *pg, int *pb, int *pa) { if ( x<0 || y<0 || x>=img->width || y>=img->height ) { fprintf(stderr, "ERR GETRGBA X %4d Y %4d\n", x, y); #if FORCE_ABORT abort(); #endif return OUT_OF_IMAGE; } if (img->type != IMAGE_RGBA) { fprintf(stderr, "%s: bad image type: %d, %s\n", __func__, img->type, Image_type2str(img->type)); #if FORCE_ABORT abort(); #endif exit(7); /* et un code d'erreur, ça irais pas mieux */ } *pr = (int)((img->Rpix[y])[x]); *pg = (int)((img->Gpix[y])[x]); *pb = (int)((img->Bpix[y])[x]); *pa = (int)((img->Apix[y])[x]); return OLL_KORRECT; } /*::------------------------------------------------------------------::*/ /* * ecriture d'une des composantes de l'image. (new=2000-02-01) * * 15 mars 2003: l'interface Fortran est dans 'img77g.c' XXX */ int Image_plot_channel(Image_Desc *img, char channel, int x, int y, int value) { if ( x<0 || y<0 || x>=img->width || y>=img->height ) { #if DEBUG_LEVEL fprintf(stderr, "ERR PLOTCHANNEL X %4d Y %4d\n", x, y); #endif return OUT_OF_IMAGE; } switch (channel) { case 'r': case 'R': (img->Rpix[y])[x] = (uint8_t)(value&0xff); break; case 'g': case 'G': (img->Gpix[y])[x] = (uint8_t)(value&0xff); break; case 'b': case 'B': (img->Bpix[y])[x] = (uint8_t)(value&0xff); break; case 'a': case 'A': (img->Apix[y])[x] = (uint8_t)(value&0xff); break; default: return WRONG_CHANNEL; } return OLL_KORRECT; } /*::------------------------------------------------------------------::*/ /* lecture d'une des composantes de l'image. */ int Image_R_pixel(Image_Desc *img, int x, int y) { if ( x<0 || y<0 || x>=img->width || y>=img->height ) { fprintf(stderr, "ERR READ R PIX X%d Y%d\n", x, y); return OUT_OF_IMAGE; } return (int)((img->Rpix[y])[x]); } int Image_G_pixel(Image_Desc *img, int x, int y) { if ( x<0 || y<0 || x>=img->width || y>=img->height ) { fprintf(stderr, "ERR READ G PIX X%d Y%d\n", x, y); return OUT_OF_IMAGE; } return (int)((img->Gpix[y])[x]); } int Image_B_pixel(Image_Desc *img, int x, int y) { if ( x<0 || y<0 || x>=img->width || y>=img->height ) { fprintf(stderr, "ERR READ B PIX X%d Y%d\n", x, y); return OUT_OF_IMAGE; } return (int)((img->Bpix[y])[x]); } int Image_A_pixel(Image_Desc *img, int x, int y) { if ( x<0 || y<0 || x>=img->width || y>=img->height ) { fprintf(stderr, "ERR A PIX X%d Y%d\n", x, y); return OUT_OF_IMAGE; } return (int)((img->Apix[y])[x]); } /*::------------------------------------------------------------------::*/ /* cette fonction ne marche que si les deux images sont allouees et de meme dimensions. */ int Image_copy(Image_Desc *src, Image_Desc *dst) { int foo; if ( (foo=Image_compare_desc(src, dst)) ) { fprintf(stderr, "%s: images are differents %d\n", __func__, foo); return foo; } for (foo=0; fooheight; foo++) { memcpy(dst->Rpix[foo], src->Rpix[foo], src->width); memcpy(dst->Gpix[foo], src->Gpix[foo], src->width); memcpy(dst->Bpix[foo], src->Bpix[foo], src->width); if (dst->Apix!=NULL && src->Apix!=NULL) memcpy(dst->Apix[foo], src->Apix[foo], src->width); } dst->modified = 1; /* >> 18 Juin 2002 >> ============ >> bon, maintenant se pose un grand problème philosophique. >> on vient juste de copier les octets qui incarnent les pixels >> rgb et peut-être alpha. Mais ce n'est que la partie évident >> d'une image: ses pixels. */ return 0; } /*::------------------------------------------------------------------::*/ /* * no boundary control ? XXX */ int Image_pixel_copy(Image_Desc *s, int x, int y, Image_Desc *d, int i, int j) { (d->Rpix[j])[i] = (s->Rpix[y])[x]; (d->Gpix[j])[i] = (s->Gpix[y])[x]; (d->Bpix[j])[i] = (s->Bpix[y])[x]; return OLL_KORRECT; } /*::------------------------------------------------------------------::*/ /* * Le nom de cette fonction n'a pas trop de rapport avec ce qu'elle fait, * mais elle permet de faire reculer Crash Coredump. */ int Image_compare_desc(Image_Desc *a, Image_Desc *b) { char *fmt = "%s: Image at %p have no 'Dead Beef' in it\n"; if ( (a==NULL) || (b==NULL) ) return NULL_DESCRIPTOR; if ( a->magic != MAGIC_OF_IMAGE ) { fprintf(stderr, fmt, __func__, a); return NOT_AN_IMAGE_DESC; } if ( b->magic != MAGIC_OF_IMAGE ) { fprintf(stderr, fmt, __func__, a); return NOT_AN_IMAGE_DESC; } if ( a->width != b->width ) return DIFFERENT_WIDTH; if ( a->height!= b->height) return DIFFERENT_HEIGHT; return OLL_KORRECT; } /*::------------------------------------------------------------------::*/ /* Cette fonction ne rend pas toute la memoire Pour le moment, le header n'est pas restitue. le probleme, si on desalloue le header c'est qu'il reste un pointeur fou chez l'appelant ... */ int Image_DeAllocate(Image_Desc *im) { int line; if (getenv("MALLOC_CHECK_") != NULL) { fprintf(stderr, "-+- libtthimage %s %d: free %p\n", __FILE__, __LINE__, im); } if ( im->magic != MAGIC_OF_IMAGE ) { fprintf(stderr, "at %p, there was no 'Dead Beef' to deallocate\n", im); /* emergency exit */ abort(); } #if DEBUG_LEVEL > 1 fprintf(stderr, ">> de-allocating image %p, cross your fingers.\n", im); fprintf(stderr, " %p %p %p %p\n", im->Rpix, im->Gpix, im->Bpix, im->Apix); #endif im->magic = 0L; /* mark dirty/invalid. */ im->type = IMAGE_NONE; /* -1, et tusors */ if (im->Rpix != NULL) { for (line=0; lineheight; line++) if (im->Rpix[line] != NULL) free(im->Rpix[line]); free(im->Rpix); im->Rpix = NULL; } if (im->Gpix != NULL) { for (line=0; lineheight; line++) if (im->Gpix[line] != NULL) free(im->Gpix[line]); free(im->Gpix); im->Gpix = NULL; } if (im->Bpix != NULL) { for (line=0; lineheight; line++) if (im->Bpix[line] != NULL) free(im->Bpix[line]); free(im->Bpix); im->Bpix = NULL; } if (im->Apix != NULL) { for (line=0; lineheight; line++) if (im->Apix[line] != NULL) free(im->Apix[line]); free(im->Apix); im->Apix = NULL; } #if DEBUG_LEVEL > 1 fprintf(stderr, "DeAllocate >> are we alive ?\n"); #endif return OLL_KORRECT; } /*::------------------------------------------------------------------::*/