| 170 | | #ifdef USE_GRAPHICS |
|---|
| 171 | | |
|---|
| 172 | | /* |
|---|
| 173 | | * The Win32 "BITMAPFILEHEADER" type. |
|---|
| 174 | | */ |
|---|
| 175 | | typedef struct BITMAPFILEHEADER |
|---|
| 176 | | { |
|---|
| 177 | | u16b bfType; |
|---|
| 178 | | u32b bfSize; |
|---|
| 179 | | u16b bfReserved1; |
|---|
| 180 | | u16b bfReserved2; |
|---|
| 181 | | u32b bfOffBits; |
|---|
| 182 | | } BITMAPFILEHEADER; |
|---|
| 183 | | |
|---|
| 184 | | |
|---|
| 185 | | /* |
|---|
| 186 | | * The Win32 "BITMAPINFOHEADER" type. |
|---|
| 187 | | */ |
|---|
| 188 | | typedef struct BITMAPINFOHEADER |
|---|
| 189 | | { |
|---|
| 190 | | u32b biSize; |
|---|
| 191 | | u32b biWidth; |
|---|
| 192 | | u32b biHeight; |
|---|
| 193 | | u16b biPlanes; |
|---|
| 194 | | u16b biBitCount; |
|---|
| 195 | | u32b biCompresion; |
|---|
| 196 | | u32b biSizeImage; |
|---|
| 197 | | u32b biXPelsPerMeter; |
|---|
| 198 | | u32b biYPelsPerMeter; |
|---|
| 199 | | u32b biClrUsed; |
|---|
| 200 | | u32b biClrImportand; |
|---|
| 201 | | } BITMAPINFOHEADER; |
|---|
| 202 | | |
|---|
| 203 | | /* |
|---|
| 204 | | * The Win32 "RGBQUAD" type. |
|---|
| 205 | | */ |
|---|
| 206 | | typedef struct RGBQUAD |
|---|
| 207 | | { |
|---|
| 208 | | unsigned char b, g, r; |
|---|
| 209 | | unsigned char filler; |
|---|
| 210 | | } RGBQUAD; |
|---|
| 211 | | |
|---|
| 212 | | |
|---|
| 213 | | /*** Helper functions for system independent file loading. ***/ |
|---|
| 214 | | |
|---|
| 215 | | static byte get_byte(FILE *fff) |
|---|
| 216 | | { |
|---|
| 217 | | /* Get a character, and return it */ |
|---|
| 218 | | return (getc(fff) & 0xFF); |
|---|
| 219 | | } |
|---|
| 220 | | |
|---|
| 221 | | static void rd_byte(FILE *fff, byte *ip) |
|---|
| 222 | | { |
|---|
| 223 | | *ip = get_byte(fff); |
|---|
| 224 | | } |
|---|
| 225 | | |
|---|
| 226 | | static void rd_u16b(FILE *fff, u16b *ip) |
|---|
| 227 | | { |
|---|
| 228 | | (*ip) = get_byte(fff); |
|---|
| 229 | | (*ip) |= ((u16b)(get_byte(fff)) << 8); |
|---|
| 230 | | } |
|---|
| 231 | | |
|---|
| 232 | | static void rd_u32b(FILE *fff, u32b *ip) |
|---|
| 233 | | { |
|---|
| 234 | | (*ip) = get_byte(fff); |
|---|
| 235 | | (*ip) |= ((u32b)(get_byte(fff)) << 8); |
|---|
| 236 | | (*ip) |= ((u32b)(get_byte(fff)) << 16); |
|---|
| 237 | | (*ip) |= ((u32b)(get_byte(fff)) << 24); |
|---|
| 238 | | } |
|---|
| 239 | | |
|---|
| 240 | | |
|---|
| 241 | | /* |
|---|
| 242 | | * Read a Win32 BMP file. |
|---|
| 243 | | * |
|---|
| 244 | | * This function replaces the old ReadRaw and RemapColors functions. |
|---|
| 245 | | * |
|---|
| 246 | | * Assumes that the bitmap has a size such that no padding is needed in |
|---|
| 247 | | * various places. Currently only handles bitmaps with 3 to 256 colors. |
|---|
| 248 | | */ |
|---|
| 249 | | XImage *ReadBMP(Display *dpy, char *Name) |
|---|
| 250 | | { |
|---|
| 251 | | Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy)); |
|---|
| 252 | | |
|---|
| 253 | | int depth = DefaultDepth(dpy, DefaultScreen(dpy)); |
|---|
| 254 | | |
|---|
| 255 | | FILE *f; |
|---|
| 256 | | |
|---|
| 257 | | BITMAPFILEHEADER fileheader; |
|---|
| 258 | | BITMAPINFOHEADER infoheader; |
|---|
| 259 | | |
|---|
| 260 | | XImage *Res = NULL; |
|---|
| 261 | | |
|---|
| 262 | | char *Data; |
|---|
| 263 | | |
|---|
| 264 | | int ncol; |
|---|
| 265 | | |
|---|
| 266 | | int total; |
|---|
| 267 | | |
|---|
| 268 | | int i, j; |
|---|
| 269 | | |
|---|
| 270 | | u32b x, y; |
|---|
| 271 | | |
|---|
| 272 | | unsigned long clr_pixels[256]; |
|---|
| 273 | | |
|---|
| 274 | | |
|---|
| 275 | | /* Open the BMP file */ |
|---|
| 276 | | f = fopen(Name, "r"); |
|---|
| 277 | | |
|---|
| 278 | | /* No such file */ |
|---|
| 279 | | if (f == NULL) |
|---|
| 280 | | { |
|---|
| 281 | | return (NULL); |
|---|
| 282 | | } |
|---|
| 283 | | |
|---|
| 284 | | /* Read the "BITMAPFILEHEADER" */ |
|---|
| 285 | | rd_u16b(f, &(fileheader.bfType)); |
|---|
| 286 | | rd_u32b(f, &(fileheader.bfSize)); |
|---|
| 287 | | rd_u16b(f, &(fileheader.bfReserved1)); |
|---|
| 288 | | rd_u16b(f, &(fileheader.bfReserved2)); |
|---|
| 289 | | rd_u32b(f, &(fileheader.bfOffBits)); |
|---|
| 290 | | |
|---|
| 291 | | /* Read the "BITMAPINFOHEADER" */ |
|---|
| 292 | | rd_u32b(f, &(infoheader.biSize)); |
|---|
| 293 | | rd_u32b(f, &(infoheader.biWidth)); |
|---|
| 294 | | rd_u32b(f, &(infoheader.biHeight)); |
|---|
| 295 | | rd_u16b(f, &(infoheader.biPlanes)); |
|---|
| 296 | | rd_u16b(f, &(infoheader.biBitCount)); |
|---|
| 297 | | rd_u32b(f, &(infoheader.biCompresion)); |
|---|
| 298 | | rd_u32b(f, &(infoheader.biSizeImage)); |
|---|
| 299 | | rd_u32b(f, &(infoheader.biXPelsPerMeter)); |
|---|
| 300 | | rd_u32b(f, &(infoheader.biYPelsPerMeter)); |
|---|
| 301 | | rd_u32b(f, &(infoheader.biClrUsed)); |
|---|
| 302 | | rd_u32b(f, &(infoheader.biClrImportand)); |
|---|
| 303 | | |
|---|
| 304 | | /* Verify the header */ |
|---|
| 305 | | if (feof(f) || |
|---|
| 306 | | (fileheader.bfType != 19778) || |
|---|
| 307 | | (infoheader.biSize != 40)) |
|---|
| 308 | | { |
|---|
| 309 | | quit_fmt("Incorrect BMP file format %s", Name); |
|---|
| 310 | | } |
|---|
| 311 | | |
|---|
| 312 | | /* The two headers above occupy 54 bytes total */ |
|---|
| 313 | | /* The "bfOffBits" field says where the data starts */ |
|---|
| 314 | | /* The "biClrUsed" field does not seem to be reliable */ |
|---|
| 315 | | /* Compute number of colors recorded */ |
|---|
| 316 | | ncol = (fileheader.bfOffBits - 54) / 4; |
|---|
| 317 | | |
|---|
| 318 | | for (i = 0; i < ncol; i++) |
|---|
| 319 | | { |
|---|
| 320 | | RGBQUAD clrg; |
|---|
| 321 | | |
|---|
| 322 | | /* Read an "RGBQUAD" */ |
|---|
| 323 | | rd_byte(f, &(clrg.b)); |
|---|
| 324 | | rd_byte(f, &(clrg.g)); |
|---|
| 325 | | rd_byte(f, &(clrg.r)); |
|---|
| 326 | | rd_byte(f, &(clrg.filler)); |
|---|
| 327 | | |
|---|
| 328 | | /* Analyze the color */ |
|---|
| 329 | | clr_pixels[i] = create_pixel(dpy, clrg.r, clrg.g, clrg.b); |
|---|
| 330 | | } |
|---|
| 331 | | |
|---|
| 332 | | /* Determine total bytes needed for image */ |
|---|
| 333 | | i = 1; |
|---|
| 334 | | j = (depth - 1) >> 2; |
|---|
| 335 | | while (j >>= 1) i <<= 1; |
|---|
| 336 | | total = infoheader.biWidth * infoheader.biHeight * i; |
|---|
| 337 | | |
|---|
| 338 | | /* Allocate image memory */ |
|---|
| 339 | | Data = C_ZNEW(total, char); |
|---|
| 340 | | |
|---|
| 341 | | Res = XCreateImage(dpy, visual, depth, ZPixmap, 0 /*offset*/, |
|---|
| 342 | | Data, infoheader.biWidth, infoheader.biHeight, |
|---|
| 343 | | 32 /*bitmap_pad*/, 0 /*bytes_per_line*/); |
|---|
| 344 | | |
|---|
| 345 | | /* Failure */ |
|---|
| 346 | | if (Res == NULL) |
|---|
| 347 | | { |
|---|
| 348 | | FREE(Data); |
|---|
| 349 | | fclose(f); |
|---|
| 350 | | return (NULL); |
|---|
| 351 | | } |
|---|
| 352 | | |
|---|
| 353 | | for (y = 0; y < infoheader.biHeight; y++) |
|---|
| 354 | | { |
|---|
| 355 | | u32b y2 = infoheader.biHeight - y - 1; |
|---|
| 356 | | |
|---|
| 357 | | for (x = 0; x < infoheader.biWidth; x++) |
|---|
| 358 | | { |
|---|
| 359 | | int ch = getc(f); |
|---|
| 360 | | |
|---|
| 361 | | /* Verify not at end of file XXX XXX */ |
|---|
| 362 | | if (feof(f)) quit_fmt("Unexpected end of file in %s", Name); |
|---|
| 363 | | |
|---|
| 364 | | if (infoheader.biBitCount == 24) |
|---|
| 365 | | { |
|---|
| 366 | | int c3, c2 = getc(f); |
|---|
| 367 | | |
|---|
| 368 | | /* Verify not at end of file XXX XXX */ |
|---|
| 369 | | if (feof(f)) quit_fmt("Unexpected end of file in %s", Name); |
|---|
| 370 | | |
|---|
| 371 | | c3 = getc(f); |
|---|
| 372 | | |
|---|
| 373 | | /* Verify not at end of file XXX XXX */ |
|---|
| 374 | | if (feof(f)) quit_fmt("Unexpected end of file in %s", Name); |
|---|
| 375 | | |
|---|
| 376 | | XPutPixel(Res, x, y2, create_pixel(dpy, ch, c2, c3)); |
|---|
| 377 | | } |
|---|
| 378 | | else if (infoheader.biBitCount == 8) |
|---|
| 379 | | { |
|---|
| 380 | | XPutPixel(Res, x, y2, clr_pixels[ch]); |
|---|
| 381 | | } |
|---|
| 382 | | else if (infoheader.biBitCount == 4) |
|---|
| 383 | | { |
|---|
| 384 | | XPutPixel(Res, x, y2, clr_pixels[ch / 16]); |
|---|
| 385 | | x++; |
|---|
| 386 | | XPutPixel(Res, x, y2, clr_pixels[ch % 16]); |
|---|
| 387 | | } |
|---|
| 388 | | else |
|---|
| 389 | | { |
|---|
| 390 | | /* Technically 1 bit is legal too */ |
|---|
| 391 | | quit_fmt("Illegal biBitCount %d in %s", |
|---|
| 392 | | infoheader.biBitCount, Name); |
|---|
| 393 | | } |
|---|
| 394 | | } |
|---|
| 395 | | } |
|---|
| 396 | | |
|---|
| 397 | | fclose(f); |
|---|
| 398 | | |
|---|
| 399 | | return Res; |
|---|
| 400 | | } |
|---|
| 401 | | |
|---|
| 402 | | |
|---|
| 403 | | /* ========================================================*/ |
|---|
| 404 | | /* Code for smooth icon rescaling from Uwe Siems, Jan 2000 */ |
|---|
| 405 | | /* ========================================================*/ |
|---|
| 406 | | |
|---|
| 407 | | /* |
|---|
| 408 | | * to save ourselves some labour, define a maximum expected icon width here: |
|---|
| 409 | | */ |
|---|
| 410 | | #define MAX_ICON_WIDTH 32 |
|---|
| 411 | | |
|---|
| 412 | | |
|---|
| 413 | | /* some static variables for composing and decomposing pixel values into |
|---|
| 414 | | * red, green and blue values |
|---|
| 415 | | */ |
|---|
| 416 | | static unsigned long redMask, greenMask, blueMask; |
|---|
| 417 | | static int redShift, greenShift, blueShift; |
|---|
| 418 | | |
|---|
| 419 | | |
|---|
| 420 | | /* |
|---|
| 421 | | * Use smooth rescaling? |
|---|
| 422 | | */ |
|---|
| 423 | | bool smoothRescaling = TRUE; |
|---|
| 424 | | |
|---|
| 425 | | |
|---|
| 426 | | /* |
|---|
| 427 | | * GetScaledRow reads a scan from the given XImage, scales it smoothly |
|---|
| 428 | | * and returns the red, green and blue values in arrays. |
|---|
| 429 | | * The values in this arrays must be divided by a certain value that is |
|---|
| 430 | | * calculated in ScaleIcon. |
|---|
| 431 | | * x, y is the position, iw is the input width and ow the output width |
|---|
| 432 | | * redScan, greenScan and blueScan must be sufficiently sized |
|---|
| 433 | | */ |
|---|
| 434 | | static void GetScaledRow(XImage *Im, int x, int y, int iw, int ow, |
|---|
| 435 | | unsigned long *redScan, unsigned long *greenScan, |
|---|
| 436 | | unsigned long *blueScan) |
|---|
| 437 | | { |
|---|
| 438 | | int xi, si, sifrac, ci, cifrac, addWhole, addFrac; |
|---|
| 439 | | unsigned long pix; |
|---|
| 440 | | int prevRed, prevGreen, prevBlue, nextRed, nextGreen, nextBlue; |
|---|
| 441 | | bool getNextPix; |
|---|
| 442 | | |
|---|
| 443 | | if (iw == ow) |
|---|
| 444 | | { |
|---|
| 445 | | /* unscaled */ |
|---|
| 446 | | for (xi = 0; xi < ow; xi++) |
|---|
| 447 | | { |
|---|
| 448 | | pix = XGetPixel(Im, x + xi, y); |
|---|
| 449 | | redScan [xi] = (pix >> redShift) & redMask; |
|---|
| 450 | | greenScan [xi] = (pix >> greenShift) & greenMask; |
|---|
| 451 | | blueScan [xi] = (pix >> blueShift) & blueMask; |
|---|
| 452 | | } |
|---|
| 453 | | } |
|---|
| 454 | | else if (iw < ow) |
|---|
| 455 | | { |
|---|
| 456 | | /* scaling by subsampling (grow) */ |
|---|
| 457 | | iw--; |
|---|
| 458 | | ow--; |
|---|
| 459 | | /* read first pixel: */ |
|---|
| 460 | | pix = XGetPixel(Im, x, y); |
|---|
| 461 | | nextRed = (pix >> redShift) & redMask; |
|---|
| 462 | | nextGreen = (pix >> greenShift) & greenMask; |
|---|
| 463 | | nextBlue = (pix >> blueShift) & blueMask; |
|---|
| 464 | | prevRed = nextRed; |
|---|
| 465 | | prevGreen = nextGreen; |
|---|
| 466 | | prevBlue = nextBlue; |
|---|
| 467 | | /* si and sifrac give the subsampling position: */ |
|---|
| 468 | | si = x; |
|---|
| 469 | | sifrac = 0; |
|---|
| 470 | | /* getNextPix tells us, that we need the next pixel */ |
|---|
| 471 | | getNextPix = TRUE; |
|---|
| 472 | | |
|---|
| 473 | | for (xi = 0; xi <= ow; xi++) |
|---|
| 474 | | { |
|---|
| 475 | | if (getNextPix) |
|---|
| 476 | | { |
|---|
| 477 | | prevRed = nextRed; |
|---|
| 478 | | prevGreen = nextGreen; |
|---|
| 479 | | prevBlue = nextBlue; |
|---|
| 480 | | if (xi < ow) |
|---|
| 481 | | { |
|---|
| 482 | | /* only get next pixel if in same icon */ |
|---|
| 483 | | pix = XGetPixel(Im, si + 1, y); |
|---|
| 484 | | nextRed = (pix >> redShift) & redMask; |
|---|
| 485 | | nextGreen = (pix >> greenShift) & greenMask; |
|---|
| 486 | | nextBlue = (pix >> blueShift) & blueMask; |
|---|
| 487 | | } |
|---|
| 488 | | } |
|---|
| 489 | | |
|---|
| 490 | | /* calculate subsampled color values: */ |
|---|
| 491 | | /* division by ow occurs in ScaleIcon */ |
|---|
| 492 | | redScan [xi] = prevRed * (ow - sifrac) + nextRed * sifrac; |
|---|
| 493 | | greenScan [xi] = prevGreen * (ow - sifrac) + nextGreen * sifrac; |
|---|
| 494 | | blueScan [xi] = prevBlue * (ow - sifrac) + nextBlue * sifrac; |
|---|
| 495 | | |
|---|
| 496 | | /* advance sampling position: */ |
|---|
| 497 | | sifrac += iw; |
|---|
| 498 | | if (sifrac >= ow) |
|---|
| 499 | | { |
|---|
| 500 | | si++; |
|---|
| 501 | | sifrac -= ow; |
|---|
| 502 | | getNextPix = TRUE; |
|---|
| 503 | | } |
|---|
| 504 | | else |
|---|
| 505 | | { |
|---|
| 506 | | getNextPix = FALSE; |
|---|
| 507 | | } |
|---|
| 508 | | |
|---|
| 509 | | } |
|---|
| 510 | | } |
|---|
| 511 | | else |
|---|
| 512 | | { |
|---|
| 513 | | /* scaling by averaging (shrink) */ |
|---|
| 514 | | /* width of an output pixel in input pixels: */ |
|---|
| 515 | | addWhole = iw / ow; |
|---|
| 516 | | addFrac = iw % ow; |
|---|
| 517 | | /* start position of the first output pixel: */ |
|---|
| 518 | | si = x; |
|---|
| 519 | | sifrac = 0; |
|---|
| 520 | | /* get first input pixel: */ |
|---|
| 521 | | pix = XGetPixel(Im, x, y); |
|---|
| 522 | | nextRed = (pix >> redShift) & redMask; |
|---|
| 523 | | nextGreen = (pix >> greenShift) & greenMask; |
|---|
| 524 | | nextBlue = (pix >> blueShift) & blueMask; |
|---|
| 525 | | for (xi = 0; xi < ow; xi++) |
|---|
| 526 | | { |
|---|
| 527 | | /* find endpoint of the current output pixel: */ |
|---|
| 528 | | ci = si + addWhole; |
|---|
| 529 | | cifrac = sifrac + addFrac; |
|---|
| 530 | | if (cifrac >= ow) |
|---|
| 531 | | { |
|---|
| 532 | | ci++; |
|---|
| 533 | | cifrac -= ow; |
|---|
| 534 | | } |
|---|
| 535 | | /* take fraction of current input pixel (starting segment): */ |
|---|
| 536 | | redScan[xi] = nextRed * (ow - sifrac); |
|---|
| 537 | | greenScan[xi] = nextGreen * (ow - sifrac); |
|---|
| 538 | | blueScan[xi] = nextBlue * (ow - sifrac); |
|---|
| 539 | | si++; |
|---|
| 540 | | /* add values for whole pixels: */ |
|---|
| 541 | | while (si < ci) |
|---|
| 542 | | { |
|---|
| 543 | | pix = XGetPixel(Im, si, y); |
|---|
| 544 | | redScan[xi] += ((pix >> redShift) & redMask) *ow; |
|---|
| 545 | | greenScan[xi] += ((pix >> greenShift) & greenMask) *ow; |
|---|
| 546 | | blueScan[xi] += ((pix >> blueShift) & blueMask) *ow; |
|---|
| 547 | | si++; |
|---|
| 548 | | } |
|---|
| 549 | | /* add fraction of current input pixel (ending segment): */ |
|---|
| 550 | | if (xi < ow - 1) |
|---|
| 551 | | { |
|---|
| 552 | | /* only get next pixel if still in icon: */ |
|---|
| 553 | | pix = XGetPixel(Im, si, y); |
|---|
| 554 | | nextRed = (pix >> redShift) & redMask; |
|---|
| 555 | | nextGreen = (pix >> greenShift) & greenMask; |
|---|
| 556 | | nextBlue = (pix >> blueShift) & blueMask; |
|---|
| 557 | | } |
|---|
| 558 | | sifrac = cifrac; |
|---|
| 559 | | if (sifrac > 0) |
|---|
| 560 | | { |
|---|
| 561 | | redScan[xi] += nextRed * sifrac; |
|---|
| 562 | | greenScan[xi] += nextGreen * sifrac; |
|---|
| 563 | | blueScan[xi] += nextBlue * sifrac; |
|---|
| 564 | | } |
|---|
| 565 | | } |
|---|
| 566 | | } |
|---|
| 567 | | } |
|---|
| 568 | | |
|---|
| 569 | | |
|---|
| 570 | | /* |
|---|
| 571 | | * PutRGBScan takes arrays for red, green and blue and writes pixel values |
|---|
| 572 | | * according to this values in the XImage-structure. w is the number of |
|---|
| 573 | | * pixels to write and div is the value by which all red/green/blue values |
|---|
| 574 | | * are divided first. |
|---|
| 575 | | */ |
|---|
| 576 | | static void PutRGBScan(XImage *Im, int x, int y, int w, int div, |
|---|
| 577 | | unsigned long *redScan, unsigned long *greenScan, |
|---|
| 578 | | unsigned long *blueScan) |
|---|
| 579 | | { |
|---|
| 580 | | int xi; |
|---|
| 581 | | unsigned long pix; |
|---|
| 582 | | unsigned long adj = div / 2; |
|---|
| 583 | | for (xi = 0; xi < w; xi++) |
|---|
| 584 | | { |
|---|
| 585 | | pix = (((((redScan[xi] + adj) / div) & redMask) << redShift) + |
|---|
| 586 | | ((((greenScan[xi] + adj) / div) & greenMask) << greenShift) + |
|---|
| 587 | | ((((blueScan[xi] + adj) / div) & blueMask) << blueShift)); |
|---|
| 588 | | XPutPixel(Im, x + xi, y, pix); |
|---|
| 589 | | } |
|---|
| 590 | | } |
|---|
| 591 | | |
|---|
| 592 | | |
|---|
| 593 | | /* |
|---|
| 594 | | * ScaleIcon transfers an area from XImage ImIn, locate (x1,y1) to ImOut, |
|---|
| 595 | | * locate (x2, y2). |
|---|
| 596 | | * Source size is (ix, iy) and destination size is (ox, oy). |
|---|
| 597 | | * It does this by getting icon scan line from GetScaledScan and handling |
|---|
| 598 | | * them the same way as pixels are handled in GetScaledScan. |
|---|
| 599 | | * This even allows icons to be scaled differently in horizontal and |
|---|
| 600 | | * vertical directions (eg. shrink horizontal, grow vertical). |
|---|
| 601 | | */ |
|---|
| 602 | | static void ScaleIcon(XImage *ImIn, XImage *ImOut, |
|---|
| 603 | | int x1, int y1, int x2, int y2, |
|---|
| 604 | | int ix, int iy, int ox, int oy) |
|---|
| 605 | | { |
|---|
| 606 | | int div; |
|---|
| 607 | | int xi, yi, si, sifrac, ci, cifrac, addWhole, addFrac; |
|---|
| 608 | | |
|---|
| 609 | | /* buffers for pixel rows: */ |
|---|
| 610 | | unsigned long prevRed [MAX_ICON_WIDTH]; |
|---|
| 611 | | unsigned long prevGreen [MAX_ICON_WIDTH]; |
|---|
| 612 | | unsigned long prevBlue [MAX_ICON_WIDTH]; |
|---|
| 613 | | unsigned long nextRed [MAX_ICON_WIDTH]; |
|---|
| 614 | | unsigned long nextGreen [MAX_ICON_WIDTH]; |
|---|
| 615 | | unsigned long nextBlue [MAX_ICON_WIDTH]; |
|---|
| 616 | | unsigned long tempRed [MAX_ICON_WIDTH]; |
|---|
| 617 | | unsigned long tempGreen [MAX_ICON_WIDTH]; |
|---|
| 618 | | unsigned long tempBlue [MAX_ICON_WIDTH]; |
|---|
| 619 | | |
|---|
| 620 | | bool getNextRow; |
|---|
| 621 | | |
|---|
| 622 | | /* get divider value for the horizontal scaling: */ |
|---|
| 623 | | if (ix == ox) |
|---|
| 624 | | div = 1; |
|---|
| 625 | | else if (ix < ox) |
|---|
| 626 | | div = ox - 1; |
|---|
| 627 | | else |
|---|
| 628 | | div = ix; |
|---|
| 629 | | |
|---|
| 630 | | if (iy == oy) |
|---|
| 631 | | { |
|---|
| 632 | | /* no scaling needed vertically: */ |
|---|
| 633 | | for (yi = 0; yi < oy; yi++) |
|---|
| 634 | | { |
|---|
| 635 | | GetScaledRow(ImIn, x1, y1 + yi, ix, ox, |
|---|
| 636 | | tempRed, tempGreen, tempBlue); |
|---|
| 637 | | PutRGBScan(ImOut, x2, y2 + yi, ox, div, |
|---|
| 638 | | tempRed, tempGreen, tempBlue); |
|---|
| 639 | | } |
|---|
| 640 | | } |
|---|
| 641 | | else if (iy < oy) |
|---|
| 642 | | { |
|---|
| 643 | | /* scaling by subsampling (grow): */ |
|---|
| 644 | | iy--; |
|---|
| 645 | | oy--; |
|---|
| 646 | | div *= oy; |
|---|
| 647 | | |
|---|
| 648 | | /* get first row: */ |
|---|
| 649 | | GetScaledRow(ImIn, x1, y1, ix, ox, nextRed, nextGreen, nextBlue); |
|---|
| 650 | | |
|---|
| 651 | | /* si and sifrac give the subsampling position: */ |
|---|
| 652 | | si = y1; |
|---|
| 653 | | sifrac = 0; |
|---|
| 654 | | |
|---|
| 655 | | /* getNextRow tells us, that we need the next row */ |
|---|
| 656 | | getNextRow = TRUE; |
|---|
| 657 | | |
|---|
| 658 | | for (yi = 0; yi <= oy; yi++) |
|---|
| 659 | | { |
|---|
| 660 | | if (getNextRow) |
|---|
| 661 | | { |
|---|
| 662 | | for (xi = 0; xi < ox; xi++) |
|---|
| 663 | | { |
|---|
| 664 | | prevRed[xi] = nextRed[xi]; |
|---|
| 665 | | prevGreen[xi] = nextGreen[xi]; |
|---|
| 666 | | prevBlue[xi] = nextBlue[xi]; |
|---|
| 667 | | } |
|---|
| 668 | | |
|---|
| 669 | | if (yi < oy) |
|---|
| 670 | | { |
|---|
| 671 | | /* only get next row if in same icon */ |
|---|
| 672 | | GetScaledRow(ImIn, x1, si + 1, ix, ox, |
|---|
| 673 | | nextRed, nextGreen, nextBlue); |
|---|
| 674 | | } |
|---|
| 675 | | } |
|---|
| 676 | | |
|---|
| 677 | | /* calculate subsampled color values: */ |
|---|
| 678 | | /* division by oy occurs in PutRGBScan */ |
|---|
| 679 | | for (xi = 0; xi < ox; xi++) |
|---|
| 680 | | { |
|---|
| 681 | | tempRed[xi] = (prevRed[xi] * (oy - sifrac) + |
|---|
| 682 | | nextRed[xi] * sifrac); |
|---|
| 683 | | tempGreen[xi] = (prevGreen[xi] * (oy - sifrac) + |
|---|
| 684 | | nextGreen[xi] * sifrac); |
|---|
| 685 | | tempBlue[xi] = (prevBlue[xi] * (oy - sifrac) + |
|---|
| 686 | | nextBlue[xi] * sifrac); |
|---|
| 687 | | } |
|---|
| 688 | | |
|---|
| 689 | | /* write row to output image: */ |
|---|
| 690 | | PutRGBScan(ImOut, x2, y2 + yi, ox, div, |
|---|
| 691 | | tempRed, tempGreen, tempBlue); |
|---|
| 692 | | |
|---|
| 693 | | /* advance sampling position: */ |
|---|
| 694 | | sifrac += iy; |
|---|
| 695 | | if (sifrac >= oy) |
|---|
| 696 | | { |
|---|
| 697 | | si++; |
|---|
| 698 | | sifrac -= oy; |
|---|
| 699 | | getNextRow = TRUE; |
|---|
| 700 | | } |
|---|
| 701 | | else |
|---|
| 702 | | { |
|---|
| 703 | | getNextRow = FALSE; |
|---|
| 704 | | } |
|---|
| 705 | | } |
|---|
| 706 | | } |
|---|
| 707 | | else |
|---|
| 708 | | { |
|---|
| 709 | | /* scaling by averaging (shrink) */ |
|---|
| 710 | | div *= iy; |
|---|
| 711 | | |
|---|
| 712 | | /* height of a output row in input rows: */ |
|---|
| 713 | | addWhole = iy / oy; |
|---|
| 714 | | addFrac = iy % oy; |
|---|
| 715 | | |
|---|
| 716 | | /* start position of the first output row: */ |
|---|
| 717 | | si = y1; |
|---|
| 718 | | sifrac = 0; |
|---|
| 719 | | |
|---|
| 720 | | /* get first input row: */ |
|---|
| 721 | | GetScaledRow(ImIn, x1, y1, ix, ox, nextRed, nextGreen, nextBlue); |
|---|
| 722 | | |
|---|
| 723 | | for (yi = 0; yi < oy; yi++) |
|---|
| 724 | | { |
|---|
| 725 | | /* find endpoint of the current output row: */ |
|---|
| 726 | | ci = si + addWhole; |
|---|
| 727 | | cifrac = sifrac + addFrac; |
|---|
| 728 | | |
|---|
| 729 | | if (cifrac >= oy) |
|---|
| 730 | | { |
|---|
| 731 | | ci++; |
|---|
| 732 | | cifrac -= oy; |
|---|
| 733 | | } |
|---|
| 734 | | |
|---|
| 735 | | /* take fraction of current input row (starting segment): */ |
|---|
| 736 | | for (xi = 0; xi < ox; xi++) |
|---|
| 737 | | { |
|---|
| 738 | | tempRed[xi] = nextRed[xi] * (oy - sifrac); |
|---|
| 739 | | tempGreen[xi] = nextGreen[xi] * (oy - sifrac); |
|---|
| 740 | | tempBlue[xi] = nextBlue[xi] * (oy - sifrac); |
|---|
| 741 | | } |
|---|
| 742 | | |
|---|
| 743 | | si++; |
|---|
| 744 | | |
|---|
| 745 | | /* add values for whole pixels: */ |
|---|
| 746 | | while (si < ci) |
|---|
| 747 | | { |
|---|
| 748 | | GetScaledRow(ImIn, x1, si, ix, ox, |
|---|
| 749 | | nextRed, nextGreen, nextBlue); |
|---|
| 750 | | |
|---|
| 751 | | for (xi = 0; xi < ox; xi++) |
|---|
| 752 | | { |
|---|
| 753 | | tempRed[xi] += nextRed[xi] * oy; |
|---|
| 754 | | tempGreen[xi] += nextGreen[xi] * oy; |
|---|
| 755 | | tempBlue[xi] += nextBlue[xi] * oy; |
|---|
| 756 | | } |
|---|
| 757 | | si++; |
|---|
| 758 | | } |
|---|
| 759 | | |
|---|
| 760 | | /* add fraction of current input row (ending segment): */ |
|---|
| 761 | | if (yi < oy - 1) |
|---|
| 762 | | { |
|---|
| 763 | | /* only get next row if still in icon: */ |
|---|
| 764 | | GetScaledRow(ImIn, x1, si, ix, ox, |
|---|
| 765 | | nextRed, nextGreen, nextBlue); |
|---|
| 766 | | } |
|---|
| 767 | | |
|---|
| 768 | | sifrac = cifrac; |
|---|
| 769 | | |
|---|
| 770 | | for (xi = 0; xi < ox; xi++) |
|---|
| 771 | | { |
|---|
| 772 | | tempRed[xi] += nextRed[xi] * sifrac; |
|---|
| 773 | | tempGreen[xi] += nextGreen[xi] * sifrac; |
|---|
| 774 | | tempBlue[xi] += nextBlue[xi] * sifrac; |
|---|
| 775 | | } |
|---|
| 776 | | |
|---|
| 777 | | /* write row to output image: */ |
|---|
| 778 | | PutRGBScan(ImOut, x2, y2 + yi, ox, div, |
|---|
| 779 | | tempRed, tempGreen, tempBlue); |
|---|
| 780 | | } |
|---|
| 781 | | } |
|---|
| 782 | | } |
|---|
| 783 | | |
|---|
| 784 | | |
|---|
| 785 | | |
|---|
| 786 | | static XImage *ResizeImageSmooth(Display *dpy, XImage *Im, |
|---|
| 787 | | int ix, int iy, int ox, int oy) |
|---|
| 788 | | { |
|---|
| 789 | | Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy)); |
|---|
| 790 | | |
|---|
| 791 | | int width1, height1, width2, height2; |
|---|
| 792 | | int x1, x2, y1, y2; |
|---|
| 793 | | |
|---|
| 794 | | XImage *Tmp; |
|---|
| 795 | | |
|---|
| 796 | | char *Data; |
|---|
| 797 | | |
|---|
| 798 | | width1 = Im->width; |
|---|
| 799 | | height1 = Im->height; |
|---|
| 800 | | |
|---|
| 801 | | width2 = ox * width1 / ix; |
|---|
| 802 | | height2 = oy * height1 / iy; |
|---|
| 803 | | |
|---|
| 804 | | Data = (char *)malloc(width2 * height2 * Im->bits_per_pixel / 8); |
|---|
| 805 | | |
|---|
| 806 | | Tmp = XCreateImage(dpy, visual, |
|---|
| 807 | | Im->depth, ZPixmap, 0, Data, width2, height2, |
|---|
| 808 | | 32, 0); |
|---|
| 809 | | |
|---|
| 810 | | /* compute values for decomposing pixel into color values: */ |
|---|
| 811 | | redMask = Im->red_mask; |
|---|
| 812 | | redShift = 0; |
|---|
| 813 | | |
|---|
| 814 | | while ((redMask & 1) == 0) |
|---|
| 815 | | { |
|---|
| 816 | | redShift++; |
|---|
| 817 | | redMask >>= 1; |
|---|
| 818 | | } |
|---|
| 819 | | |
|---|
| 820 | | greenMask = Im->green_mask; |
|---|
| 821 | | greenShift = 0; |
|---|
| 822 | | |
|---|
| 823 | | while ((greenMask & 1) == 0) |
|---|
| 824 | | { |
|---|
| 825 | | greenShift++; |
|---|
| 826 | | greenMask >>= 1; |
|---|
| 827 | | } |
|---|
| 828 | | |
|---|
| 829 | | blueMask = Im->blue_mask; |
|---|
| 830 | | blueShift = 0; |
|---|
| 831 | | |
|---|
| 832 | | while ((blueMask & 1) == 0) |
|---|
| 833 | | { |
|---|
| 834 | | blueShift++; |
|---|
| 835 | | blueMask >>= 1; |
|---|
| 836 | | } |
|---|
| 837 | | |
|---|
| 838 | | /* scale each icon: */ |
|---|
| 839 | | for (y1 = 0, y2 = 0; (y1 < height1) && (y2 < height2); y1 += iy, y2 += oy) |
|---|
| 840 | | { |
|---|
| 841 | | for (x1 = 0, x2 = 0; (x1 < width1) && (x2 < width2); x1 += ix, x2 += ox) |
|---|
| 842 | | { |
|---|
| 843 | | ScaleIcon(Im, Tmp, x1, y1, x2, y2, |
|---|
| 844 | | ix, iy, ox, oy); |
|---|
| 845 | | } |
|---|
| 846 | | } |
|---|
| 847 | | |
|---|
| 848 | | return Tmp; |
|---|
| 849 | | } |
|---|
| 850 | | |
|---|
| 851 | | |
|---|
| 852 | | /* |
|---|
| 853 | | * Resize an image. |
|---|
| 854 | | */ |
|---|
| 855 | | XImage *ResizeImage(Display *dpy, XImage *Im, |
|---|
| 856 | | int ix, int iy, int ox, int oy) |
|---|
| 857 | | { |
|---|
| 858 | | Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy)); |
|---|
| 859 | | |
|---|
| 860 | | int width1, height1, width2, height2; |
|---|
| 861 | | int x1, x2, y1, y2, Tx, Ty; |
|---|
| 862 | | int *px1, *px2, *dx1, *dx2; |
|---|
| 863 | | int *py1, *py2, *dy1, *dy2; |
|---|
| 864 | | |
|---|
| 865 | | XImage *Tmp; |
|---|
| 866 | | |
|---|
| 867 | | char *Data; |
|---|
| 868 | | |
|---|
| 869 | | if (smoothRescaling && (ix != ox || iy != oy) && |
|---|
| 870 | | (visual->class == TrueColor)) |
|---|
| 871 | | { |
|---|
| 872 | | return ResizeImageSmooth(dpy, Im, ix, iy, ox, oy); |
|---|
| 873 | | } |
|---|
| 874 | | |
|---|
| 875 | | width1 = Im->width; |
|---|
| 876 | | height1 = Im->height; |
|---|
| 877 | | |
|---|
| 878 | | width2 = ox * width1 / ix; |
|---|
| 879 | | height2 = oy * height1 / iy; |
|---|
| 880 | | |
|---|
| 881 | | Data = (char *)malloc(width2 * height2 * Im->bits_per_pixel / 8); |
|---|
| 882 | | |
|---|
| 883 | | Tmp = XCreateImage(dpy, visual, |
|---|
| 884 | | Im->depth, ZPixmap, 0, Data, width2, height2, |
|---|
| 885 | | 32, 0); |
|---|
| 886 | | |
|---|
| 887 | | if (ix > ox) |
|---|
| 888 | | { |
|---|
| 889 | | px1 = &x1; |
|---|
| 890 | | px2 = &x2; |
|---|
| 891 | | dx1 = &ix; |
|---|
| 892 | | dx2 = &ox; |
|---|
| 893 | | } |
|---|
| 894 | | else |
|---|
| 895 | | { |
|---|
| 896 | | px1 = &x2; |
|---|
| 897 | | px2 = &x1; |
|---|
| 898 | | dx1 = &ox; |
|---|
| 899 | | dx2 = &ix; |
|---|
| 900 | | } |
|---|
| 901 | | |
|---|
| 902 | | if (iy > oy) |
|---|
| 903 | | { |
|---|
| 904 | | py1 = &y1; |
|---|
| 905 | | py2 = &y2; |
|---|
| 906 | | dy1 = &iy; |
|---|
| 907 | | dy2 = &oy; |
|---|
| 908 | | } |
|---|
| 909 | | else |
|---|
| 910 | | { |
|---|
| 911 | | py1 = &y2; |
|---|
| 912 | | py2 = &y1; |
|---|
| 913 | | dy1 = &oy; |
|---|
| 914 | | dy2 = &iy; |
|---|
| 915 | | } |
|---|
| 916 | | |
|---|
| 917 | | Ty = *dy1/2; |
|---|
| 918 | | |
|---|
| 919 | | for (y1 = 0, y2 = 0; (y1 < height1) && (y2 < height2); ) |
|---|
| 920 | | { |
|---|
| 921 | | Tx = *dx1/2; |
|---|
| 922 | | |
|---|
| 923 | | for (x1 = 0, x2 = 0; (x1 < width1) && (x2 < width2); ) |
|---|
| 924 | | { |
|---|
| 925 | | XPutPixel(Tmp, x2, y2, XGetPixel(Im, x1, y1)); |
|---|
| 926 | | |
|---|
| 927 | | (*px1)++; |
|---|
| 928 | | |
|---|
| 929 | | Tx -= *dx2; |
|---|
| 930 | | if (Tx < 0) |
|---|
| 931 | | { |
|---|
| 932 | | Tx += *dx1; |
|---|
| 933 | | (*px2)++; |
|---|
| 934 | | } |
|---|
| 935 | | } |
|---|
| 936 | | |
|---|
| 937 | | (*py1)++; |
|---|
| 938 | | |
|---|
| 939 | | Ty -= *dy2; |
|---|
| 940 | | if (Ty < 0) |
|---|
| 941 | | { |
|---|
| 942 | | Ty += *dy1; |
|---|
| 943 | | (*py2)++; |
|---|
| 944 | | } |
|---|
| 945 | | } |
|---|
| 946 | | |
|---|
| 947 | | return Tmp; |
|---|
| 948 | | } |
|---|
| 949 | | |
|---|
| 950 | | #endif /* USE_GRAPHICS */ |
|---|
| 951 | | |
|---|