int im_makerw( IMAGE *im ) { return( im_rwcheck( im ) ); }
/* Draw a line on a image with a user plot function. We do no clipping: the * user function should check ranges for each pixel when it is called. */ int im_fastlineuser( IMAGE *im, int x1, int y1, int x2, int y2, int (*fn)(), void *client1, void *client2, void *client3 ) { int x, y, dx, dy; int err; if( im_rwcheck( im ) ) return( -1 ); /* Find offsets. */ dx = x2 - x1; dy = y2 - y1; /* Swap endpoints to reduce number of cases. */ if( abs( dx ) >= abs( dy ) && dx < 0 ) { /* Swap to get all x greater or equal cases going to the * right. Do diagonals here .. just have up and right and down * and right now. */ SWAP( x1, x2 ); SWAP( y1, y2 ); } else if( abs( dx ) < abs( dy ) && dy < 0 ) { /* Swap to get all y greater cases going down the screen. */ SWAP( x1, x2 ); SWAP( y1, y2 ); } /* Recalculate dx, dy. */ dx = x2 - x1; dy = y2 - y1; /* Start point and offset. */ x = x1; y = y1; /* Special case: zero width and height is single point. */ if( dx == 0 && dy == 0 ) { if( fn( im, x, y, client1, client2, client3 ) ) return( 1 ); } /* Special case vertical and horizontal lines for speed. */ else if( dx == 0 ) { /* Vertical line going down. */ for( ; y <= y2; y++ ) { if( fn( im, x, y, client1, client2, client3 ) ) return( 1 ); } } else if( dy == 0 ) { /* Horizontal line to the right. */ for( ; x <= x2; x++ ) { if( fn( im, x, y, client1, client2, client3 ) ) return( 1 ); } } /* Special case diagonal lines. */ else if( abs( dy ) == abs( dx ) && dy > 0 ) { /* Diagonal line going down and right. */ for( ; x <= x2; x++, y++ ) { if( fn( im, x, y, client1, client2, client3 ) ) return( 1 ); } } else if( abs( dy ) == abs( dx ) && dy < 0 ) { /* Diagonal line going up and right. */ for( ; x <= x2; x++, y-- ) { if( fn( im, x, y, client1, client2, client3 ) ) return( 1 ); } } else if( abs( dy ) < abs( dx ) && dy > 0 ) { /* Between -45 and 0 degrees. */ for( err = 0; x <= x2; x++ ) { if( fn( im, x, y, client1, client2, client3 ) ) return( 1 ); err += dy; if( err >= dx ) { err -= dx; y++; } } } else if( abs( dy ) < abs( dx ) && dy < 0 ) { /* Between 0 and 45 degrees. */ for( err = 0; x <= x2; x++ ) { if( fn( im, x, y, client1, client2, client3 ) ) return( 1 ); err -= dy; if( err >= dx ) { err -= dx; y--; } } } else if( abs( dy ) > abs( dx ) && dx > 0 ) { /* Between -45 and -90 degrees. */ for( err = 0; y <= y2; y++ ) { if( fn( im, x, y, client1, client2, client3 ) ) return( 1 ); err += dx; if( err >= dy ) { err -= dy; x++; } } } else if( abs( dy ) > abs( dx ) && dx < 0 ) { /* Between -90 and -135 degrees. */ for( err = 0; y <= y2; y++ ) { if( fn( im, x, y, client1, client2, client3 ) ) return( 1 ); err -= dx; if( err >= dy ) { err -= dy; x--; } } } else error_exit( "internal error #9872659823475982375" ); return( 0 ); }
/* Draw a line on a image. */ int im_fastline( IMAGE *im, int x1, int y1, int x2, int y2, PEL *pel ) { int es = IM_IMAGE_SIZEOF_ELEMENT( im ); int ps = es * im->Bands; int ls = ps * im->Xsize; PEL *p; int x, y, dx, dy; int err; int b; if( im_rwcheck( im ) ) return( -1 ); /* Check coordinates in range. */ if( x1 > im->Xsize || x1 < 0 || y1 > im->Ysize || y1 < 0 || x2 > im->Xsize || x2 < 0 || y2 > im->Ysize || y2 < 0 ) { im_error( "im_fastline", "%s", _( "invalid line cooordinates" ) ); return( -1 ); } /* Find offsets. */ dx = x2 - x1; dy = y2 - y1; /* Swap endpoints to reduce number of cases. */ if( abs( dx ) >= abs( dy ) && dx < 0 ) { /* Swap to get all x greater or equal cases going to the * right. Do diagonals here .. just have up and right and down * and right now. */ SWAP( x1, x2 ); SWAP( y1, y2 ); } else if( abs( dx ) < abs( dy ) && dy < 0 ) { /* Swap to get all y greater cases going down the screen. */ SWAP( x1, x2 ); SWAP( y1, y2 ); } /* Recalculate dx, dy. */ dx = x2 - x1; dy = y2 - y1; /* Start point and offset. */ x = x1; y = y1; p = (PEL *) im->data + x * ps + y * ls; /* Plot point macro. */ #define PLOT \ for( b = 0; b < ps; b++ ) \ p[b] = pel[b]; /* Special case: zero width and height is single point. */ if( dx == 0 && dy == 0 ) { PLOT; } /* Special case vertical and horizontal lines for speed. */ else if( dx == 0 ) { /* Vertical line going down. */ for( ; y <= y2; y++ ) { PLOT; p += ls; } } else if( dy == 0 ) { /* Horizontal line to the right. */ for( ; x <= x2; x++ ) { PLOT; p += ps; } } /* Special case diagonal lines. */ else if( abs( dy ) == abs( dx ) && dy > 0 ) { /* Diagonal line going down and right. */ for( ; x <= x2; x++ ) { PLOT; p += ps + ls; } } else if( abs( dy ) == abs( dx ) && dy < 0 ) { /* Diagonal line going up and right. */ for( ; x <= x2; x++ ) { PLOT; p += ps - ls; } } else if( abs( dy ) < abs( dx ) && dy > 0 ) { /* Between -45 and 0 degrees. */ for( err = 0; x <= x2; x++ ) { PLOT; p += ps; err += dy; if( err >= dx ) { err -= dx; p += ls; } } } else if( abs( dy ) < abs( dx ) && dy < 0 ) { /* Between 0 and 45 degrees. */ for( err = 0; x <= x2; x++ ) { PLOT; p += ps; err -= dy; if( err >= dx ) { err -= dx; p -= ls; } } } else if( abs( dy ) > abs( dx ) && dx > 0 ) { /* Between -45 and -90 degrees. */ for( err = 0; y <= y2; y++ ) { PLOT; p += ls; err += dx; if( err >= dy ) { err -= dy; p += ps; } } } else if( abs( dy ) > abs( dx ) && dx < 0 ) { /* Between -90 and -135 degrees. */ for( err = 0; y <= y2; y++ ) { PLOT; p += ls; err -= dx; if( err >= dy ) { err -= dy; p -= ps; } } } else error_exit( "internal error #9872659823475982375" ); return( 0 ); }
/* Smear a section of an IMAGE. As above, but shift it left a bit. */ int im_smear( IMAGE *im, int ix, int iy, Rect *r ) { int x, y, a, b, c; int ba = im->Bands; int el = ba * im->Xsize; Rect area, image, clipped; double total[ 256 ]; if( im_rwcheck( im ) ) return( -1 ); /* Don't do the margins. */ area = *r; area.left += ix; area.top += iy; image.left = 0; image.top = 0; image.width = im->Xsize; image.height = im->Ysize; im_rect_marginadjust( &image, -1 ); image.left--; im_rect_intersectrect( &area, &image, &clipped ); /* Any left? */ if( im_rect_isempty( &clipped ) ) return( 0 ); /* What we do for each type. */ #define SMEAR(TYPE) \ for( y = clipped.top; y < clipped.top + clipped.height; y++ ) \ for( x = clipped.left; \ x < clipped.left + clipped.width; x++ ) { \ TYPE *to = (TYPE *) im->data + x * ba + y * el; \ TYPE *from = to - el; \ TYPE *f; \ \ for( a = 0; a < ba; a++ ) \ total[a] = 0.0; \ \ for( a = 0; a < 3; a++ ) { \ f = from; \ for( b = 0; b < 3; b++ ) \ for( c = 0; c < ba; c++ ) \ total[c] += *f++; \ from += el; \ } \ \ for( a = 0; a < ba; a++ ) \ to[a] = (40 * (double) to[a+ba] + total[a]) \ / 49.0; \ } /* Loop through the remaining pixels. */ switch( im->BandFmt ) { case IM_BANDFMT_UCHAR: SMEAR(unsigned char); break; case IM_BANDFMT_CHAR: SMEAR(char); break; case IM_BANDFMT_USHORT: SMEAR(unsigned short); break; case IM_BANDFMT_SHORT: SMEAR(short); break; case IM_BANDFMT_UINT: SMEAR(unsigned int); break; case IM_BANDFMT_INT: SMEAR(int); break; case IM_BANDFMT_FLOAT: SMEAR(float); break; case IM_BANDFMT_DOUBLE: SMEAR(double); break; /* Do complex types too. Just treat as float and double, but with * twice the number of bands. */ case IM_BANDFMT_COMPLEX: /* Twice number of bands: double size and bands. */ ba *= 2; el *= 2; SMEAR(float); break; case IM_BANDFMT_DPCOMPLEX: /* Twice number of bands: double size and bands. */ ba *= 2; el *= 2; SMEAR(double); break; default: im_error( "im_smear", "%s", _( "unknown band format" ) ); return( -1 ); } return( 0 ); }