~ubuntu-branches/ubuntu/maverick/crossfire-client/maverick

« back to all changes in this revision

Viewing changes to gtk/png.c

  • Committer: Bazaar Package Importer
  • Author(s): Kari Pahula
  • Date: 2007-04-13 21:15:44 UTC
  • mfrom: (1.2.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20070413211544-vjo6zesj6g0wgmwf
Tags: 1.10.0-1
* New upstream release
* Install the README, README-dev and TODO files specific to the GTK2
  client to the corresponding package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
const char *rcsid_gtk_png_c =
2
 
    "$Id: png.c,v 1.13 2006/02/23 20:18:28 akirschbaum Exp $";
 
2
    "$Id: png.c 4963 2006-09-21 05:50:22Z mwedel $";
3
3
/*
4
4
    Crossfire client, a client program for the crossfire program.
5
5
 
399
399
}
400
400
 
401
401
 
402
 
static guchar rgb[512*512*3];   /* Make this especially big to support larger images in the future */
403
 
 
404
402
/* This takes data that has already been converted into RGBA format (via
405
403
 * png_to_data above perhaps) and creates a GdkPixmap and GdkBitmap out
406
404
 * of it.
456
454
}
457
455
 
458
456
 
459
 
static int png_to_gdkpixmap(GdkWindow *window, uint8 *data, int len,
460
 
                   GdkPixmap **pix, GdkBitmap **mask, GdkColormap *colormap)
461
 
{
462
 
    static uint8 *pixels=NULL;
463
 
    static int pixels_byte=0, rows_byte=0;
464
 
    static png_bytepp   rows=NULL;
465
 
    unsigned long width, height;
466
 
    png_structp png_ptr;
467
 
    png_infop   info_ptr;
468
 
    int bit_depth, color_type, interlace_type, compression_type,
469
 
        bpp, x,y,has_alpha,i,alpha;
470
 
    GdkColor  scolor;
471
 
    GdkGC       *gc, *gc_alpha;
472
 
 
473
 
    data_len=len;
474
 
    data_cp = data;
475
 
    data_start=0;
476
 
 
477
 
    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
478
 
                                     NULL, NULL, NULL);
479
 
 
480
 
    if (!png_ptr) {
481
 
        return PNGX_OUTOFMEM;
482
 
    }
483
 
    info_ptr = png_create_info_struct (png_ptr);
484
 
 
485
 
    if (!info_ptr) {
486
 
        png_destroy_read_struct (&png_ptr, NULL, NULL);
487
 
        return PNGX_OUTOFMEM;
488
 
    }
489
 
    if (setjmp (png_ptr->jmpbuf)) {
490
 
        png_destroy_read_struct (&png_ptr, &info_ptr,NULL);
491
 
        return PNGX_DATA;
492
 
    }
493
 
    has_alpha=0;
494
 
    png_set_read_fn(png_ptr, NULL, user_read_data);
495
 
    png_read_info (png_ptr, info_ptr);
496
 
    
497
 
   /*
498
 
    * This seems to bug on at least one system (other than mine)
499
 
    * http://www.metalforge.net/cfmb/viewtopic.php?t=1085
500
 
    *
501
 
    * I think its actually a bug in libpng. This function dies with an 
502
 
    * error based on image width. However I've produced a work around
503
 
    * using the indivial functions. Repeated below.
504
 
    * 
505
 
    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
506
 
                 &color_type, &interlace_type, &compression_type, &filter_type);
507
 
    */
508
 
    width = png_get_image_width(png_ptr, info_ptr);
509
 
    height = png_get_image_height(png_ptr, info_ptr);
510
 
    bit_depth = png_get_bit_depth(png_ptr, info_ptr);
511
 
    color_type = png_get_color_type(png_ptr, info_ptr);
512
 
    interlace_type = png_get_interlace_type(png_ptr, info_ptr);
513
 
    compression_type = png_get_compression_type(png_ptr, info_ptr);
514
 
    if (color_type == PNG_COLOR_TYPE_PALETTE &&
515
 
            bit_depth <= 8) {
516
 
 
517
 
                /* Convert indexed images to RGB */
518
 
                png_set_expand (png_ptr);
519
 
 
520
 
    } else if (color_type == PNG_COLOR_TYPE_GRAY &&
521
 
                   bit_depth < 8) {
522
 
 
523
 
                /* Convert grayscale to RGB */
524
 
                png_set_expand (png_ptr);
525
 
 
526
 
    } else if (png_get_valid (png_ptr,
527
 
                                  info_ptr, PNG_INFO_tRNS)) {
528
 
 
529
 
                /* If we have transparency header, convert it to alpha
530
 
                   channel */
531
 
                png_set_expand(png_ptr);
532
 
 
533
 
    } else if (bit_depth < 8) {
534
 
 
535
 
                /* If we have < 8 scale it up to 8 */
536
 
                png_set_expand(png_ptr);
537
 
 
538
 
 
539
 
                /* Conceivably, png_set_packing() is a better idea;
540
 
                 * God only knows how libpng works
541
 
                 */
542
 
    }
543
 
        /* If we are 16-bit, convert to 8-bit */
544
 
    if (bit_depth == 16) {
545
 
                png_set_strip_16(png_ptr);
546
 
    }
547
 
 
548
 
        /* If gray scale, convert to RGB */
549
 
    if (color_type == PNG_COLOR_TYPE_GRAY ||
550
 
            color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
551
 
                png_set_gray_to_rgb(png_ptr);
552
 
    }
553
 
 
554
 
        /* If interlaced, handle that */
555
 
    if (interlace_type != PNG_INTERLACE_NONE) {
556
 
                png_set_interlace_handling(png_ptr);
557
 
    }
558
 
 
559
 
    /* Update the info the reflect our transformations */
560
 
    png_read_update_info(png_ptr, info_ptr);
561
 
    /* re-read due to transformations just made */
562
 
    /*
563
 
     * This seems to bug on at least one system (other than mine)
564
 
     * http://www.metalforge.net/cfmb/viewtopic.php?t=1085
565
 
     *
566
 
     * I think its actually a bug in libpng. This function dies with an 
567
 
     * error based on image width. However I've produced a work around
568
 
     * using the indivial functions. Repeated below.
569
 
     *
570
 
    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
571
 
                 &color_type, &interlace_type, &compression_type, &filter_type);
572
 
     */
573
 
    width = png_get_image_width(png_ptr, info_ptr);
574
 
    height = png_get_image_height(png_ptr, info_ptr);
575
 
    bit_depth = png_get_bit_depth(png_ptr, info_ptr);
576
 
    color_type = png_get_color_type(png_ptr, info_ptr);
577
 
    interlace_type = png_get_interlace_type(png_ptr, info_ptr);
578
 
    compression_type = png_get_compression_type(png_ptr, info_ptr);
579
 
    
580
 
    if (color_type & PNG_COLOR_MASK_ALPHA)
581
 
                bpp = 4;
582
 
    else
583
 
                bpp = 3;
584
 
 
585
 
    /* Allocate the memory we need once, and increase it if necessary.
586
 
     * This is more efficient the allocating this block of memory every time.
587
 
     */
588
 
    if (pixels_byte==0) {
589
 
        pixels_byte = width * height * bpp;
590
 
        pixels = (uint8*)malloc(pixels_byte);
591
 
    } else if ((width * height * bpp) > pixels_byte) {
592
 
        pixels_byte =width * height * bpp;
593
 
        /* Doing a free/malloc is probably more efficient -
594
 
         * we don't care about the old data in this
595
 
         * buffer.
596
 
         */
597
 
        free(pixels);
598
 
        pixels= (uint8*)malloc(pixels_byte);
599
 
    }
600
 
 
601
 
    if (!pixels) {
602
 
        png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
603
 
        pixels_byte=0;
604
 
        return PNGX_OUTOFMEM;
605
 
    }
606
 
    if (rows_byte == 0) {
607
 
        rows =(png_bytepp) malloc(sizeof(char*) * height);
608
 
        rows_byte=height;
609
 
    } else if (height > rows_byte) {
610
 
        rows =(png_bytepp) realloc(rows, sizeof(char*) * height);
611
 
        rows_byte=height;
612
 
    }
613
 
    if (!rows) {
614
 
        png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
615
 
        pixels_byte=0;
616
 
        return PNGX_OUTOFMEM;
617
 
    }
618
 
 
619
 
    for (y=0; y<height; y++) 
620
 
        rows[y] = pixels + y * width * bpp;
621
 
 
622
 
    png_read_image(png_ptr, rows);
623
 
#if 0
624
 
    fprintf(stderr,"image is %d X %d, bpp=%d, color_type=%d\n",
625
 
            width, height, bpp, color_type);
626
 
#endif
627
 
 
628
 
    *pix = gdk_pixmap_new(window, width, height, -1);
629
 
 
630
 
 
631
 
    gc=gdk_gc_new(*pix);
632
 
    gdk_gc_set_function(gc, GDK_COPY);
633
 
 
634
 
    if (color_type & PNG_COLOR_MASK_ALPHA) {
635
 
        *mask=gdk_pixmap_new(window, width, height,1);
636
 
        gc_alpha=gdk_gc_new(*mask);
637
 
        gdk_gc_set_function(gc_alpha, GDK_COPY);
638
 
 
639
 
        scolor.pixel=1;
640
 
        gdk_gc_set_foreground(gc_alpha, &scolor);
641
 
        gdk_draw_rectangle(*mask, gc_alpha, 1, 0, 0, width, height);
642
 
 
643
 
        scolor.pixel=0;
644
 
        gdk_gc_set_foreground(gc_alpha, &scolor);
645
 
        has_alpha=1;
646
 
    }
647
 
    else {
648
 
        *mask = None;
649
 
        gc_alpha = None;    /* Prevent compile warnings */
650
 
    }
651
 
    i=0;
652
 
    for (y=0; y<height; y++) {
653
 
        for (x=0; x<width; x++) {
654
 
            rgb[i++]=rows[y][x*bpp];    /* red */
655
 
            rgb[i++]=rows[y][x*bpp+1];  /* green */
656
 
            rgb[i++]=rows[y][x*bpp+2];  /* blue */
657
 
            if (has_alpha) {
658
 
                alpha = rows[y][x*bpp+3];
659
 
                /* Transparent bit */
660
 
                if (alpha==0) {
661
 
                    gdk_draw_point(*mask, gc_alpha, x, y);
662
 
                }
663
 
            }
664
 
        }
665
 
    }
666
 
    gdk_draw_rgb_image(*pix, gc,  0, 0, 32, 32, GDK_RGB_DITHER_NONE, rgb, 32*3);
667
 
    png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
668
 
    if (has_alpha)
669
 
        gdk_gc_destroy(gc_alpha);
670
 
    gdk_gc_destroy(gc);
671
 
    return 0;
672
 
}
673