Imager

 view release on metacpan or  search on metacpan

SGI/imsgi.c  view on Meta::CPAN

=item i_writergb_wiol(img, ig)

Writes an image in targa format.  Returns 0 on error.

   img    - image to store
   ig     - io_glue object

=cut
*/

int
i_writesgi_wiol(io_glue *ig, i_img *img) {
  int rle;
  int bpc2;

  i_clear_error();

  if (img->xsize > SGI_DIM_LIMIT || img->ysize > SGI_DIM_LIMIT) {
    i_push_error(0, "image too large for SGI");
    return 0;
  }

  if (!write_sgi_header(img, ig, &rle, &bpc2))
    return 0;

  mm_log((1, "format rle %d bpc2 %d\n", rle, bpc2));

  if (bpc2) {
    if (rle)
      return write_sgi_16_rle(img, ig);
    else
      return write_sgi_16_verb(img, ig);
  }
  else {
    if (rle)
      return write_sgi_8_rle(img, ig);
    else
      return write_sgi_8_verb(img, ig);
  }
}

static i_img *
read_rgb_8_verbatim(i_img *img, io_glue *ig, rgb_header const *header) {
  i_color *linebuf;
  unsigned char *databuf;
  int c, y;
  int savemask;
  i_img_dim width = i_img_get_width(img);
  i_img_dim height = i_img_get_height(img);
  int channels = i_img_getchannels(img);
  int pixmin = header->pixmin;
  int pixmax = header->pixmax;
  int outmax = pixmax - pixmin;
  
  linebuf   = mymalloc(width * sizeof(i_color)); /* checked 31Jul07 TonyC */
  databuf   = mymalloc(width); /* checked 31Jul07 TonyC */

  savemask = i_img_getmask(img);

  for(c = 0; c < channels; c++) {
    i_img_setmask(img, 1<<c);
    for(y = 0; y < height; y++) {
      int x;
      
      if (i_io_read(ig, databuf, width) != width) {
	i_push_error(0, "SGI image: cannot read image data");
	i_img_destroy(img);
	myfree(linebuf);
	myfree(databuf);
	return NULL;
      }

      if (pixmin == 0 && pixmax == 255) {
	for(x = 0; x < img->xsize; x++)
	  linebuf[x].channel[c] = databuf[x];
      }
      else {
	for(x = 0; x < img->xsize; x++) {
	  int sample = databuf[x];
	  if (sample < pixmin)
	    sample = 0;
	  else if (sample > pixmax)
	    sample = outmax;
	  else
	    sample -= pixmin;
	    
	  linebuf[x].channel[c] = sample * 255 / outmax;
	}
      }
      
      i_plin(img, 0, width, height-1-y, linebuf);
    }
  }
  i_img_setmask(img, savemask);

  myfree(linebuf);
  myfree(databuf);
  
  return img;
}

static int
read_rle_tables(io_glue *ig, i_img *img,
		unsigned long **pstart_tab, unsigned long **plength_tab, 
		unsigned long *pmax_length) {
  i_img_dim height = i_img_get_height(img);
  int channels = i_img_getchannels(img);
  unsigned char *databuf;
  unsigned long *start_tab, *length_tab;
  unsigned long max_length = 0;
  int i;
  size_t databuf_size = (size_t)height * channels * 4;
  size_t tab_size = (size_t)height * channels * sizeof(unsigned long);

  /* assumption: that the lengths are in bytes rather than in pixels */
  if (databuf_size / height / channels != 4
      || tab_size / height / channels != sizeof(unsigned long)) {
    i_push_error(0, "SGI image: integer overflow calculating allocation size");
    return 0;
  }
  databuf    = mymalloc(height * channels * 4);  /* checked 31Jul07 TonyC */
  start_tab  = mymalloc(height*channels*sizeof(unsigned long));
  length_tab = mymalloc(height*channels*sizeof(unsigned long));
    
    /* Read offset table */
  if (i_io_read(ig, databuf, height * channels * 4) != height * channels * 4) {
    i_push_error(0, "SGI image: short read reading RLE start table");
    goto ErrorReturn;
  }

  for(i = 0; i < height * channels; i++) 
    start_tab[i] = ((unsigned long)databuf[i*4] << 24) | (databuf[i*4+1] << 16) |
      (databuf[i*4+2] << 8) | (databuf[i*4+3]);


  /* Read length table */
  if (i_io_read(ig, databuf, height*channels*4) != height*channels*4) {
    i_push_error(0, "SGI image: short read reading RLE length table");
    goto ErrorReturn;
  }

  for(i=0; i < height * channels; i++) {
    length_tab[i] = ((unsigned long)databuf[i*4] << 24) | (databuf[i*4+1] << 16) |
      (databuf[i*4+2] << 8) | (databuf[i*4+3]);
    if (length_tab[i] > max_length)
      max_length = length_tab[i];
  }

  mm_log((3, "Offset/length table:\n"));
  for(i=0; i < height * channels; i++)
    mm_log((3, "%d: %lu/%lu\n", i, start_tab[i], length_tab[i]));

  *pstart_tab = start_tab;
  *plength_tab = length_tab;

SGI/imsgi.c  view on Meta::CPAN

	  }
	  --data_left;
	  pixels_left -= count;
	  while (count-- > 0) {
	    outp->channel[c] = sample;
	    ++outp;
	  }
	}
      }
      /* must have a full scanline */
      if (pixels_left) {
	i_push_error(0, "SGI image: incomplete RLE scanline");
	goto ErrorReturn;
      }
      /* must have used all of the data */
      if (data_left) {
	i_push_errorf(0, "SGI image: unused RLE data");
	goto ErrorReturn;
      }
    }
    i_plin(img, 0, width, height-1-y, linebuf);
  }

  myfree(linebuf);
  myfree(databuf);
  myfree(start_tab);
  myfree(length_tab);

  return img;

 ErrorReturn:
  if (linebuf)
    myfree(linebuf);
  if (databuf)
    myfree(databuf);
  myfree(start_tab);
  myfree(length_tab);
  i_img_destroy(img);
  return NULL;
}

static i_img *
read_rgb_16_verbatim(i_img *img, io_glue *ig, rgb_header const *header) {
  i_fcolor *linebuf;
  unsigned char *databuf;
  int c, y;
  int savemask;
  i_img_dim width = i_img_get_width(img);
  i_img_dim height = i_img_get_height(img);
  int channels = i_img_getchannels(img);
  int pixmin = header->pixmin;
  int pixmax = header->pixmax;
  int outmax = pixmax - pixmin;
  
  linebuf   = mymalloc(width * sizeof(i_fcolor));  /* checked 31Jul07 TonyC */
  databuf   = mymalloc(width * 2);  /* checked 31Jul07 TonyC */

  savemask = i_img_getmask(img);

  for(c = 0; c < channels; c++) {
    i_img_setmask(img, 1<<c);
    for(y = 0; y < height; y++) {
      int x;
      
      if (i_io_read(ig, databuf, width*2) != width*2) {
	i_push_error(0, "SGI image: cannot read image data");
	i_img_destroy(img);
	myfree(linebuf);
	myfree(databuf);
	return NULL;
      }

      if (pixmin == 0 && pixmax == 65535) {
	for(x = 0; x < img->xsize; x++)
	  linebuf[x].channel[c] = (databuf[x*2] * 256 + databuf[x*2+1]) / 65535.0;
      }
      else {
	for(x = 0; x < img->xsize; x++) {
	  int sample = databuf[x*2] * 256 + databuf[x*2+1];
	  if (sample < pixmin)
	    sample = 0;
	  else if (sample > pixmax)
	    sample = outmax;
	  else
	    sample -= pixmin;
	    
	  linebuf[x].channel[c] = (double)sample / outmax;
	}
      }
      
      i_plinf(img, 0, width, height-1-y, linebuf);
    }
  }
  i_img_setmask(img, savemask);

  myfree(linebuf);
  myfree(databuf);
  
  return img;
}

static i_img *
read_rgb_16_rle(i_img *img, io_glue *ig, rgb_header const *header) {
  i_fcolor *linebuf = NULL;
  unsigned char *databuf = NULL;
  unsigned long *start_tab, *length_tab;
  unsigned long max_length;
  i_img_dim width = i_img_get_width(img);
  i_img_dim height = i_img_get_height(img);
  int channels = i_img_getchannels(img);
  i_img_dim y;
  int c;
  int pixmin = header->pixmin;
  int pixmax = header->pixmax;
  int outmax = pixmax - pixmin;

  if (!read_rle_tables(ig, img,  
		       &start_tab, &length_tab, &max_length)) {
    i_img_destroy(img);
    return NULL;
  }

  mm_log((1, "maxlen for an rle buffer: %lu\n", max_length));

  if (max_length > (img->xsize * 2 + 1) * 2) {
    i_push_errorf(0, "SGI image: ridiculous RLE line length %lu", max_length);
    goto ErrorReturn;
  }

  linebuf = mymalloc(width*sizeof(i_fcolor)); /* checked 31Jul07 TonyC */
  databuf = mymalloc(max_length); /* checked 31Jul07 TonyC */

  for(y = 0; y < img->ysize; y++) {
    for(c = 0; c < channels; c++) {
      int ci = height * c + y;
      int datalen = length_tab[ci];
      unsigned char *inp;
      i_fcolor *outp;
      int data_left = datalen;
      int pixels_left = width;
      int sample;
      
      if (datalen & 1) {
	i_push_error(0, "SGI image: invalid RLE length value for BPC=2");
	goto ErrorReturn;
      }
      if (i_io_seek(ig, start_tab[ci], SEEK_SET) != start_tab[ci]) {
	i_push_error(0, "SGI image: cannot seek to RLE data");
	goto ErrorReturn;
      }
      if (i_io_read(ig, databuf, datalen) != datalen) {
	i_push_error(0, "SGI image: cannot read RLE data");
	goto ErrorReturn;
      }



( run in 1.027 second using v1.01-cache-2.11-cpan-99c4e6809bf )