Ejemplo n.º 1
0
void
input_png_file(struct Options opts, struct PNGImage *img)
{
	FILE *f;
	int i, y, num_trans;
	bool has_palette = false;
	png_byte *trans_alpha;
	png_color_16 *trans_values;
	bool *full_alpha;
	png_color *palette;

	f = fopen(opts.infile, "rb");
	if (!f) {
		err(1, "Opening input png file '%s' failed", opts.infile);
	}

	img->png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if (!img->png) {
		errx(1, "Creating png structure failed");
	}

	img->info = png_create_info_struct(img->png);
	if (!img->info) {
		errx(1, "Creating png info structure failed");
	}

	/* Better error handling here? */
	if (setjmp(png_jmpbuf(img->png))) {
		exit(1);
	}

	png_init_io(img->png, f);

	png_read_info(img->png, img->info);

	img->width  = png_get_image_width(img->png, img->info);
	img->height = png_get_image_height(img->png, img->info);
	img->depth  = png_get_bit_depth(img->png, img->info);
	img->type   = png_get_color_type(img->png, img->info);

	if (img->type & PNG_COLOR_MASK_ALPHA) {
		png_set_strip_alpha(img->png);
	}

	if (img->depth != depth) {
		if (opts.verbose) {
			warnx("Image bit depth is not %i (is %i).", depth,
			    img->depth);
		}
	}

	if (img->type == PNG_COLOR_TYPE_GRAY) {
		if (img->depth < 8) {
			png_set_expand_gray_1_2_4_to_8(img->png);
		}
		png_set_gray_to_rgb(img->png);
	} else {
		if (img->depth < 8) {
			png_set_expand_gray_1_2_4_to_8(img->png);
		}
		has_palette = png_get_PLTE(img->png, img->info, &palette,
		    &colors);
	}

	if (png_get_tRNS(img->png, img->info, &trans_alpha, &num_trans,
	    &trans_values)) {
		if (img->type == PNG_COLOR_TYPE_PALETTE) {
			full_alpha = malloc(sizeof(bool) * num_trans);

			for (i = 0; i < num_trans; i++) {
				if (trans_alpha[i] > 0) {
					full_alpha[i] = false;
				} else {
					full_alpha[i] = true;
				}
			}

			for (i = 0; i < num_trans; i++) {
				if (full_alpha[i]) {
					palette[i].red   = 0xFF;
					palette[i].green = 0x00;
					palette[i].blue  = 0xFF;
					/*
					 * Set to the lightest color in the
					 * palette.
					 */
				}
			}

			free(full_alpha);
		} else {
			/* Set to the lightest color in the image. */
		}

		png_free_data(img->png, img->info, PNG_FREE_TRNS, -1);
	}

	if (has_palette) {
		/* Make sure palette only has the amount of colors you want. */
	} else {
		/*
		 * Eventually when this copies colors from the image itself,
		 * make sure order is lightest to darkest.
		 */
		palette = malloc(sizeof(png_color) * colors);

		if (strcmp(opts.infile, "rgb.png") == 0) {
			palette[0].red   = 0xFF;
			palette[0].green = 0xEF;
			palette[0].blue  = 0xFF;

			palette[1].red   = 0xF7;
			palette[1].green = 0xF7;
			palette[1].blue  = 0x8C;

			palette[2].red   = 0x94;
			palette[2].green = 0x94;
			palette[2].blue  = 0xC6;

			palette[3].red   = 0x39;
			palette[3].green = 0x39;
			palette[3].blue  = 0x84;
		} else {
			palette[0].red   = 0xFF;
			palette[0].green = 0xFF;
			palette[0].blue  = 0xFF;

			palette[1].red   = 0xA9;
			palette[1].green = 0xA9;
			palette[1].blue  = 0xA9;

			palette[2].red   = 0x55;
			palette[2].green = 0x55;
			palette[2].blue  = 0x55;

			palette[3].red   = 0x00;
			palette[3].green = 0x00;
			palette[3].blue  = 0x00;
		}
	}

	/*
	 * Also unfortunately, this sets it at 8 bit, and I can't find any
	 * option to reduce to 2 or 1 bit.
	 */
#if PNG_LIBPNG_VER < 10402
	png_set_dither(img->png, palette, colors, colors, NULL, 1);
#else
	png_set_quantize(img->png, palette, colors, colors, NULL, 1);
#endif

	if (!has_palette) {
		png_set_PLTE(img->png, img->info, palette, colors);
		free(palette);
	}

	/*
	 * If other useless chunks exist (sRGB, bKGD, pHYs, gAMA, cHRM, iCCP,
	 * etc.) offer to remove?
	 */

	png_read_update_info(img->png, img->info);

	img->data = malloc(sizeof(png_byte *) * img->height);
	for (y = 0; y < img->height; y++) {
		img->data[y] = malloc(png_get_rowbytes(img->png, img->info));
	}

	png_read_image(img->png, img->data);
	png_read_end(img->png, img->info);

	fclose(f);
}
Ejemplo n.º 2
0
unsigned char *
ReadPNG(FILE *infile,int *width, int *height, XColor *colrs)
{

    unsigned char *pixmap;
    unsigned char *p;
    png_byte *q;

    png_struct *png_ptr;
    png_info *info_ptr;

    double screen_gamma;

    png_byte *png_pixels=NULL, **row_pointers=NULL;
    int i, j;

    unsigned int packets;

    png_color std_color_cube[216];

    
        /* first check to see if its a valid PNG file. If not, return. */
        /* we assume that infile is a valid filepointer */
    {
        int ret;
        png_byte buf[8];
        
        ret = fread(buf, 1, 8, infile);
        
        if(ret != 8)
            return 0;
        
        ret = png_check_sig(buf, 8);
        
        if(!ret)
            return(0);
    }

        /* OK, it is a valid PNG file, so let's rewind it, and start 
           decoding it */
    rewind(infile);

        /* allocate the structures */
    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if(!png_ptr)
        return 0;

    info_ptr = png_create_info_struct(png_ptr);
    if(!info_ptr) {
        png_destroy_read_struct(&png_ptr, NULL, NULL);
        return 0;
    }

        /* Establish the setjmp return context for png_error to use. */
    if (setjmp(png_jmpbuf(png_ptr))) {
        
#ifndef DISABLE_TRACE
        if (srcTrace) {
            fprintf(stderr, "\n!!!libpng read error!!!\n");
        }
#endif

	png_destroy_read_struct(&png_ptr, &info_ptr, NULL);

        if(png_pixels != NULL)
            free((char *)png_pixels);
        if(row_pointers != NULL)
            free((png_byte **)row_pointers);
	png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        
        return 0;
    }
    
        /* set up the input control */
    png_init_io(png_ptr, infile);
    
        /* read the file information */
    png_read_info(png_ptr, info_ptr);
    
        /* setup other stuff using the fields of png_info. */
    
    *width = (int)png_get_image_width(png_ptr, info_ptr);
    *height = (int)png_get_image_height(png_ptr, info_ptr);

#ifndef DISABLE_TRACE
    if (srcTrace) {

        fprintf(stderr,"\n\nBEFORE\nheight = %d\n", (int)png_get_image_width(png_ptr, info_ptr));
        fprintf(stderr,"width = %d\n", (int)png_get_image_height(png_ptr, info_ptr));
        fprintf(stderr,"bit depth = %d\n", png_get_bit_depth(png_ptr, info_ptr));
        fprintf(stderr,"color type = %d\n", png_get_color_type(png_ptr, info_ptr));
        fprintf(stderr,"compression type = %d\n", png_get_compression_type(png_ptr, info_ptr));
        fprintf(stderr,"filter type = %d\n", png_get_filter_type(png_ptr, info_ptr));
        fprintf(stderr,"interlace type = %d\n", png_get_interlace_type(png_ptr, info_ptr));
        fprintf(stderr,"num colors = %d\n", png_get_palette_max(png_ptr, info_ptr));
        fprintf(stderr,"rowbytes = %d\n", png_get_rowbytes(png_ptr, info_ptr));
    }
#endif


#if 0
        /* This handles alpha and transparency by replacing it with 
           a background value. */
        /* its #if'ed out for now cause I don't have anything to 
           test it with */
    {
        png_color_16 my_background;
	
        if (png_get_valid(png_ptr, info_ptr) & PNG_INFO_bKGD)
            png_set_background(png_ptr, &(info_ptr->background),
                               PNG_GAMMA_FILE, 1, 1.0);
        else
            png_set_background(png_ptr, &my_background,
                               PNG_GAMMA_SCREEN, 0, 1.0);
    }
#endif

        /* strip pixels in 16-bit images down to 8 bits */
    if (png_get_bit_depth(png_ptr, info_ptr) == 16)
        png_set_strip_16(png_ptr);


        /* If it is a color image then check if it has a palette. If not
           then dither the image to 256 colors, and make up a palette */
    if (png_get_color_type(png_ptr, info_ptr)==PNG_COLOR_TYPE_RGB ||
        png_get_color_type(png_ptr, info_ptr)==PNG_COLOR_TYPE_RGB_ALPHA) {

        if(! (png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)) ) {

#ifndef DISABLE_TRACE
            if (srcTrace) {
                fprintf(stderr,"dithering (RGB->palette)...\n");
            }
#endif
                /* if there is is no valid palette, then we need to make
                   one up */
            for(i=0;i<216;i++) {
                    /* 255.0/5 = 51 */
                std_color_cube[i].red=(i%6)*51;
                std_color_cube[i].green=((i/6)%6)*51;
                std_color_cube[i].blue=(i/36)*51;
            }

                /* this should probably be dithering to 
                   Rdata.colors_per_inlined_image colors */
            png_set_quantize(png_ptr, std_color_cube,
                             216,
                             216, NULL, 1);
            
        } else {
#ifndef DISABLE_TRACE
            if (srcTrace) {
                fprintf(stderr,"dithering (RGB->file supplied palette)...\n");
            }
#endif
 
            png_colorp palette;
            int num_palette;
            png_get_PLTE(png_ptr, info_ptr, palette, &num_palette);

            png_uint_16p hist;
            png_get_hIST(png_ptr, info_ptr, &hist);

            png_set_quantize(png_ptr, palette,
                             num_palette,
                             get_pref_int(eCOLORS_PER_INLINED_IMAGE),
                             hist, 1);
            
        }
    }

        /* PNG files pack pixels of bit depths 1, 2, and 4 into bytes as
           small as they can. This expands pixels to 1 pixel per byte, and
           if a transparency value is supplied, an alpha channel is
           built.*/
    if (png_get_bit_depth(png_ptr, info_ptr) < 8)
        png_set_packing(png_ptr);


        /* have libpng handle the gamma conversion */

    if (get_pref_boolean(eUSE_SCREEN_GAMMA)) { /*SWP*/
        if (png_get_bit_depth(png_ptr, info_ptr) != 16) {  /* temporary .. glennrp */
            screen_gamma=(double)(get_pref_float(eSCREEN_GAMMA));
            
#ifndef DISABLE_TRACE
            if (srcTrace) {
                fprintf(stderr,"screen gamma=%f\n",screen_gamma);
            }
#endif
            if (png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA)) {
                double gamma;
                png_get_gAMA(png_ptr, info_ptr, &gamma);
#ifndef DISABLE_TRACE
                if (srcTrace) {
                    printf("setting gamma=%f\n",gamma);
                }
#endif
                png_set_gamma(png_ptr, screen_gamma, gamma);
            }
            else {
#ifndef DISABLE_TRACE
                if (srcTrace) {
                    fprintf(stderr,"setting gamma=%f\n",0.45);
                }
#endif
                png_set_gamma(png_ptr, screen_gamma, (double)0.45);
            }
        }
    }
    
    if (png_get_interlace_type(png_ptr, info_ptr))
        png_set_interlace_handling(png_ptr);

    png_read_update_info(png_ptr, info_ptr);
    
#ifndef DISABLE_TRACE
    if (srcTrace) {
        fprintf(stderr,"\n\nAFTER\nheight = %d\n", (int)png_get_image_width(png_ptr, info_ptr));
        fprintf(stderr,"width = %d\n", (int)png_get_image_height(png_ptr, info_ptr));
        fprintf(stderr,"bit depth = %d\n", png_get_bit_depth(png_ptr, info_ptr));
        fprintf(stderr,"color type = %d\n", png_get_color_type(png_ptr, info_ptr));
        fprintf(stderr,"compression type = %d\n", png_get_compression_type(png_ptr, info_ptr));
        fprintf(stderr,"filter type = %d\n", png_get_filter_type(png_ptr, info_ptr));
        fprintf(stderr,"interlace type = %d\n", png_get_interlace_type(png_ptr, info_ptr));
        fprintf(stderr,"num colors = %d\n", png_get_palette_max(png_ptr, info_ptr));
        fprintf(stderr,"rowbytes = %d\n", png_get_rowbytes(png_ptr, info_ptr));
    }
#endif

        /* allocate the pixel grid which we will need to send to 
           png_read_image(). */
    png_pixels = (png_byte *)malloc(png_get_rowbytes(png_ptr, info_ptr) * 
                                    (*height) * sizeof(png_byte));
    

    row_pointers = (png_byte **) malloc((*height) * sizeof(png_byte *));
    for (i=0; i < *height; i++)
        row_pointers[i]=png_pixels+(png_get_rowbytes(png_ptr, info_ptr)*i);

    
        /* FINALLY - read the darn thing. */
    png_read_image(png_ptr, row_pointers);
    
    
        /* now that we have the (transformed to 8-bit RGB) image, we have
           to copy the resulting palette to our colormap. */
    if (png_get_color_type(png_ptr, info_ptr) & PNG_COLOR_MASK_COLOR) {
        if (png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)) {
            png_colorp palette;
            int num_palette = png_get_palette_max(png_ptr, info_ptr);

            for (i=0; i < num_palette; i++) {
                png_get_PLTE(png_ptr, info_ptr, &palette, i);

                colrs[i].red = palette->red << 8;
                colrs[i].green = palette->green << 8;
                colrs[i].blue = palette->blue << 8;
                colrs[i].pixel = i;
                colrs[i].flags = DoRed|DoGreen|DoBlue;
            }
        }
        else {
            for (i=0; i < 216; i++) {
                colrs[i].red = std_color_cube[i].red << 8;
                colrs[i].green = std_color_cube[i].green << 8;
                colrs[i].blue = std_color_cube[i].blue << 8;
                colrs[i].pixel = i;
                colrs[i].flags = DoRed|DoGreen|DoBlue;
            }	    
        }
    } else {
            /* grayscale image */
        
        for(i=0; i < 256; i++ ) {
            colrs[i].red = i << 8;
            colrs[i].green = i << 8; 	    
            colrs[i].blue = i << 8;
            colrs[i].pixel = i;
            colrs[i].flags = DoRed|DoGreen|DoBlue;    
        }
    }
    
        /* Now copy the pixel data from png_pixels to pixmap */
 
    pixmap = (png_byte *)malloc((*width) * (*height) * sizeof(png_byte));
    
    p = pixmap; q = png_pixels;

        /* if there is an alpha channel, we have to get rid of it in the
           pixmap, since I don't do anything with it yet */
    if (png_get_color_type(png_ptr, info_ptr) & PNG_COLOR_MASK_ALPHA) {

#ifndef DISABLE_TRACE
        if (srcTrace) {
            fprintf(stderr,"Getting rid of alpha channel\n");
        }
#endif
        for(i=0; i<*height; i++) {
            q = row_pointers[i];
            for(j=0; j<*width; j++) {
                *p++ = *q++; /*palette index*/
                q++; /* skip the alpha pixel */
            }
        }
        
        free((char *)png_pixels);
    }
    else {
        
#ifndef DISABLE_TRACE
        if (srcTrace) {
            fprintf(stderr,"No alpha channel\n");
        }
#endif
        
        for(i=0; i<*height; i++) {
            q = row_pointers[i];
            for(j=0; j<*width; j++) {
                *p++ = *q++; /*palette index*/
            }
        }
        
        free((char *)png_pixels);
        
    }

    free((png_byte **)row_pointers);
    
        /* clean up after the read, and free any memory allocated */

        /* free the structure */
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);

    return pixmap;
}