Image-stitching and virtual tour solutions My account Updates
It is currently Sat Nov 01, 2014 8:42 am

All times are UTC + 1 hour




Post new topic Reply to topic  [ 1 post ] 
Author Message
 Post subject: write large PNG files
PostPosted: Thu May 10, 2012 5:34 pm 
Offline
Member
User avatar

Joined: Sat Jul 28, 2007 4:59 pm
Posts: 173
Location: New Hampshire, USA
AutoPano users who wish to work with large images don't have many choices of image format. There is a request to support BigTIFF, but that format is not widely supported by other software. Similarly, psb file support is not widespread, except within Adobe products.

PNG file format is widely supported, and the format is flexible enough to support large images, but AutoPano does not support PNG files larger than 2GiB. I ask that this limitation be lifted so that AutoPano can write large PNG files.

In support of that request, I include a program which writes a PNG file from an internal buffer, using the standard PNG library routines. It illustrates where you need 64-bit integers to handle large images. Run it with -s 30000 -r 5 to get a PNG file just over 2GiB. The resulting file passes pngcheck and is read by The Gimp without error. The -s value is the length of one side in pixels, and the -r parameter controls the randomness of the pixels; too simple a pattern can be compressed below 2GiB. You will need libpng12-dev installed to compile it on Ubuntu; I don't know what the requirements are on other platforms. Compile with gcc -lpng. When invoking it, -h prints a usage message.

I dedicate this program to the public domain. Anyone can use it, at any time, for any purpose, without needing any further permission from me.

Code:
/*
* Program to write a checkerboard image as a PNG file..
*/
#include <stdlib.h>
#include <getopt.h>             /* getopt_long() */
#include <errno.h>
#include <malloc.h>

#include <png.h>

static char *output_file = NULL;
static int png_compression_level_value = 6;
static int debug_level = 0;
static int checkerboard_size = 1024;
static int random_bits = 0;
static int random_mask = 0;

/* routine to exit with an error message */
static void
errno_exit (const char *s)
{
  fprintf (stderr, "%s error %d, %s\n", s, errno, strerror (errno));
  exit (EXIT_FAILURE);
}

/* routine to create a random value limited to low-order bits */
static int
random_val ()
{
  int return_val;
  return_val = rand () & random_mask;
  return return_val;
}

/* routine to create a checkerboard image and write it as a png file */
static void
write_file (char *output_file_name)
{
  int result;
  long int output_buffer_size;
  long int pixel_count;

  pixel_count = (long int) checkerboard_size * (long int) checkerboard_size;
  output_buffer_size = pixel_count * 3;
  unsigned char *output_buffer;
  output_buffer = malloc (output_buffer_size);
  if (output_buffer == NULL)
    {
      fprintf (stderr, "Unable to allocate output buffer of %ld bytes.\n",
        output_buffer_size);
      exit (EXIT_FAILURE);
    }

/*
 * Create the checkerboard.
 */
  int row, column;
  for (row = 0; row < checkerboard_size; row++)
    {
      for (column = 0; column < checkerboard_size; column++)
        {
          int color = (row ^ column) & 1;
          long int buffer_pointer = 3L *
            ((long int) ((long int) row * (long int) checkerboard_size) +
                (long int) column);
          switch (color)
            {
            case 0:
              output_buffer[buffer_pointer] = random_val();
              output_buffer[buffer_pointer + 1] = random_val();
              output_buffer[buffer_pointer + 2] = random_val();
              break;
            case 1:
              output_buffer[buffer_pointer] = 255 ^ random_val();
              output_buffer[buffer_pointer + 1] = 255 ^ random_val();
              output_buffer[buffer_pointer + 2] = 255 ^ random_val();
              break;
            }
        }
    }

/*
 * Write the image.
 */
  FILE *fp;
  fp = fopen (output_file_name, "wb");
  if (!fp)
    {
      fprintf (stderr, "File: %s\n", output_file_name);
      errno_exit ("Opening png file.");
    }
  png_structp png_ptr = png_create_write_struct
    (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if (!png_ptr)
    {
      fprintf (stderr, "Unable to allocate png write structure.\n");
      exit (EXIT_FAILURE);
    }
  png_infop info_ptr = png_create_info_struct (png_ptr);
  if (!info_ptr)
    {
      png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
      fprintf (stderr, "Unable to allocate png info structure.\n");
      exit (EXIT_FAILURE);
    }
  if (setjmp (png_jmpbuf (png_ptr)))
    {
      fprintf (stderr, "Error during png file processing.\n");
      png_destroy_write_struct (&png_ptr, &info_ptr);
      fclose (fp);
      exit (EXIT_FAILURE);
    }
  png_init_io (png_ptr, fp);
  png_set_IHDR (png_ptr, info_ptr, checkerboard_size,
                checkerboard_size, 8,
                PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
                PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
  png_set_compression_level (png_ptr, png_compression_level_value);
  if (checkerboard_size > PNG_UINT_32_MAX / png_sizeof (png_byte))
    png_error (png_ptr, "Image is too tall to process in memory");
  if (checkerboard_size > PNG_UINT_32_MAX / 3)
    png_error (png_ptr, "Image is too wide to process in memory");
  png_bytep* row_pointers;
  row_pointers = png_malloc (png_ptr,
    (long int) sizeof(png_bytep) * (long int) checkerboard_size);
  if (row_pointers == NULL)
    {
      fprintf (stderr, "Unable to allocate row pointers: %ld bytes.\n",
        sizeof(png_bytep) * checkerboard_size);
      png_destroy_write_struct (&png_ptr, &info_ptr);
      fclose (fp);
      exit (EXIT_FAILURE);
    }
  long int row_no;
  for (row_no = 0; row_no < checkerboard_size; row_no++)
    row_pointers[row_no] = &output_buffer[row_no * (long int) (checkerboard_size * 3)];
  png_set_rows (png_ptr, info_ptr, &row_pointers[0]);
  png_write_png (png_ptr, info_ptr, 0, NULL);
  png_destroy_write_struct (&png_ptr, &info_ptr);
  free (output_buffer);
  result = fclose (fp);
  if (result != 0)
    {
      fprintf (stderr, "File: %s\n", output_file_name);
      errno_exit ("closing png file");
    }
}

static void
usage (FILE * fp, int argc, char **argv)
{
  fprintf (fp,
           "Usage: %s [options]\n\n"
           "\n"
           "Write a checkerboard image in png format.\n"
           " Version 2.0 2012-05-10\n"
           "\n"
           "Options:\n"
           "-h | --help          Print this message\n"
           "-o | --output-file   Where to put the png file\n"
           "-p | --png-compression-level space vs speed, 0-9, default 3\n"
           "-s | --size          Size of the checkerboard, in pixels\n"
           "-r | --random        Random bits to add to each check, 0-8\n"
           "-D | --debug-level   Amount of debugging output, default 0\n"
           "", argv[0]);
}

static const char short_options[] = "ho:p:s:r:D:";

static const struct option long_options[] = {
  {"help", no_argument, NULL, 'h'},
  {"output-file", required_argument, NULL, 'o'},
  {"png-compression-level", required_argument, NULL, 'p'},
  {"size", required_argument, NULL, 's'},
  {"random", required_argument, NULL, 'r'},
  {"debug-level", required_argument, NULL, 'D'},
  {0, 0, 0, 0}
};

/* main program: parse options, convert file, exit. */
int
main (int argc, char **argv)
{

  for (;;)
    {
      int index;
      int c;

      c = getopt_long (argc, argv, short_options, long_options, &index);

      if (-1 == c)
        break;

      switch (c)
        {
        case 0:         /* getopt_long() flag */
          break;

        case 'h':
          usage (stdout, argc, argv);
          exit (EXIT_SUCCESS);

        case 'o':
          output_file = optarg;
          break;

        case 'p':
          png_compression_level_value = atoi (optarg);
          break;

        case 's':
          checkerboard_size = atoi (optarg);
          break;

        case 'r':
          random_bits = atoi (optarg);
          random_mask = (1 << (random_bits+1)) - 1;
          break;

        case 'D':
          debug_level = atoi (optarg);
          break;

        default:
          usage (stderr, argc, argv);
          exit (EXIT_FAILURE);
        }
    }

  if (output_file == NULL)
    {
      fprintf (stderr, "The output file must be specified.\n");
      exit (EXIT_FAILURE);
    }
  write_file (output_file);
  exit (EXIT_SUCCESS);

  return 0;
}


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 1 post ] 

All times are UTC + 1 hour


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group