1/*********************************************************************** 2 * * 3 * $Id: hpgspaintimage.c 281 2006-02-25 19:40:31Z softadm $ 4 * * 5 * hpgs - HPGl Script, a hpgl/2 interpreter, which uses a Postscript * 6 * API for rendering a scene and thus renders to a variety of * 7 * devices and fileformats. * 8 * * 9 * (C) 2004-2006 ev-i Informationstechnologie GmbH http://www.ev-i.at * 10 * * 11 * Author: Wolfgang Glas * 12 * * 13 * hpgs is free software; you can redistribute it and/or * 14 * modify it under the terms of the GNU Lesser General Public * 15 * License as published by the Free Software Foundation; either * 16 * version 2.1 of the License, or (at your option) any later version. * 17 * * 18 * hpgs is distributed in the hope that it will be useful, * 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 21 * Lesser General Public License for more details. * 22 * * 23 * You should have received a copy of the GNU Lesser General Public * 24 * License along with this library; if not, write to the * 25 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, * 26 * Boston, MA 02111-1307 USA * 27 * * 28 *********************************************************************** 29 * * 30 * The implementation of the public API for the pixel painter. * 31 * * 32 ***********************************************************************/ 33 34#include<hpgspaint.h> 35#include<math.h> 36#include<assert.h> 37#include<string.h> 38 39//#define HPGS_PAINT_IMAGE_DEBUG 40 41#ifdef HPGS_PAINT_IMAGE_DEBUG 42static void log_mat_6(const char *lead, const double *mat) 43{ 44 hpgs_log("%s%10lg,%10lg,%10lg\n%*s%10lg,%10lg,%10lg.\n", 45 lead,mat->dx,mat->mxx,mat->mxy, 46 strlen(lead)," ",mat->dy,mat->myx,mat->myy); 47 48} 49#endif 50 51// multiplicates the given vector with the specified matrix. 52// This is here in order to allow efficient inlining of the code. 53// 54static void mat_6_mul(hpgs_point *pout, const hpgs_matrix *mat, double xin, double yin) 55{ 56 pout->x = mat->dx + mat->mxx * xin + mat->mxy * yin; 57 pout->y = mat->dy + mat->myx * xin + mat->myy * yin; 58} 59 60// build matrix from destination to source pixel coordinates. 61static void build_inv_matrix(hpgs_matrix *m, 62 const hpgs_paint_clipper *c, 63 const hpgs_image *dest, 64 const hpgs_image *src, 65 const hpgs_point *ll, 66 const hpgs_point *ul, 67 const hpgs_point *lr, 68 const hpgs_point *ur) 69{ 70 // image to device coordinates. 71 hpgs_matrix a = { ul->x, ul->y, 72 (lr->x-ll->x)/src->width, (lr->x-ur->x)/src->height, 73 (lr->y-ll->y)/src->width, (lr->y-ur->y)/src->height }; 74 75 // device to target raster coordinates. 76 hpgs_matrix b = {-0.5-c->bb.llx*dest->width/(c->bb.urx-c->bb.llx), c->y0/c->yfac, 77 dest->width/(c->bb.urx-c->bb.llx), 0.0, 78 0.0, -1.0/c->yfac }; 79 80 hpgs_matrix tmp; 81 82 // take half a pixel into account. 83 a.dx += 0.5 * (a.mxx + a.mxy); 84 a.dy += 0.5 * (a.myx + a.myy); 85 86 hpgs_matrix_concat(&tmp,&b,&a); 87#ifdef HPGS_PAINT_IMAGE_DEBUG 88 log_mat_6("a = ",a); 89 log_mat_6("b = ",b); 90 log_mat_6("b*a = ",tmp); 91#endif 92 hpgs_matrix_invert(m,&tmp); 93} 94 95typedef int (*put_point_func_t)(hpgs_image *, const hpgs_image *, 96 int, int, const hpgs_point *, double); 97 98static int put_point_0(hpgs_image *dest, const hpgs_image *src, 99 int dest_i, int dest_j, const hpgs_point *src_point, 100 double alpha) 101{ 102 hpgs_paint_color col; 103 104 double a; 105 106 int src_i = (int)rint(src_point->x); 107 int src_j = (int)rint(src_point->y); 108 109 if (src_i < 0 || src_i >= src->width) return 0; 110 if (src_j < 0 || src_j >= src->height) return 0; 111 112 hpgs_image_get_pixel(src,src_i,src_j,&col,&a); 113 114 if (hpgs_image_define_color (dest,&col)) 115 return -1; 116 117 return hpgs_image_rop3_pixel(dest,dest_i,dest_j,&col, 118 alpha*a); 119} 120 121static int put_point_1(hpgs_image *dest, const hpgs_image *src, 122 int dest_i, int dest_j, const hpgs_point *src_point, 123 double alpha) 124{ 125 hpgs_paint_color col; 126 127 double aa,a=0.0; 128 double r=0.0,g=0.0,b=0.0; 129 130 double w; 131 double sw = 0.0; 132 133 int src_i = (int)ceil(src_point->x); 134 int src_j = (int)ceil(src_point->y); 135 136 double wx = ceil(src_point->x) - src_point->x; 137 double wy = ceil(src_point->y) - src_point->y; 138 139 if (src_i < 0 || src_i > src->width) return 0; 140 if (src_j < 0 || src_j > src->height) return 0; 141 142 if (src_i > 0) 143 { 144 if (src_j > 0) 145 { 146 hpgs_image_get_pixel(src,src_i-1,src_j-1,&col,&aa); 147 w = wx+wy; 148 r+=w*col.r; 149 g+=w*col.g; 150 b+=w*col.b; 151 a += w*aa; 152 sw += w; 153 } 154 155 if (src_j < src->height) 156 { 157 hpgs_image_get_pixel(src,src_i-1,src_j,&col,&aa); 158 w = 1.0-wy+wx; 159 r+=w*col.r; 160 g+=w*col.g; 161 b+=w*col.b; 162 a += w*aa; 163 sw += w; 164 } 165 } 166 167 if (src_i < src->width) 168 { 169 if (src_j > 0) 170 { 171 hpgs_image_get_pixel(src,src_i,src_j-1,&col,&aa); 172 w = 1.0-wx+wy; 173 r+=w*col.r; 174 g+=w*col.g; 175 b+=w*col.b; 176 a += w*aa; 177 sw += w; 178 } 179 180 if (src_j < src->height) 181 { 182 hpgs_image_get_pixel(src,src_i,src_j,&col,&aa); 183 w=2.0-wx-wy; 184 r+=w*col.r; 185 g+=w*col.g; 186 b+=w*col.b; 187 a += w*aa; 188 sw += w; 189 } 190 } 191 192 if (!sw) return 0; 193 194 col.r = r / sw; 195 col.g = g / sw; 196 col.b = b / sw; 197 198 if (hpgs_image_define_color (dest,&col)) 199 return -1; 200 201 return hpgs_image_rop3_pixel(dest,dest_i,dest_j,&col, 202 0.25*alpha*a); 203} 204 205/*! 206 207 Draws the intersection of the given image with the current clip 208 path of the paint device \c pdv to the destination image of \c pdv. 209 210 The arguments \c ll, \c lr and \c ur are the 211 lower left, lower right and upper right corner of the drawn image 212 in world coordinates. 213 214 Return values: 215 216 \li 0 Sucess. 217 \li -1 An error ocurred. 218 Call \c hpgs_device_get_error in order to retrieve the error message. 219 220*/ 221int hpgs_paint_device_drawimage(hpgs_paint_device *pdv, 222 const hpgs_image *img, 223 const hpgs_point *ll, const hpgs_point *lr, 224 const hpgs_point *ur) 225{ 226 const hpgs_paint_clipper *c = pdv->clippers[pdv->current_clipper]; 227 put_point_func_t put_point_func = put_point_0; 228 hpgs_point ul; 229 double ll_i,lr_i,ur_i,ul_i; 230 int iscan0; 231 int iscan1; 232 int iscan; 233 hpgs_matrix imat[6]; 234 235 if (pdv->image_interpolation) 236 put_point_func = put_point_1; 237 238 ul.x = ll->x + (ur->x - lr->x); 239 ul.y = ll->y + (ur->y - lr->y); 240 241 build_inv_matrix(imat,c,pdv->image,img,ll,&ul,lr,ur); 242 243 ll_i = (c->y0 - ll->y)/c->yfac; 244 lr_i = (c->y0 - lr->y)/c->yfac; 245 ur_i = (c->y0 - ur->y)/c->yfac; 246 ul_i = (c->y0 - ul.y)/c->yfac; 247 248 iscan0 = (int)ceil(ll_i); 249 if (lr_i < iscan0) iscan0 = (int)ceil(lr_i); 250 if (ur_i < iscan0) iscan0 = (int)ceil(ur_i); 251 if (ul_i < iscan0) iscan0 = (int)ceil(ul_i); 252 253 if (iscan0 < c->iscan0) iscan0 = c->iscan0; 254 255 iscan1 = (int)floor(ll_i); 256 if (lr_i > iscan1) iscan1 = (int)floor(lr_i); 257 if (ur_i > iscan1) iscan1 = (int)floor(ur_i); 258 if (ul_i > iscan1) iscan1 = (int)floor(ul_i); 259 260 if (iscan1 > c->iscan1) iscan1 = c->iscan1; 261 262#ifdef HPGS_PAINT_IMAGE_DEBUG 263 hpgs_log("ll_i,lr_i,ur_i,ul_i,iscan0,iscan1=%lg,%lg,%lg,%lg,%d,%d.\n", 264 ll_i,lr_i,ur_i,ul_i,iscan0,iscan1); 265 266 print_mat_6(stderr,"imat = ",imat); 267#endif 268 269 for (iscan = iscan0; iscan <= iscan1; ++iscan) 270 { 271 double x[2]; 272 int ix = 0; 273 int io; 274 const hpgs_paint_scanline *scanline = c->scanlines+iscan; 275 276 if ((iscan > ll_i && iscan < lr_i) || 277 (iscan < ll_i && iscan > lr_i) ) 278 { 279 x[ix] = ((ll_i - iscan)*lr->x + (iscan - lr_i)*ll->x) / (ll_i-lr_i); 280 ++ix; 281 } 282 283 if ((iscan > lr_i && iscan < ur_i) || 284 (iscan < lr_i && iscan > ur_i) ) 285 { 286 x[ix] = ((lr_i - iscan)*ur->x + (iscan - ur_i)*lr->x) / (lr_i-ur_i); 287 ++ix; 288 } 289 if ((iscan > ur_i && iscan < ul_i) || 290 (iscan < ur_i && iscan > ul_i) ) 291 { 292 x[ix] = ((ur_i - iscan)*ul.x + (iscan - ul_i)*ur->x) / (ur_i-ul_i); 293 ++ix; 294 } 295 if ((iscan > ul_i && iscan < ll_i) || 296 (iscan < ul_i && iscan > ll_i) ) 297 { 298 x[ix] = ((ul_i - iscan)*ll->x + (iscan - ll_i)*ul.x) / (ul_i-ll_i); 299 ++ix; 300 } 301 302 if (ix!=2) continue; 303 304 if (x[0] > x[1]) 305 { 306 double tmp = x[0]; 307 x[0] = x[1]; 308 x[1] = tmp; 309 } 310 311 if (pdv->overscan) 312 { 313 int out_state = 0; 314 io = 0; 315 316 // go through clip segments antialiased 317 while (io<scanline->n_points) 318 { 319 double xleft,xright,ixleft,ixright; 320 double ileft,iright,ii,alpha_left,alpha_right; 321 hpgs_point src_point; 322 323 xleft= scanline->points[io].x; 324 325 while (io<scanline->n_points && scanline->points[io].x == xleft) 326 { 327 out_state += scanline->points[io].order; 328 ++io; 329 } 330 331 if (io >= scanline->n_points) break; 332 333 alpha_left = out_state/256.0; 334 335 xright = scanline->points[io].x; 336 alpha_right = (out_state+scanline->points[io].order)/256.0; 337 338 ixright = xright; 339 ixleft = xleft; 340 341 if (ixleft < x[0]) ixleft = x[0]; 342 if (ixleft > x[1]) ixleft = x[1]; 343 344 if (ixright < x[0]) ixright = x[0]; 345 if (ixright > x[1]) ixright = x[1]; 346 347 if ((alpha_left == 0.0 && alpha_right == 0.0) || 348 ixleft >= ixright) continue; 349 350 ixleft = pdv->image->width*(ixleft-c->bb.llx) / (c->bb.urx-c->bb.llx); 351 ixright = pdv->image->width*(ixright-c->bb.llx) / (c->bb.urx-c->bb.llx); 352 353 ileft = ceil(ixleft); 354 iright = floor(ixright); 355 356 // output left corner points with alpha 357 if (ileft >= 1.0) 358 { 359 double alpha = (ileft - ixleft) * 360 (alpha_left*(xright-0.5*(ileft+xleft))+alpha_right*(0.5*(ileft+xleft)-xleft))/(xright-xleft); 361 362 mat_6_mul(&src_point,imat,ileft-1.0,iscan); 363 364 if (put_point_func(pdv->image,img,ileft-1.0,iscan,&src_point,alpha)) 365 return -1; 366 367#ifdef HPGS_PAINT_IMAGE_DEBUG 368 hpgs_log("src: %lg,%lg, dest: %lg,%d.\n", 369 src_point->x,src_point->y,ileft-1.0,iscan); 370#endif 371 } 372 373 // output intermediate pixels. 374 for (ii = ileft; ii < iright; ++ii) 375 { 376 double alpha = (alpha_left*(xright-(ii+0.5))+alpha_right*((ii+0.5)-xleft))/(xright-xleft); 377 378 mat_6_mul(&src_point,imat,ii,iscan); 379 if (put_point_func(pdv->image,img,ii,iscan,&src_point,alpha)) 380 return -1; 381 } 382 383 // output right corner points with alpha 384 if (iright >= ileft && iright < pdv->image->width) 385 { 386 double alpha = (ixright - iright) * 387 (alpha_left*(xright-0.5*(iright+xright))+alpha_right*(0.5*(iright+xright)-xleft))/(xright-xleft); 388 389 mat_6_mul(&src_point,imat,iright,iscan); 390 391 if (put_point_func(pdv->image,img,iright,iscan,&src_point,alpha)) 392 return -1; 393 394#ifdef HPGS_PAINT_IMAGE_DEBUG 395 hpgs_log("src: %lg,%lg, dest: %lg,%d.\n", 396 src_point->x,src_point->y,iright,iscan); 397#endif 398 } 399 } 400 } 401 else 402 { 403 // go through clip segments - non-antialiased 404 for (io = 0; io+1<scanline->n_points; io+=2) 405 { 406 double xleft= scanline->points[io].x; 407 double xright= scanline->points[io+1].x; 408 double ileft,iright,ii; 409 hpgs_point src_point; 410 411 if (xleft < x[0]) xleft = x[0]; 412 if (xleft > x[1]) xleft = x[1]; 413 414 if (xright < x[0]) xright = x[0]; 415 if (xright > x[1]) xright = x[1]; 416 417 if (xleft >= xright) continue; 418 419 xleft = pdv->image->width*(xleft-c->bb.llx) / (c->bb.urx-c->bb.llx); 420 xright = pdv->image->width*(xright-c->bb.llx) / (c->bb.urx-c->bb.llx); 421 422 ileft = ceil(xleft); 423 iright = floor(xright); 424 425 // output left corner points with alpha 426 if (ileft >= 1.0) 427 { 428 double alpha = ileft - xleft; 429 430 mat_6_mul(&src_point,imat,ileft-1.0,iscan); 431 432 if (put_point_func(pdv->image,img,ileft-1.0,iscan,&src_point,alpha)) 433 return -1; 434 435#ifdef HPGS_PAINT_IMAGE_DEBUG 436 hpgs_log("src: %lg,%lg, dest: %lg,%d.\n", 437 src_point->x,src_point->y,ileft-1.0,iscan); 438#endif 439 } 440 441 // output intermediate pixels. 442 for (ii = ileft; ii < iright; ++ii) 443 { 444 mat_6_mul(&src_point,imat,ii,iscan); 445 if (put_point_func(pdv->image,img,ii,iscan,&src_point,1.0)) 446 return -1; 447 } 448 449 // output right corner points with alpha 450 if (iright >= ileft && iright < pdv->image->width) 451 { 452 double alpha = xright - iright; 453 454 mat_6_mul(&src_point,imat,iright,iscan); 455 456 if (put_point_func(pdv->image,img,iright,iscan,&src_point,alpha)) 457 return -1; 458 459#ifdef HPGS_PAINT_IMAGE_DEBUG 460 hpgs_log("src: %lg,%lg, dest: %lg,%d.\n", 461 src_point->x,src_point->y,iright,iscan); 462#endif 463 } 464 } 465 } 466 } 467 468 return 0; 469} 470