Esempio n. 1
0
/***********************************************************************
* decode png file
* const char *file_path  =  path to png file e.g. "/dev_hdd0/test.png" 
***********************************************************************/
Buffer load_png(const char *file_path)
{
	Buffer tmp;
	png_dec_info dec_ctx;          // decryption handles
	void *buf_addr = NULL;         // buffer for decoded png data
	
	
	// create png decoder 
	create_decoder(&dec_ctx);
	
	// open png stream
	open_png(&dec_ctx, file_path);
	
	// set decode parameter
	set_dec_param(&dec_ctx);
	
	// alloc target buffer
	buf_addr = mem_alloc(png_w * png_h * 4);
	
	// decode png stream, into target buffer
	decode_png_stream(&dec_ctx, buf_addr);
	
	// close png stream 
	PngDecClose(dec_ctx.main_h, dec_ctx.sub_h);
	
	// destroy png decoder
	PngDecDestroy(dec_ctx.main_h);
	
	// store png values
	tmp.addr = (uint32_t*)buf_addr;
	tmp.w = png_w;
	tmp.h = png_h;
  
  return tmp;
}
int
res_create_alpha_surface(const char *name, gr_surface *pSurface)
{
	int result = 0;
	unsigned int y;
	unsigned char *p_row;
	gr_surface surface = NULL;
	png_structp png_ptr = NULL;
	png_infop info_ptr = NULL;
	png_uint_32 width, height;
	png_byte channels;
	FILE *fp = NULL;

	*pSurface = NULL;

	result = open_png(name, &png_ptr, &info_ptr, &fp, &width, &height,
			  &channels);
	if (result < 0)
		return result;

	if (channels != 1) {
		result = -7;
		goto exit;
	}

	if (!(surface = malloc_surface(width * height))) {
		result = -8;
		goto exit;
	}

	surface->width = width;
	surface->height = height;
	surface->row_bytes = width;
	surface->pixel_bytes = 1;

	for (y = 0; y < height; y++) {
		p_row = surface->data + y * surface->row_bytes;
		png_read_row(png_ptr, p_row, NULL);
	}

	*pSurface = surface;
exit:
	close_png(&png_ptr, &info_ptr, fp);
	if (result < 0 && surface != NULL)
		free(surface);

	return result;
}
int res_create_alpha_surface(const char* name, gr_surface* pSurface) {
    gr_surface surface = NULL;
    int result = 0;
    png_structp png_ptr = NULL;
    png_infop info_ptr = NULL;
    png_uint_32 width, height;
    png_byte channels;

    *pSurface = NULL;

    result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels);
    if (result < 0) return result;

    if (channels != 1) {
        result = -7;
        goto exit;
    }

    surface = malloc_surface(width * height);
    if (surface == NULL) {
        result = -8;
        goto exit;
    }
    surface->width = width;
    surface->height = height;
    surface->row_bytes = width;
    surface->pixel_bytes = 1;

#if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA)
    png_set_bgr(png_ptr);
#endif

    unsigned char* p_row;
    unsigned int y;
    for (y = 0; y < height; ++y) {
        p_row = surface->data + y * surface->row_bytes;
        png_read_row(png_ptr, p_row, NULL);
    }

    *pSurface = surface;

  exit:
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
    if (result < 0 && surface != NULL) free(surface);
    return result;
}
int
res_create_display_surface(const char *name, gr_surface *pSurface)
{
	int result = 0;
	unsigned int y;
	unsigned char *p_row;
	gr_surface surface = NULL;
	png_structp png_ptr = NULL;
	png_infop info_ptr = NULL;
	png_uint_32 width, height;
	png_byte channels;
	FILE *fp = NULL;

	*pSurface = NULL;

	result = open_png(name, &png_ptr, &info_ptr, &fp, &width, &height,
			  &channels);
	if (result < 0)
		return result;

	if (!(surface = init_display_surface(width, height))) {
		result = -8;
		goto exit;
	}

	/* TODO: check for error */
	p_row = malloc(width * 4);
	for (y = 0; y < height; y++) {
		png_read_row(png_ptr, p_row, NULL);
		transform_rgb_to_draw(p_row,
				      surface->data + y * surface->row_bytes,
				      channels, width);
	}

	free(p_row);

	*pSurface = surface;

exit:
	close_png(&png_ptr, &info_ptr, fp);
	if (result < 0 && surface != NULL)
		free(surface);

	return result;
}
Esempio n. 5
0
int main (int argc, char *argv[])
{
    InPng *in_png;
    char *input_file;
    char *output_file;

    if (argc != 3) {
	fail("usage: stencilizer INPUT-PNG OUTPUT-PNG");
    }
    
    input_file = argv[1];
    output_file = argv[2];

    in_png = open_png(input_file);
    stencilize(in_png, output_file);

    return 0;
}
Esempio n. 6
0
int res_create_surface_png(const char* name, gr_surface* pSurface) {
    GGLSurface* surface = NULL;
    int result = 0;
    png_structp png_ptr = NULL;
    png_infop info_ptr = NULL;
    png_uint_32 width, height;
    png_byte channels;
    FILE* fp;

    *pSurface = NULL;

    result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels, &fp);
    if (result < 0) return result;

    surface = init_display_surface(width, height);
    if (surface == NULL) {
        result = -8;
        goto exit;
    }

    unsigned char* p_row = malloc(width * 4);
    unsigned int y;
    for (y = 0; y < height; ++y) {
        png_read_row(png_ptr, p_row, NULL);
        transform_rgb_to_draw(p_row, surface->data + y * width * 4, channels, width);
    }
    free(p_row);

    if (channels == 3)
        surface->format = GGL_PIXEL_FORMAT_RGBX_8888;
    else
        surface->format = GGL_PIXEL_FORMAT_RGBA_8888;

    *pSurface = (gr_surface) surface;

  exit:
    fclose(fp);
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
    if (result < 0 && surface != NULL) free(surface);
    return result;
}
int res_create_display_surface(const char* name, gr_surface* pSurface) {
    gr_surface surface = NULL;
    int result = 0;
    png_structp png_ptr = NULL;
    png_infop info_ptr = NULL;
    png_uint_32 width, height;
    png_byte channels;

    *pSurface = NULL;

    result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels);
    if (result < 0) return result;

    surface = init_display_surface(width, height);
    if (surface == NULL) {
        result = -8;
        goto exit;
    }

#if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA)
    png_set_bgr(png_ptr);
#endif

    unsigned char* p_row = malloc(width * 4);
    unsigned int y;
    for (y = 0; y < height; ++y) {
        png_read_row(png_ptr, p_row, NULL);
        transform_rgb_to_draw(p_row, surface->data + y * surface->row_bytes, channels, width);
    }
    free(p_row);

    *pSurface = surface;

  exit:
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
    if (result < 0 && surface != NULL) free(surface);
    return result;
}
Esempio n. 8
0
/***********************************************************************
 * Method : Image::read_png
 * Params : char *file_name
 * Returns: int (success/failure)
 * Effects: opens file, reads data into memory (if it is a png file)
 ***********************************************************************/
int
Image::read_png(char *file)
{
   // reset and free up memory:
   clear();

   FILE *fp = open_png(file);
   if (!fp)
      return 0;

   png_structp  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0,0);
   if (!png_ptr) {
      fclose(fp);
      fprintf(stderr,"Image::read_png: png_create_read_struct() failed");
      return 0;
   }

   // Allocate/initialize the memory for image information
   png_infop info_ptr = png_create_info_struct(png_ptr);
   if (!info_ptr) {
      fclose(fp);
      png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
      fprintf(stderr,"Image::read_png: png_create_info_struct() failed");
      return 0;
   }

   // Set error handling
   if (setjmp(png_ptr->jmpbuf)) {
      // jump here from error encountered inside PNG code...
      // free all memory associated with the png_ptr and info_ptr
      png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
      fclose(fp);
      fprintf(stderr,"Image::read_png: error reading file %s", file);
      clear();
      return 0;
   }

   // Set up the input control (using standard C streams)
   //

   png_init_io(png_ptr, fp);

   // indicate how much of the file has been read:
   png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);

   // read information from the file before the first image data chunk
   png_read_info(png_ptr, info_ptr);

   // extract _width, _height, and other info from header:
   int bit_depth, color_type, interlace_type;
   png_get_IHDR(png_ptr, info_ptr,
                (unsigned long*)&_width,
                (unsigned long*)&_height,
                &bit_depth,
                &color_type,
                &interlace_type,
                NULL, NULL);

   // tell libpng to strip 16 bit/color files down to 8 bits/channel
   png_set_strip_16(png_ptr);

   // Extract multiple pixels with bit depths of 1, 2, and 4 from a single
   // byte into separate bytes (useful for paletted and grayscale images).
   png_set_packing(png_ptr);

   // Expand paletted colors into true RGB triplets
   if (color_type == PNG_COLOR_TYPE_PALETTE)
      png_set_expand(png_ptr);

   // Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel
   if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
      png_set_expand(png_ptr);

   // Expand paletted or RGB images with transparency to full alpha channels
   // so the data will be available as RGBA quartets.
   if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
      png_set_expand(png_ptr);

   // update the header to reflect transformations applied:
   png_read_update_info(png_ptr, info_ptr);

   // now it's safe to read the size of a row:
   unsigned long row_bytes = png_get_rowbytes(png_ptr, info_ptr);
   _bpp = row_bytes / _width;

   // make sure bytes per pixel is a valid number:
   if (_bpp < 1 || _bpp > 4) {
      fprintf(stderr,"Image::read_png: %d bytes/pixel not supported", _bpp);
   } else if (interlace_type != PNG_INTERLACE_NONE) {
      fprintf(stderr,"Image::read_png: unsupported interlace type (%d)",
              interlace_type);
   } else if ((_data = new uchar [ size() ]) == 0) {
      fprintf(stderr,"Image::read_png: can't allocate data");
   } else {
      _no_delete = 0;

      // no more excuses: read the image (inverted vertically):
      for (int y=_height-1; y>=0; y--)
         png_read_row(png_ptr, _data + y*row_bytes, 0);

      // read rest of file, and get additional
      // chunks in info_ptr - REQUIRED
      png_read_end(png_ptr, info_ptr);
   }

   // clean up after the read, and free any memory allocated - REQUIRED
   png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);

   // close the file
   fclose(fp);

   // return pixel data:
   if (_data)
      return 1;
   else {
      clear();
      return 0;
   }
}
Esempio n. 9
0
/*
 * Parameters: <hundred_dpi> <basename_> <titlestring> <bottom_html_code>
 * <pageoffset> [first page number]
 */
int
main(int argc, char **argv)
{
        int a,z;
 
        if (argc<7){
                fprintf(stderr,"Usage: pbm2png <hundred_dpi> <basename_> <titlestring> <bottom_html_code> <pageoffset> <ifname> [starting_filenumber]\n");
        return 0;
        }
        dpi=atof(argv[1])/10;
        ppm=dpi*1000/25.4;
        basename_=argv[2];
        titlestring=argv[3];
	bottom=argv[4];
        pageoffset=atol(argv[5]);
        filename=argv[6];
	again0:
        ifd=open(filename,O_RDONLY);
	if (ifd<0){
		if (errno==EAGAIN||errno==EINTR||errno==EWOULDBLOCK) goto
			again0;
		else {
			perror("");
			exit(1);
		}
	}
        fprintf(stderr,"filename %s, %d\n",filename,ifd);
        if (argc>=8){
                filenumber=atol(argv[7]);
        }
        gentables();
        again:
        fprintf(stderr,"\nFile %i\n",filenumber);
        if (read_header()){
                for (a=0;a<filenumber;a++)
                        make_page(a);
		make_index();
                return 0;
        }
        lw=(x+15)>>4;
        lb=(x+7)>>3;
        ox=x/17;
        oy=y/15;
        fprintf(stderr,"Input: %i*%i pixels, %f*%f dpi, %.1fMB.\n",x,y,dpi*17,dpi*15,(float)lb*y/1048576);
        fprintf(stderr,"Ouput: %i*%i pixels, %f*%f dpi, %.1fKB raw data.\n",ox,oy,dpi,dpi,(float)ox*oy/1024);
        l1=(unsigned char*)malloc(lw*2);
        l2=(unsigned long*)malloc(lw*sizeof(unsigned long));
        l4=(unsigned long long*)malloc(lw*sizeof(unsigned long long));
        sprintf(string,"%s%d.png",basename_,filenumber);
        filenumber++;
        of=fopen(string,"w");
        open_png();
        for (z=oy;z;z--){
                if (!(z&15)){
                        fprintf(stderr,".");
                        fflush(stderr);
                } 
                load_to_4();
                export_from_4();
        }
        close_png();
        fprintf(stderr,"\nWritten %lu bytes of data, ratio %.1f%%\n",ftell(of),(float)ftell(of)*100/ox/oy);
        fclose(of);
        for (a=y%15;a;a--)
                load();
        free(l1);
        free(l2);
        free(l4);
        goto again;
}
Esempio n. 10
0
image_t *load_png(char *png) {
	int width = 0;
	int height = 0;
	FILE *f = NULL;
	png_structp png_ptr = NULL;
	png_infop info_ptr = NULL;
	png_infop end_info = NULL;
	png_uint_32 rowbytes = 0;
	image_t *image = NULL;

	f = open_png(png);
	if (f == NULL)
		goto err;

	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
			(png_voidp) NULL, NULL, NULL);
	if (!png_ptr)
		goto err;

	info_ptr = png_create_info_struct(png_ptr);
	if (!info_ptr)
		goto err;

	end_info = png_create_info_struct(png_ptr);
	if (!end_info)
		goto err;

	if (setjmp(png_jmpbuf(png_ptr))) {
		printf("[read_png_file] Error during read_image");
		goto err;
	}

	png_init_io(png_ptr, f);
	png_set_sig_bytes(png_ptr, HEADER_SIZE);
	png_read_info(png_ptr, info_ptr);
	rowbytes = png_get_rowbytes(png_ptr, info_ptr);
	width = png_get_image_width(png_ptr, info_ptr);
	height = png_get_image_height(png_ptr, info_ptr);

	if (png_get_color_type(png_ptr, info_ptr) != PNG_COLOR_TYPE_RGBA) {
		printf("Error: PNG format is not RGBA\n");
		goto err;
	}

	if (setjmp(png_jmpbuf(png_ptr))) {
		printf("[read_png_file] Error during read_image");
		goto err;
	}

	image = make_image(width, height, rowbytes);
	if (image == NULL)
		goto err;
	png_read_image(png_ptr, image->rows);
	png_read_end(png_ptr, end_info);

	done: if (f != NULL)
		fclose(f);
	if (png_ptr != NULL)
		png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
	return image;
	err: free_image(image);
	image = NULL;
	goto done;
}
int res_create_multi_display_surface(const char* name, int* frames, gr_surface** pSurface) {
    gr_surface* surface = NULL;
    int result = 0;
    png_structp png_ptr = NULL;
    png_infop info_ptr = NULL;
    png_uint_32 width, height;
    png_byte channels;
    int i;

    *pSurface = NULL;
    *frames = -1;

    result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels);
    if (result < 0) return result;

    *frames = 1;
    png_textp text;
    int num_text;
    if (png_get_text(png_ptr, info_ptr, &text, &num_text)) {
        for (i = 0; i < num_text; ++i) {
            if (text[i].key && strcmp(text[i].key, "Frames") == 0 && text[i].text) {
                *frames = atoi(text[i].text);
                break;
            }
        }
        printf("  found frames = %d\n", *frames);
    }

    if (height % *frames != 0) {
        printf("bad height (%d) for frame count (%d)\n", height, *frames);
        result = -9;
        goto exit;
    }

    surface = malloc(*frames * sizeof(gr_surface));
    if (surface == NULL) {
        result = -8;
        goto exit;
    }
    for (i = 0; i < *frames; ++i) {
        surface[i] = NULL;//init_display_surface(width, height / *frames);
        if (surface[i] == NULL) {
            result = -8;
            goto exit;
        }
    }

    /*unsigned char* p_row = malloc(width * 4);
    unsigned int y;
    for (y = 0; y < height; ++y) {
        png_read_row(png_ptr, p_row, NULL);
        int frame = y % *frames;
        unsigned char* out_row = surface[frame]->data +
            (y / *frames) * surface[frame]->row_bytes;
        transform_rgb_to_draw(p_row, out_row, channels, width);
    }
    free(p_row); this will need to be brought in line with the older resources and graphics code */

    *pSurface = (gr_surface*) surface;

exit:
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);

    if (result < 0) {
        if (surface) {
            for (i = 0; i < *frames; ++i) {
                if (surface[i]) free(surface[i]);
            }
            free(surface);
        }
    }
    return result;
}
Esempio n. 12
0
int main(int argc, char **argv)
{

  // Handle command line arguments
  prog_options p;
  parse_options(&p,argc,argv);
  validate_options(&p);

  // Return value
  int r;

  // Init library
  r = png_init(0, 0);

  // Read current image
  png_file pf_current;
  png_file pf_previous;

  // Find motion
  if ( p.file_out != NULL ) {

    // Run until signal trap is reached
    signal(SIGINT, &trap);
    execute = 1;
    while(execute){

      if(p.verbose || p.debug) fprintf(stdout,"\nNew round\n");
      if(p.verbose || p.debug) gettimeofday(&tv1_total, NULL);

      // Read current image
      if(p.debug) gettimeofday(&tv1, NULL);
      r = open_png(&pf_current, p.file_current);
      png_write_error(r);
      if( r >= PNG_NO_ERROR ) {

        // Read "previous" image
        if( pf_previous.is_open != 1 ) {
          r = open_png(&pf_previous, p.file_current);
          png_write_error(r);
        }

        // Image instance from png
        motion_image image_current;
        image_from_png_data (&image_current, pf_current.data, pf_current.png_obj.width, pf_current.png_obj.height);
        motion_image image_previous;
        image_from_png_data (&image_previous, pf_previous.data, pf_current.png_obj.width, pf_current.png_obj.height);
        if(p.debug) gettimeofday(&tv2, NULL);
        if(p.debug) printf ("Open file:\t\t%f seconds\n", get_timediff(&tv1,&tv2));

        // Noise reduction
        if(p.debug) gettimeofday(&tv1, NULL);
        filter_noise_reduction (&(image_current.average),1);
        filter_noise_reduction (&(image_previous.average),1);
        if(p.debug) gettimeofday(&tv2, NULL);
        if(p.debug) printf ("Noise reduction:\t%f seconds\n", get_timediff(&tv1,&tv2));

        // Intensity correction
        if(p.debug) gettimeofday(&tv1, NULL);
        int intensity_current = get_average_intensity(&(image_current.average));
        int intensity_previous = get_average_intensity(&(image_previous.average));
        int intensity_difference_before = (intensity_current - intensity_previous) / 2;
        filter_adjust_intensity (&(image_current.average),-intensity_difference_before);
        filter_adjust_intensity (&(image_previous.average),intensity_difference_before);
        if(p.debug) gettimeofday(&tv2, NULL);
        if(p.debug) printf ("Intensity correction:\t%f seconds\n", get_timediff(&tv1,&tv2));

        // Background subtraction
        if(p.debug) gettimeofday(&tv1, NULL);
        filter_background_subtraction(&(image_current.average),&(image_previous.average));
        if(p.debug) gettimeofday(&tv2, NULL);
        if(p.debug) printf ("Background subtraction:\t%f seconds\n", get_timediff(&tv1,&tv2));

        // Binary split
        if(p.debug) gettimeofday(&tv1, NULL);
        filter_split_binary(&(image_current.average),p.sensitivity);
        if(p.debug) gettimeofday(&tv2, NULL);
        if(p.debug) printf ("Binary split:\t\t%f seconds\n", get_timediff(&tv1,&tv2));

        // Blob reduction
        if(p.debug) gettimeofday(&tv1, NULL);
        int pixels_left = filter_reduce_blobs(&(image_current.average),p.passes);
        if(p.debug) gettimeofday(&tv2, NULL);
        if(p.debug) printf ("Blob reduction:\t\t%f seconds\n", get_timediff(&tv1,&tv2));
        if(p.verbose || p.debug) printf ("Pixels left:\t\t%i/10\n", pixels_left);

        if( pixels_left >= 10 ) {
          // Save file
          if(p.debug) gettimeofday(&tv1, NULL);
          // ToDo: Delegate file saving to thread
          char * filename = format_time(p.file_out);
          png_save_file(&pf_current,format_time(p.file_out));
          free(filename);
          if(p.debug) gettimeofday(&tv2, NULL);
          if(p.debug) printf ("File save:\t\t%f seconds\n", get_timediff(&tv1,&tv2));
        }

        // png_close_file(&pf_current.png_obj); // pf_current is closed as pf_previous on signal
        png_close_file(&pf_previous.png_obj);
        free(pf_previous.data);

        pf_previous = pf_current;

        free_image(image_current);
        free_image(image_previous);

        if(p.verbose || p.debug) gettimeofday(&tv2_total, NULL);
        if(p.verbose || p.debug) printf ("Total round time:\t%f seconds\n", get_timediff(&tv1_total,&tv2_total));

      } else {
	pf_previous.is_open = 0;
        png_close_file(&pf_previous.png_obj);
        free(pf_previous.data);
	pf_previous.data = NULL;
      }

    }

    if(p.verbose || p.debug) printf ("\nExecution interrupted, cleaning up...\n");

    r = png_close_file(&pf_previous.png_obj);
    free(pf_previous.data);

    signal(SIGINT, SIG_DFL);
  }

  // Find difference
  if ( p.file_out_difference != NULL ) {
    // Fixme: Move calculation to motion.c
    int change_treshold = 10;
    int x, y;
    for( x = 0 ; x < pf_current.png_obj.width ; x++ ) {
      for( y = 0 ; y < pf_current.png_obj.height ; y++ ) {

      int pixel_idx = (pf_current.png_obj.width*y*4+x*4);

      // Check for changes on pixel level
      int avg_new = (pf_current.data[pixel_idx]+pf_current.data[pixel_idx+1]+pf_current.data[pixel_idx+2])/3;
      int avg_old = (pf_previous.data[pixel_idx]+pf_previous.data[pixel_idx+1]+pf_previous.data[pixel_idx+2])/3;
      int difference = (avg_new - avg_old);
      if(!(
        abs(pf_current.data[pixel_idx]-pf_previous.data[pixel_idx]) > change_treshold ||
        abs(pf_current.data[pixel_idx+1]-pf_previous.data[pixel_idx+1]) > change_treshold ||
        abs(pf_current.data[pixel_idx+2]-pf_previous.data[pixel_idx+2]) > change_treshold ||
        abs(difference) > change_treshold
        ))
        {
          pf_current.data[pixel_idx] = 0;
          pf_current.data[pixel_idx+1] = 0;
          pf_current.data[pixel_idx+2] = 0;
          pf_current.data[pixel_idx+3] = 0;
        }
      }
    }

    // Save difference
    png_save_file(&pf_current,p.file_out_difference);

    // Output file old
    r = png_close_file(&pf_current.png_obj);
    r = png_close_file(&pf_previous.png_obj);
    free(pf_current.data);
    free(pf_previous.data);

  }
  
  exit(EXIT_SUCCESS);

}
int res_create_localized_alpha_surface(const char* name,
                                       const char* locale,
                                       gr_surface* pSurface) {
    gr_surface surface = NULL;
    int result = 0;
    png_structp png_ptr = NULL;
    png_infop info_ptr = NULL;
    png_uint_32 width, height;
    png_byte channels;

    *pSurface = NULL;

    if (locale == NULL) {
        surface = malloc_surface(0);
        surface->width = 0;
        surface->height = 0;
        surface->row_bytes = 0;
        surface->pixel_bytes = 1;
        goto exit;
    }

    result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels);
    if (result < 0) return result;

    if (channels != 1) {
        result = -7;
        goto exit;
    }

    unsigned char* row = malloc(width);
    png_uint_32 y;
    for (y = 0; y < height; ++y) {
        png_read_row(png_ptr, row, NULL);
        int w = (row[1] << 8) | row[0];
        int h = (row[3] << 8) | row[2];
        int len = row[4];
        char* loc = (char*)row+5;

        if (y+1+h >= height || matches_locale(loc, locale)) {
            printf("  %20s: %s (%d x %d @ %d)\n", name, loc, w, h, y);

            surface = malloc_surface(w*h);
            if (surface == NULL) {
                result = -8;
                goto exit;
            }
            surface->width = w;
            surface->height = h;
            surface->row_bytes = w;
            surface->pixel_bytes = 1;

            int i;
            for (i = 0; i < h; ++i, ++y) {
                png_read_row(png_ptr, row, NULL);
                memcpy(surface->data + i*w, row, w);
            }

            *pSurface = (gr_surface) surface;
            break;
        } else {
            int i;
            for (i = 0; i < h; ++i, ++y) {
                png_read_row(png_ptr, row, NULL);
            }
        }
    }

exit:
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
    if (result < 0 && surface != NULL) free(surface);
    return result;
}
int
res_create_localized_alpha_surface(const char *name, const char *locale,
				   gr_surface *pSurface)
{
	int result = 0;
	unsigned char *row;
	gr_surface surface = NULL;
	png_structp png_ptr = NULL;
	png_infop info_ptr = NULL;
	png_uint_32 width, height, y;
	png_byte channels;
	FILE *fp = NULL;

	*pSurface = NULL;

	if (!locale) {
		surface = malloc_surface(0);
		surface->width = 0;
		surface->height = 0;
		surface->row_bytes = 0;
		surface->pixel_bytes = 1;
		goto exit;
	}

	result = open_png(name, &png_ptr, &info_ptr, &fp, &width, &height,
			  &channels);
	if (result < 0)
		return result;

	if (channels != 1) {
		result = -7;
		goto exit;
	}

	/* TODO: check for error */
	row = malloc(width);
	for (y = 0; y < height; y++) {
		int h, w;
		char *loc;

		png_read_row(png_ptr, row, NULL);
		w = (row[1] << 8) | row[0];
		h = (row[3] << 8) | row[2];
		loc = (char *)row + 5;

		if (y + 1 + h >= height || matches_locale(loc, locale)) {
			int i;

			printf("  %20s: %s (%d x %d @ %ld)\n", name, loc, w,
			       h, (long)y);

			if (!(surface = malloc_surface(w * h))) {
				result = -8;
				goto exit;
			}

			surface->width = w;
			surface->height = h;
			surface->row_bytes = w;
			surface->pixel_bytes = 1;

			for (i = 0; i < h; i++, y++) {
				png_read_row(png_ptr, row, NULL);
				memcpy(surface->data + i * w, row, w);
			}

			*pSurface = (gr_surface)surface;
			break;
		} else {
			int i;

			for (i = 0; i < h; i++, y++)
				png_read_row(png_ptr, row, NULL);
		}
	}

exit:
	close_png(&png_ptr, &info_ptr, fp);
	if (result < 0 && surface)
		free(surface);

	return result;
}
int
res_create_multi_display_surface(const char *name, int *frames,
				 gr_surface **pSurface)
{
	int i, result = 0, num_text;
	unsigned int y;
	unsigned char *p_row;
	gr_surface *surface = NULL;
	png_structp png_ptr = NULL;
	png_infop info_ptr = NULL;
	png_uint_32 width, height;
	png_byte channels = 0;
	png_textp text;
	FILE *fp = NULL;

	*pSurface = NULL;
	*frames = -1;

	result = open_png(name, &png_ptr, &info_ptr, &fp, &width, &height,
			  &channels);
	if (result < 0)
		return result;

	*frames = 1;
	if (png_get_text(png_ptr, info_ptr, &text, &num_text)) {
		for (i = 0; i < num_text; i++)
			if (text[i].key && !strcmp(text[i].key, "Frames") &&
			    text[i].text) {
				*frames = atoi(text[i].text);
				break;
			}

		printf("  found frames = %d\n", *frames);
	}

	if (height % *frames != 0) {
		printf("bad height (%ld) for frame count (%d)\n",
		       (long)height, *frames);
		result = -9;
		goto exit;
	}

	if (!(surface = malloc(*frames * sizeof(gr_surface)))) {
		result = -8;
		goto exit;
	}

	for (i = 0; i < *frames; i++) {
		surface[i] = init_display_surface(width, height / *frames);
		if (!surface[i]) {
			result = -8;
			goto exit;
		}
	}

	/* TODO: Check for error */
	p_row = malloc(width * 4);
	for (y = 0; y < height; y++) {
		int frame = y % *frames;
		unsigned char *out_row;

		png_read_row(png_ptr, p_row, NULL);
		out_row = surface[frame]->data + (y / *frames) *
			  surface[frame]->row_bytes;
		transform_rgb_to_draw(p_row, out_row, channels, width);
	}

	free(p_row);

	*pSurface = (gr_surface *)surface;

exit:
	close_png(&png_ptr, &info_ptr, fp);

	if (result < 0)
		if (surface) {
			for (i = 0; i < *frames; i++)
				if (surface[i])
					free(surface[i]);

			free(surface);
		}

	return result;
}