[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/dpsanders/matplotlib/transforms/src/_image.cpp [Back]  [Original]

#include 
#include 
#include 
#include 
#include 

#include "Python.h" //after png.h due to setjmp bug
#include 

#define PY_ARRAY_TYPES_PREFIX NumPy
#include "numpy/arrayobject.h"

#include "agg_color_rgba.h"
#include "agg_conv_transform.h"
#include "agg_image_accessors.h"
#include "agg_path_storage.h"
#include "agg_pixfmt_rgb.h"
#include "agg_pixfmt_rgba.h"
#include "agg_rasterizer_scanline_aa.h"
#include "agg_renderer_scanline.h"
#include "agg_rendering_buffer.h"
#include "agg_scanline_bin.h"
#include "agg_scanline_bin.h"
#include "agg_scanline_u.h"
#include "agg_span_allocator.h"
#include "agg_span_image_filter_rgb.h"
#include "agg_span_image_filter_rgba.h"
#include "agg_span_interpolator_linear.h"
#include "util/agg_color_conv_rgb8.h"
#include "_image.h"
#include "mplutils.h"


typedef agg::pixfmt_rgba32 pixfmt;
typedef agg::renderer_base renderer_base;
typedef agg::span_interpolator_linear interpolator_type;
typedef agg::rasterizer_scanline_aa rasterizer;


Image::Image() :
  bufferIn(NULL), rbufIn(NULL), colsIn(0), rowsIn(0),
  bufferOut(NULL), rbufOut(NULL), colsOut(0), rowsOut(0),  BPP(4),
  interpolation(BILINEAR), aspect(ASPECT_FREE), bg(1,1,1,0) {
  _VERBOSE("Image::Image");
}

Image::~Image() {
  _VERBOSE("Image::~Image");
  delete [] bufferIn; bufferIn = NULL;
  delete rbufIn; rbufIn=NULL;
  delete rbufOut; rbufOut = NULL;
  delete [] bufferOut; bufferOut=NULL;
}

int
Image::setattr( const char * name, const Py::Object & value ) {
  _VERBOSE("Image::setattr");
  __dict__[name] = value;
  return 0;
}

Py::Object
Image::getattr( const char * name ) {
  _VERBOSE("Image::getattro");
  if ( __dict__.hasKey(name) ) return __dict__[name];
  else return getattr_default( name );

}

char Image::apply_rotation__doc__[] =
"apply_rotation(angle)\n"
"\n"
"Apply the rotation (degrees) to image"
;
Py::Object
Image::apply_rotation(const Py::Tuple& args) {
  _VERBOSE("Image::apply_rotation");

  args.verify_length(1);
  double r = Py::Float(args[0]);


  agg::trans_affine M = agg::trans_affine_rotation( r * agg::pi / 180.0);
  srcMatrix *= M;
  imageMatrix *= M;
  return Py::Object();
}


char Image::flipud_out__doc__[] =
"flipud()\n"
"\n"
"Flip the output image upside down"
;
Py::Object
Image::flipud_out(const Py::Tuple& args) {
  _VERBOSE("Image::flipud_out");

  args.verify_length(0);
  int stride = rbufOut->stride();
  rbufOut->attach(bufferOut, colsOut, rowsOut, -stride);
  return Py::Object();
}

char Image::flipud_in__doc__[] =
"flipud()\n"
"\n"
"Flip the input image upside down"
;
Py::Object
Image::flipud_in(const Py::Tuple& args) {
  _VERBOSE("Image::flipud_in");

  args.verify_length(0);
  int stride = rbufIn->stride();
  rbufIn->attach(bufferIn, colsIn, rowsIn, -stride);

  return Py::Object();
}

char Image::set_bg__doc__[] =
"set_bg(r,g,b,a)\n"
"\n"
"Set the background color"
;

Py::Object
Image::set_bg(const Py::Tuple& args) {
  _VERBOSE("Image::set_bg");

  args.verify_length(4);
  bg.r = Py::Float(args[0]);
  bg.g = Py::Float(args[1]);
  bg.b = Py::Float(args[2]);
  bg.a = Py::Float(args[3]);
  return Py::Object();
}

char Image::apply_scaling__doc__[] =
"apply_scaling(sx, sy)\n"
"\n"
"Apply the scale factors sx, sy to the transform matrix"
;

Py::Object
Image::apply_scaling(const Py::Tuple& args) {
  _VERBOSE("Image::apply_scaling");

  args.verify_length(2);
  double sx = Py::Float(args[0]);
  double sy = Py::Float(args[1]);

  //printf("applying scaling %1.2f, %1.2f\n", sx, sy);
  agg::trans_affine M = agg::trans_affine_scaling(sx, sy);
  srcMatrix *= M;
  imageMatrix *= M;

  return Py::Object();


}

char Image::apply_translation__doc__[] =
"apply_translation(tx, ty)\n"
"\n"
"Apply the translation tx, ty to the transform matrix"
;

Py::Object
Image::apply_translation(const Py::Tuple& args) {
  _VERBOSE("Image::apply_translation");

  args.verify_length(2);
  double tx = Py::Float(args[0]);
  double ty = Py::Float(args[1]);

  //printf("applying translation %1.2f, %1.2f\n", tx, ty);
  agg::trans_affine M = agg::trans_affine_translation(tx, ty);
  srcMatrix *= M;
  imageMatrix *= M;

  return Py::Object();


}

char Image::as_rgba_str__doc__[] =
"numrows, numcols, s = as_rgba_str()"
"\n"
"Call this function after resize to get the data as string\n"
"The string is a numrows by numcols x 4 (RGBA) unsigned char buffer\n"
;

Py::Object
Image::as_rgba_str(const Py::Tuple& args, const Py::Dict& kwargs) {
  _VERBOSE("Image::as_rgba_str");

  args.verify_length(0);

  std::pair bufpair = _get_output_buffer();

  Py::Object ret =  Py::asObject(Py_BuildValue("lls#", rowsOut, colsOut,
					       bufpair.first, colsOut*rowsOut*4));

  if (bufpair.second) delete [] bufpair.first;
  return ret;
}


char Image::color_conv__doc__[] =
"numrows, numcols, buffer = color_conv(format)"
"\n"
"format 0(BGRA) or 1(ARGB)\n"
"Convert image to format and return in a writable buffer\n"
;
Py::Object
Image::color_conv(const Py::Tuple& args) {
  _VERBOSE("Image::color_conv");

  args.verify_length(1);
  int format = Py::Int(args[0]);

  int row_len = colsOut * 4;
  PyObject* py_buffer = PyBuffer_New(row_len * rowsOut);
  if (py_buffer ==NULL)
    throw Py::MemoryError("Image::color_conv could not allocate memory");

  void* buf;
  Py_ssize_t buffer_len;
  int ret = PyObject_AsWriteBuffer(py_buffer, &buf, &buffer_len);
  if (ret !=0)
    throw Py::MemoryError("Image::color_conv could not allocate memory");

  agg::rendering_buffer rtmp;
  rtmp.attach(reinterpret_cast(buf), colsOut, rowsOut,
	      row_len);

  switch (format) {
  case 0:
    agg::color_conv(&rtmp, rbufOut, agg::color_conv_rgba32_to_bgra32());
    break;
  case 1:
    agg::color_conv(&rtmp, rbufOut, agg::color_conv_rgba32_to_argb32());
    break;
  default:
    throw Py::ValueError("Image::color_conv unknown format");
  }
  PyObject* o = Py_BuildValue("llN", rowsOut, colsOut, py_buffer);
  return Py::asObject(o);
}

char Image::buffer_rgba__doc__[] =
"buffer = buffer_rgba()"
"\n"
"Return the image buffer as rgba32\n"
;
Py::Object
Image::buffer_rgba(const Py::Tuple& args) {
  //"Return the image object as rgba";

  _VERBOSE("RendererAgg::buffer_rgba");

  args.verify_length(0);
  int row_len = colsOut * 4;
  PyObject* o = Py_BuildValue("lls#", rowsOut, colsOut,
			      rbufOut, row_len * rowsOut);
  return Py::asObject(o);
}

char Image::reset_matrix__doc__[] =
"reset_matrix()"
"\n"
"Reset the transformation matrix"
;

Py::Object
Image::reset_matrix(const Py::Tuple& args) {
  _VERBOSE("Image::reset_matrix");

  args.verify_length(0);
  srcMatrix.reset();
  imageMatrix.reset();

  return Py::Object();


}

char Image::get_matrix__doc__[] =
"(m11,m21,m12,m22,m13,m23) = get_matrix()\n"
"\n"
"Get the affine transformation matrix\n"
"  /m11,m12,m13\\\n"
"  /m21,m22,m23|\n"
"  \\ 0 , 0 , 1 /"
;

Py::Object
Image::get_matrix(const Py::Tuple& args) {
  _VERBOSE("Image::get_size");

  args.verify_length(0);

  double m[6];
  srcMatrix.store_to(m);
  Py::Tuple ret(6);
  for(int i=0;iattach(bufferOut, numcols, numrows, numcols * BPP);

  // init the output rendering/rasterizing stuff
  pixfmt pixf(*rbufOut);
  renderer_base rb(pixf);
  rb.clear(bg);
  agg::rasterizer_scanline_aa ras;
  agg::scanline_u8 sl;


  //srcMatrix *= resizingMatrix;
  //imageMatrix *= resizingMatrix;
  imageMatrix.invert();
  interpolator_type interpolator(imageMatrix);

  typedef agg::span_allocator span_alloc_type;
  span_alloc_type sa;
  agg::rgba8 background(agg::rgba8(int(255*bg.r),
				   int(255*bg.g),
				   int(255*bg.b),
				   int(255*bg.a)));

  // the image path
  agg::path_storage path;
  agg::int8u *bufferPad = NULL;
  agg::rendering_buffer rbufPad;

  double x0, y0, x1, y1;

  x0 = 0.0;
  x1 = colsIn;
  y0 = 0.0;
  y1 = rowsIn;

  path.move_to(x0, y0);
  path.line_to(x1, y0);
  path.line_to(x1, y1);
  path.line_to(x0, y1);
  path.close_polygon();
  agg::conv_transform imageBox(path, srcMatrix);
  ras.add_path(imageBox);

  typedef agg::wrap_mode_reflect reflect_type;
  typedef agg::image_accessor_wrap img_accessor_type;

  pixfmt pixfmtin(*rbufIn);
  img_accessor_type ia(pixfmtin);
  switch(interpolation)
    {

    case NEAREST:
      {
	typedef agg::span_image_filter_rgba_nn span_gen_type;
	typedef agg::renderer_scanline_aa renderer_type;
	span_gen_type sg(ia, interpolator);
	renderer_type ri(rb, sa, sg);
	agg::render_scanlines(ras, sl, ri);
      }
      break;
        case BILINEAR:
        case BICUBIC:
        case SPLINE16:
        case SPLINE36:
        case HANNING:
        case HAMMING:
        case HERMITE:
        case KAISER:
        case QUADRIC:
        case CATROM:
        case GAUSSIAN:
        case BESSEL:
        case MITCHELL:
        case SINC:
        case LANCZOS:
        case BLACKMAN:
            {
                agg::image_filter_lut filter;
                switch(interpolation)
                {
                case BILINEAR:  filter.calculate(agg::image_filter_bilinear(), norm); break;
                case BICUBIC:  filter.calculate(agg::image_filter_bicubic(), norm); break;
                case SPLINE16:  filter.calculate(agg::image_filter_spline16(), norm); break;
                case SPLINE36:  filter.calculate(agg::image_filter_spline36(), norm); break;
                case HANNING:  filter.calculate(agg::image_filter_hanning(), norm); break;
                case HAMMING:  filter.calculate(agg::image_filter_hamming(), norm); break;
                case HERMITE:  filter.calculate(agg::image_filter_hermite(), norm); break;
                case KAISER:  filter.calculate(agg::image_filter_kaiser(), norm); break;
                case QUADRIC:  filter.calculate(agg::image_filter_quadric(), norm); break;
                case CATROM: filter.calculate(agg::image_filter_catrom(), norm); break;
                case GAUSSIAN: filter.calculate(agg::image_filter_gaussian(), norm); break;
                case BESSEL: filter.calculate(agg::image_filter_bessel(), norm); break;
                case MITCHELL: filter.calculate(agg::image_filter_mitchell(), norm); break;
                case SINC: filter.calculate(agg::image_filter_sinc(radius), norm); break;
                case LANCZOS: filter.calculate(agg::image_filter_lanczos(radius), norm); break;
                case BLACKMAN: filter.calculate(agg::image_filter_blackman(radius), norm); break;
                }
	typedef agg::span_image_filter_rgba_2x2 span_gen_type;
	typedef agg::renderer_scanline_aa renderer_type;
	span_gen_type sg(ia, interpolator, filter);
	renderer_type ri(rb, sa, sg);
	agg::render_scanlines(ras, sl, ri);
      }
      break;

    }

  delete [] bufferPad;
  return Py::Object();

}


char Image::get_interpolation__doc__[] =
"get_interpolation()\n"
"\n"
"Get the interpolation scheme to one of the module constants, "
"one of image.NEAREST, image.BILINEAR, etc..."
;

Py::Object
Image::get_interpolation(const Py::Tuple& args) {
  _VERBOSE("Image::get_interpolation");

  args.verify_length(0);
  return Py::Int((int)interpolation);
}


char Image::get_aspect__doc__[] =
"get_aspect()\n"
"\n"
"Get the aspect constraint constants"
;

Py::Object
Image::get_aspect(const Py::Tuple& args) {
  _VERBOSE("Image::get_aspect");

  args.verify_length(0);
  return Py::Int((int)aspect);
}

char Image::get_size__doc__[] =
"numrows, numcols = get_size()\n"
"\n"
"Get the number or rows and columns of the input image"
;

Py::Object
Image::get_size(const Py::Tuple& args) {
  _VERBOSE("Image::get_size");

  args.verify_length(0);

  Py::Tuple ret(2);
  ret[0] = Py::Int((long)rowsIn);
  ret[1] = Py::Int((long)colsIn);
  return ret;

}

char Image::get_size_out__doc__[] =
"numrows, numcols = get_size()\n"
"\n"
"Get the number or rows and columns of the output image"
;

Py::Object
Image::get_size_out(const Py::Tuple& args) {
  _VERBOSE("Image::get_size");

  args.verify_length(0);

  Py::Tuple ret(2);
  ret[0] = Py::Int((long)rowsOut);
  ret[1] = Py::Int((long)colsOut);
  return ret;

}

//get the output buffer, flipped if necessary.  The second element of
//the pair is a bool that indicates whether you need to free the
//memory
std::pair
Image::_get_output_buffer() {
  _VERBOSE("Image::_get_output_buffer");
  std::pair ret;
  bool flipy = rbufOut->stride()jmpbuf)) {
    if (bufpair.second) delete [] bufpair.first;
    fclose(fp);
    png_destroy_write_struct(&png_ptr, &info_ptr);
    delete [] row_pointers;
    throw Py::RuntimeError("Error building image");
  }

  png_init_io(png_ptr, fp);
  png_set_IHDR(png_ptr, info_ptr,
	       colsOut, rowsOut, 8,
	       PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
	       PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

  // this a a color image!
  sig_bit.gray = 0;
  sig_bit.red = 8;
  sig_bit.green = 8;
  sig_bit.blue = 8;
  /* if the image has an alpha channel then */
  sig_bit.alpha = 8;
  png_set_sBIT(png_ptr, info_ptr, &sig_bit);

  png_write_info(png_ptr, info_ptr);
  png_write_image(png_ptr, row_pointers);
  png_write_end(png_ptr, info_ptr);
  png_destroy_write_struct(&png_ptr, &info_ptr);
  fclose(fp);

  delete [] row_pointers;

  if (bufpair.second) delete [] bufpair.first;
  return Py::Object();
}


char Image::set_aspect__doc__[] =
"set_aspect(scheme)\n"
"\n"
"Set the aspect ration to one of the image module constant."
"eg, one of image.ASPECT_PRESERVE, image.ASPECT_FREE"
;
Py::Object
Image::set_aspect(const Py::Tuple& args) {
  _VERBOSE("Image::set_aspect");

  args.verify_length(1);
  size_t method = Py::Int(args[0]);
  aspect = (unsigned)method;
  return Py::Object();

}

void
Image::init_type() {
  _VERBOSE("Image::init_type");

  behaviors().name("Image");
  behaviors().doc("Image");
  behaviors().supportGetattr();
  behaviors().supportSetattr();

  add_varargs_method( "apply_rotation", &Image::apply_rotation, Image::apply_rotation__doc__);
  add_varargs_method( "apply_scaling",	&Image::apply_scaling, Image::apply_scaling__doc__);
  add_varargs_method( "apply_translation", &Image::apply_translation, Image::apply_translation__doc__);
  add_keyword_method( "as_rgba_str", &Image::as_rgba_str, Image::as_rgba_str__doc__);
  add_varargs_method( "color_conv", &Image::color_conv, Image::color_conv__doc__);
  add_varargs_method( "buffer_rgba", &Image::buffer_rgba, Image::buffer_rgba__doc__);
  add_varargs_method( "get_aspect", &Image::get_aspect, Image::get_aspect__doc__);
  add_varargs_method( "get_interpolation", &Image::get_interpolation, Image::get_interpolation__doc__);
  add_varargs_method( "get_size", &Image::get_size, Image::get_size__doc__);
  add_varargs_method( "get_size_out", &Image::get_size_out, Image::get_size_out__doc__);
  add_varargs_method( "reset_matrix", &Image::reset_matrix, Image::reset_matrix__doc__);
  add_varargs_method( "get_matrix", &Image::get_matrix, Image::get_matrix__doc__);
  add_keyword_method( "resize", &Image::resize, Image::resize__doc__);
  add_varargs_method( "set_interpolation", &Image::set_interpolation, Image::set_interpolation__doc__);
  add_varargs_method( "set_aspect", &Image::set_aspect, Image::set_aspect__doc__);
  add_varargs_method( "write_png", &Image::write_png, Image::write_png__doc__);
  add_varargs_method( "set_bg", &Image::set_bg, Image::set_bg__doc__);
  add_varargs_method( "flipud_out", &Image::flipud_out, Image::flipud_out__doc__);
  add_varargs_method( "flipud_in", &Image::flipud_in, Image::flipud_in__doc__);


}


char _image_module_from_images__doc__[] =
"from_images(numrows, numcols, seq)\n"
"\n"
"return an image instance with numrows, numcols from a seq of image\n"
"instances using alpha blending.  seq is a list of (Image, ox, oy)"
;
Py::Object
_image_module::from_images(const Py::Tuple& args) {
  _VERBOSE("_image_module::from_images");

  args.verify_length(3);

  size_t numrows = Py::Int(args[0]);
  size_t numcols = Py::Int(args[1]);

  Py::SeqBase tups = args[2];
  size_t N = tups.length();

  if (N==0)
    throw Py::RuntimeError("Empty list of images");

  Py::Tuple tup;

  size_t ox(0), oy(0), thisx(0), thisy(0);

  //copy image 0 output buffer into return images output buffer
  Image* imo = new Image;
  imo->rowsOut  = numrows;
  imo->colsOut  = numcols;

  size_t NUMBYTES(numrows * numcols * imo->BPP);
  imo->bufferOut = new agg::int8u[NUMBYTES];
  if (imo->bufferOut==NULL) //todo: also handle allocation throw
    throw Py::MemoryError("_image_module::from_images could not allocate memory");

  delete imo->rbufOut;
  imo->rbufOut = new agg::rendering_buffer;
  imo->rbufOut->attach(imo->bufferOut, imo->colsOut, imo->rowsOut, imo->colsOut * imo->BPP);

  pixfmt pixf(*imo->rbufOut);
  renderer_base rb(pixf);


  for (size_t imnum=0; imnum< N; imnum++) {
    tup = Py::Tuple(tups[imnum]);
    Image* thisim = static_cast(tup[0].ptr());
    if (imnum==0)
      rb.clear(thisim->bg);
    ox = Py::Int(tup[1]);
    oy = Py::Int(tup[2]);

    size_t ind=0;
    for (size_t j=0; jrowsOut; j++) {
      for (size_t i=0; icolsOut; i++) {
	thisx = i+ox;
	thisy = j+oy;
	if (thisx=numcols || thisy=numrows) {
	  ind +=4;
	  continue;
	}

	pixfmt::color_type p;
	p.r = *(thisim->bufferOut+ind++);
	p.g = *(thisim->bufferOut+ind++);
	p.b = *(thisim->bufferOut+ind++);
	p.a = *(thisim->bufferOut+ind++);
	pixf.blend_pixel(thisx, thisy, p, 255);
      }
    }
  }

  return Py::asObject(imo);


}


char _image_module_readpng__doc__[] =
"readpng(fname)\n"
"\n"
"Load an image from png file into a numerix array of MxNx4 uint8";
Py::Object
_image_module::readpng(const Py::Tuple& args) {

  args.verify_length(1);
  std::string fname = Py::String(args[0]);

  png_byte header[8];	// 8 is the maximum size that can be checked

  FILE *fp = fopen(fname.c_str(), "rb");
  if (!fp)
    throw Py::RuntimeError(Printf("_image_module::readpng could not open PNG file %s for reading", fname.c_str()).str());

  if (fread(header, 1, 8, fp) != 8)
    throw Py::RuntimeError("_image_module::readpng: error reading PNG header");
  if (png_sig_cmp(header, 0, 8))
    throw Py::RuntimeError("_image_module::readpng: file not recognized as a PNG file");


  /* initialize stuff */
  png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

  if (!png_ptr)
    throw Py::RuntimeError("_image_module::readpng:  png_create_read_struct failed");

  png_infop info_ptr = png_create_info_struct(png_ptr);
  if (!info_ptr)
    throw Py::RuntimeError("_image_module::readpng:  png_create_info_struct failed");

  if (setjmp(png_jmpbuf(png_ptr)))
    throw Py::RuntimeError("_image_module::readpng:  error during init_io");

  png_init_io(png_ptr, fp);
  png_set_sig_bytes(png_ptr, 8);

  png_read_info(png_ptr, info_ptr);

  png_uint_32 width = info_ptr->width;
  png_uint_32 height = info_ptr->height;

  // convert misc color types to rgb for simplicity
  if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
      info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
    png_set_gray_to_rgb(png_ptr);
  else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
    png_set_palette_to_rgb(png_ptr);


  int bit_depth = info_ptr->bit_depth;
  if (bit_depth == 16)  png_set_strip_16(png_ptr);


  png_set_interlace_handling(png_ptr);
  png_read_update_info(png_ptr, info_ptr);

  bool rgba = info_ptr->color_type == PNG_COLOR_TYPE_RGBA;
  if ( (info_ptr->color_type != PNG_COLOR_TYPE_RGB) && !rgba) {
    std::cerr strides[1];
      //if ((ystrides[2]) = ptr[2]/255.0;
      *(float*)(A->data + offset + 3*A->strides[2]) = rgba ? ptr[3]/255.0 : 1.0;
    }
  }

  //free the png memory
  png_read_end(png_ptr, info_ptr);
  png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
  fclose(fp);
  for (row = 0; row < height; row++)
    delete [] row_pointers[row];
  delete [] row_pointers;
  return Py::asObject((PyObject*)A);
}


char _image_module_fromarray__doc__[] =
"fromarray(A, isoutput)\n"
"\n"
"Load the image from a numpy array\n"
"By default this function fills the input buffer, which can subsequently\n"
"be resampled using resize.  If isoutput=1, fill the output buffer.\n"
"This is used to support raw pixel images w/o resampling"
;
Py::Object
_image_module::fromarray(const Py::Tuple& args) {
  _VERBOSE("_image_module::fromarray");

  args.verify_length(2);

  Py::Object x = args[0];
  int isoutput = Py::Int(args[1]);
  //PyArrayObject *A = (PyArrayObject *) PyArray_ContiguousFromObject(x.ptr(), PyArray_DOUBLE, 2, 3);
  PyArrayObject *A = (PyArrayObject *) PyArray_FromObject(x.ptr(), PyArray_DOUBLE, 2, 3);

  if (A==NULL)
    throw Py::ValueError("Array must be rank 2 or 3 of doubles");


  Image* imo = new Image;

  imo->rowsIn  = A->dimensions[0];
  imo->colsIn  = A->dimensions[1];


  size_t NUMBYTES(imo->colsIn * imo->rowsIn * imo->BPP);
  agg::int8u *buffer = new agg::int8u[NUMBYTES];
  if (buffer==NULL) //todo: also handle allocation throw
    throw Py::MemoryError("_image_module::fromarray could not allocate memory");

  if (isoutput) {
    // make the output buffer point to the input buffer

    imo->rowsOut  = imo->rowsIn;
    imo->colsOut  = imo->colsIn;

    imo->rbufOut = new agg::rendering_buffer;
    imo->bufferOut = buffer;
    imo->rbufOut->attach(imo->bufferOut, imo->colsOut, imo->rowsOut, imo->colsOut * imo->BPP);

  }
  else {
    imo->bufferIn = buffer;
    imo->rbufIn = new agg::rendering_buffer;
    imo->rbufIn->attach(buffer, imo->colsIn, imo->rowsIn, imo->colsIn*imo->BPP);
  }

  if   (A->nd == 2) { //assume luminance for now;

    agg::int8u gray;
    for (size_t rownum=0; rownumrowsIn; rownum++) {
     for (size_t colnum=0; colnumcolsIn; colnum++) {
       double val = *(double *)(A->data + rownum*A->strides[0] + colnum*A->strides[1]);

       gray = int(255 * val);
       *buffer++ = gray;       // red
       *buffer++ = gray;       // green
       *buffer++ = gray;       // blue
       *buffer++   = 255;        // alpha
     }
    }
  }
  else if   (A->nd == 3) { // assume RGB

    if (A->dimensions[2] != 3 && A->dimensions[2] != 4 ) {
      Py_XDECREF(A);
      throw Py::ValueError(Printf("3rd dimension must be length 3 (RGB) or 4 (RGBA); found %d", A->dimensions[2]).str());

    }

    int rgba = A->dimensions[2]==4;
    double r,g,b,alpha;
    int offset =0;

    for (size_t rownum=0; rownumrowsIn; rownum++) {
      for (size_t colnum=0; colnumcolsIn; colnum++) {
	offset = rownum*A->strides[0] + colnum*A->strides[1];
	r = *(double *)(A->data + offset);
	g = *(double *)(A->data + offset + A->strides[2] );
	b = *(double *)(A->data + offset + 2*A->strides[2] );

	if (rgba)
	  alpha = *(double *)(A->data + offset + 3*A->strides[2] );
	else
	  alpha = 1.0;

	*buffer++ = int(255*r);         // red
	*buffer++ = int(255*g);         // green
	*buffer++ = int(255*b);         // blue
	*buffer++ = int(255*alpha);     // alpha

      }
    }

  }
  else   { // error
    Py_XDECREF(A);
    throw Py::ValueError("Illegal array rank; must be rank; must 2 or 3");
  }
  buffer -= NUMBYTES;
  Py_XDECREF(A);

  return Py::asObject( imo );
}

char _image_module_fromarray2__doc__[] =
"fromarray2(A, isoutput)\n"
"\n"
"Load the image from a numpy array\n"
"By default this function fills the input buffer, which can subsequently\n"
"be resampled using resize.  If isoutput=1, fill the output buffer.\n"
"This is used to support raw pixel images w/o resampling"
;
Py::Object
_image_module::fromarray2(const Py::Tuple& args) {
  _VERBOSE("_image_module::fromarray2");

  args.verify_length(2);

  Py::Object x = args[0];
  int isoutput = Py::Int(args[1]);
  PyArrayObject *A = (PyArrayObject *) PyArray_ContiguousFromObject(x.ptr(), PyArray_DOUBLE, 2, 3);
  //PyArrayObject *A = (PyArrayObject *) PyArray_FromObject(x.ptr(), PyArray_DOUBLE, 2, 3);

  if (A==NULL)
    throw Py::ValueError("Array must be rank 2 or 3 of doubles");


  Image* imo = new Image;

  imo->rowsIn  = A->dimensions[0];
  imo->colsIn  = A->dimensions[1];


  size_t NUMBYTES(imo->colsIn * imo->rowsIn * imo->BPP);
  agg::int8u *buffer = new agg::int8u[NUMBYTES];
  if (buffer==NULL) //todo: also handle allocation throw
    throw Py::MemoryError("_image_module::fromarray could not allocate memory");

  if (isoutput) {
    // make the output buffer point to the input buffer

    imo->rowsOut  = imo->rowsIn;
    imo->colsOut  = imo->colsIn;

    imo->rbufOut = new agg::rendering_buffer;
    imo->bufferOut = buffer;
    imo->rbufOut->attach(imo->bufferOut, imo->colsOut, imo->rowsOut, imo->colsOut * imo->BPP);

  }
  else {
    imo->bufferIn = buffer;
    imo->rbufIn = new agg::rendering_buffer;
    imo->rbufIn->attach(buffer, imo->colsIn, imo->rowsIn, imo->colsIn*imo->BPP);
  }

  if   (A->nd == 2) { //assume luminance for now;

    agg::int8u gray;
    const size_t N = imo->rowsIn * imo->colsIn;
    size_t i = 0;
    while (i++data++);

      gray = int(255 * val);
      *buffer++ = gray;       // red
      *buffer++ = gray;       // green
      *buffer++ = gray;       // blue
      *buffer++   = 255;        // alpha
    }

  }
  else if   (A->nd == 3) { // assume RGB

    if (A->dimensions[2] != 3 && A->dimensions[2] != 4 ) {
      Py_XDECREF(A);
      throw Py::ValueError(Printf("3rd dimension must be length 3 (RGB) or 4 (RGBA); found %d", A->dimensions[2]).str());

    }

    int rgba = A->dimensions[2]==4;
    double r,g,b,alpha;
    const size_t N = imo->rowsIn * imo->colsIn;
    size_t i = 0;
    while (idata++);
	g = *(double *)(A->data++);
	b = *(double *)(A->data++);

	if (rgba)
	  alpha = *(double *)(A->data++);
	else
	  alpha = 1.0;

	*buffer++ = int(255*r);         // red
	*buffer++ = int(255*g);         // green
	*buffer++ = int(255*b);         // blue
	*buffer++ = int(255*alpha);     // alpha

      }

  }
  else   { // error
    Py_XDECREF(A);
    throw Py::ValueError("Illegal array rank; must be rank; must 2 or 3");
  }
  buffer -= NUMBYTES;
  Py_XDECREF(A);

  return Py::asObject( imo );
}

char _image_module_frombyte__doc__[] =
"frombyte(A, isoutput)\n"
"\n"
"Load the image from a byte array.\n"
"By default this function fills the input buffer, which can subsequently\n"
"be resampled using resize.  If isoutput=1, fill the output buffer.\n"
"This is used to support raw pixel images w/o resampling."
;
Py::Object
_image_module::frombyte(const Py::Tuple& args) {
  _VERBOSE("_image_module::frombyte");

  args.verify_length(2);

  Py::Object x = args[0];
  int isoutput = Py::Int(args[1]);

  PyArrayObject *A = (PyArrayObject *) PyArray_ContiguousFromObject(x.ptr(), PyArray_UBYTE, 3, 3);
  if (A == NULL)
      throw Py::ValueError("Array must have 3 dimensions");
  if (A->dimensions[2]dimensions[2]>4)
      throw Py::ValueError("Array dimension 3 must have size 3 or 4");

  Image* imo = new Image;

  imo->rowsIn = A->dimensions[0];
  imo->colsIn = A->dimensions[1];

  agg::int8u *arrbuf;
  agg::int8u *buffer;

  arrbuf = reinterpret_cast(A->data);

  size_t NUMBYTES(imo->colsIn * imo->rowsIn * imo->BPP);
  buffer = new agg::int8u[NUMBYTES];

  if (buffer==NULL) //todo: also handle allocation throw
      throw Py::MemoryError("_image_module::frombyte could not allocate memory");

  const size_t N = imo->rowsIn * imo->colsIn * imo->BPP;
  size_t i = 0;
  if (A->dimensions[2] == 4) {
      memmove(buffer, arrbuf, N);
  } else {
      while (i < N) {
          memmove(buffer, arrbuf, 3);
          buffer += 3;
          arrbuf += 3;
          *buffer++ = 255;
          i += 4;
      }
      buffer -= N;
      arrbuf -= imo->rowsIn * imo->colsIn;
  }
  Py_XDECREF(A);

  if (isoutput) {
    // make the output buffer point to the input buffer

    imo->rowsOut  = imo->rowsIn;
    imo->colsOut  = imo->colsIn;

    imo->rbufOut = new agg::rendering_buffer;
    imo->bufferOut = buffer;
    imo->rbufOut->attach(imo->bufferOut, imo->colsOut, imo->rowsOut, imo->colsOut * imo->BPP);

  }
  else {
    imo->bufferIn = buffer;
    imo->rbufIn = new agg::rendering_buffer;
    imo->rbufIn->attach(buffer, imo->colsIn, imo->rowsIn, imo->colsIn*imo->BPP);
  }

  return Py::asObject( imo );
}

char _image_module_frombuffer__doc__[] =
"frombuffer(buffer, width, height, isoutput)\n"
"\n"
"Load the image from a character buffer\n"
"By default this function fills the input buffer, which can subsequently\n"
"be resampled using resize.  If isoutput=1, fill the output buffer.\n"
"This is used to support raw pixel images w/o resampling."
;
Py::Object
_image_module::frombuffer(const Py::Tuple& args) {
  _VERBOSE("_image_module::frombuffer");

  args.verify_length(4);

  PyObject *bufin = new_reference_to(args[0]);
  int x = Py::Int(args[1]);
  int y = Py::Int(args[2]);
  int isoutput = Py::Int(args[3]);

  if (PyObject_CheckReadBuffer(bufin) != 1)
    throw Py::ValueError("First argument must be a buffer.");

  Image* imo = new Image;

  imo->rowsIn = y;
  imo->colsIn = x;
  Py_ssize_t NUMBYTES(imo->colsIn * imo->rowsIn * imo->BPP);

  Py_ssize_t buflen;
  const agg::int8u *rawbuf;
  if (PyObject_AsReadBuffer(bufin, reinterpret_cast(&rawbuf), &buflen) != 0)
    throw Py::ValueError("Cannot get buffer from object.");

  // Check buffer is required size.
  if (buflen != NUMBYTES)
    throw Py::ValueError("Buffer length must be width * height * 4.");

  // Copy from input buffer to new buffer for agg.
  agg::int8u* buffer = new agg::int8u[NUMBYTES];
  if (buffer==NULL) //todo: also handle allocation throw
    throw Py::MemoryError("_image_module::frombuffer could not allocate memory");
  memmove(buffer, rawbuf, NUMBYTES);

  if (isoutput) {
    // make the output buffer point to the input buffer

    imo->rowsOut  = imo->rowsIn;
    imo->colsOut  = imo->colsIn;

    imo->rbufOut = new agg::rendering_buffer;
    imo->bufferOut = buffer;
    imo->rbufOut->attach(imo->bufferOut, imo->colsOut, imo->rowsOut, imo->colsOut * imo->BPP);

  }
  else {
    imo->bufferIn = buffer;
    imo->rbufIn = new agg::rendering_buffer;
    imo->rbufIn->attach(buffer, imo->colsIn, imo->rowsIn, imo->colsIn*imo->BPP);
  }

  return Py::asObject(imo);
}


char __image_module_pcolor__doc__[] =
"pcolor(x, y, data, rows, cols, bounds)\n"
"\n"
"Generate a psudo-color image from data on a non-univorm grid using\n"
"nearest neighbour interpolation.\n"
"bounds = (x_min, x_max, y_min, y_max)\n"
;
Py::Object
_image_module::pcolor(const Py::Tuple& args) {
  _VERBOSE("_image_module::pcolor");


  if (args.length() != 6)
      throw Py::TypeError("Incorrect number of arguments (6 expected)");

  Py::Object xp = args[0];
  Py::Object yp = args[1];
  Py::Object dp = args[2];
  unsigned int rows = Py::Int(args[3]);
  unsigned int cols = Py::Int(args[4]);
  Py::Tuple bounds = args[5];

  if (bounds.length() !=4)
      throw Py::TypeError("Incorrect number of bounds (4 expected)");
  float x_min = Py::Float(bounds[0]);
  float x_max = Py::Float(bounds[1]);
  float y_min = Py::Float(bounds[2]);
  float y_max = Py::Float(bounds[3]);
  float width = x_max - x_min;
  float height = y_max - y_min;
  float dx = width / ((float) cols);
  float dy = height / ((float) rows);

  // Check we have something to output to
  if (rows == 0 || cols ==0)
      throw Py::ValueError("Cannot scale to zero size");

  // Get numpy arrays
  PyArrayObject *x = (PyArrayObject *) PyArray_ContiguousFromObject(xp.ptr(), PyArray_FLOAT, 1, 1);
  if (x == NULL)
      throw Py::ValueError("x is of incorrect type (wanted 1D float)");
  PyArrayObject *y = (PyArrayObject *) PyArray_ContiguousFromObject(yp.ptr(), PyArray_FLOAT, 1, 1);
  if (y == NULL) {
      Py_XDECREF(x);
      throw Py::ValueError("y is of incorrect type (wanted 1D float)");
  }
  PyArrayObject *d = (PyArrayObject *) PyArray_ContiguousFromObject(dp.ptr(), PyArray_UBYTE, 3, 3);
  if (d == NULL) {
      Py_XDECREF(x);
      Py_XDECREF(y);
      throw Py::ValueError("data is of incorrect type (wanted 3D UInt8)");
  }
  if (d->dimensions[2] != 4) {
      Py_XDECREF(x);
      Py_XDECREF(y);
      Py_XDECREF(d);
      throw Py::ValueError("data must be in RGBA format");
  }

  // Check dimensions match
  int nx = x->dimensions[0];
  int ny = y->dimensions[0];
  if (nx != d->dimensions[1] || ny != d->dimensions[0]) {
      Py_XDECREF(x);
      Py_XDECREF(y);
      Py_XDECREF(d);
      throw Py::ValueError("data and axis dimensions do not match");
  }

  // Allocate memory for pointer arrays
  unsigned int * rowstarts = reinterpret_cast(PyMem_Malloc(sizeof(unsigned int)*rows));
  if (rowstarts == NULL) {
      Py_XDECREF(x);
      Py_XDECREF(y);
      Py_XDECREF(d);
      throw Py::MemoryError("Cannot allocate memory for lookup table");
  }
  unsigned int * colstarts = reinterpret_cast(PyMem_Malloc(sizeof(unsigned int*)*cols));
  if (colstarts == NULL) {
      Py_XDECREF(x);
      Py_XDECREF(y);
      Py_XDECREF(d);
      PyMem_Free(rowstarts);
      throw Py::MemoryError("Cannot allocate memory for lookup table");
  }

  // Create output
  Image* imo = new Image;
  imo->rowsIn = rows;
  imo->colsIn = cols;
  imo->rowsOut = rows;
  imo->colsOut = cols;
  size_t NUMBYTES(rows * cols * 4);
  agg::int8u *buffer = new agg::int8u[NUMBYTES];
  if (buffer == NULL) {
      Py_XDECREF(x);
      Py_XDECREF(y);
      Py_XDECREF(d);
      PyMem_Free(rowstarts);
      PyMem_Free(colstarts);
      throw Py::MemoryError("Could not allocate memory for image");
  }

  // Calculate the pointer arrays to map input x to output x
  unsigned int i, j, j_last;
  unsigned int * colstart = colstarts;
  unsigned int * rowstart = rowstarts;
  float *xs1 = reinterpret_cast(x->data);
  float *ys1 = reinterpret_cast(y->data);
  float *xs2 = xs1+1;
  float *ys2 = ys1+1;
  float *xl = xs1 + nx - 1;
  float *yl = ys1 + ny - 1;
  float xo = x_min + dx/2.0;
  float yo = y_min + dy/2.0;
  float xm = 0.5*(*xs1 + *xs2);
  float ym = 0.5*(*ys1 + *ys2);
  // x/cols
  j = 0;
  j_last = j;
  for (i=0;i xm) {
          xs1 = xs2;
          xs2 = xs1+1;
          xm = 0.5*(*xs1 + *xs2);
          j++;
      }
      *colstart = j - j_last;
      j_last = j;
  }
  // y/rows
  j = 0;
  j_last = j;
  for (i=0;i ym) {
          ys1 = ys2;
          ys2 = ys1+1;
          ym = 0.5*(*ys1 + *ys2);
          j++;
      }
      *rowstart = j - j_last;
      j_last = j;
  }


  // Copy data to output buffer
  unsigned char *start;
  unsigned char *inposition;
  size_t inrowsize(nx*4);
  size_t rowsize(cols*4);
  rowstart = rowstarts;
  agg::int8u * position = buffer;
  agg::int8u * oldposition = NULL;
  start = reinterpret_cast(d->data);
  for(i=0;i 0 && *rowstart == 0) {
          memcpy(position, oldposition, rowsize*sizeof(agg::int8u));
          oldposition = position;
          position += rowsize;
      } else {
          oldposition = position;
          start += *rowstart * inrowsize;
          inposition = start;
          for(j=0,colstart=colstarts;jrbufOut = new agg::rendering_buffer;
  imo->bufferOut = buffer;
  imo->rbufOut->attach(imo->bufferOut, imo->colsOut, imo->rowsOut, imo->colsOut * imo->BPP);

  Py_XDECREF(x);
  Py_XDECREF(y);
  Py_XDECREF(d);
  PyMem_Free(rowstarts);
  PyMem_Free(colstarts);

  return Py::asObject(imo);
}

void _bin_indices(int *irows, int nrows, double *y, int ny,
                                            double sc, double offs)
{
    int i;
    if (sc*(y[ny-1] - y[0]) > 0)
    {
        int ii = 0;
        int iilast = ny-1;
        int iy0 = (int)floor(sc * (y[ii]  - offs));
        int iy1 = (int)floor(sc * (y[ii+1]  - offs));
        for (i=0; idimensions[0]+1) {
        Py_XDECREF(x);
        Py_XDECREF(y);
        Py_XDECREF(d);
        throw Py::ValueError("data and axis bin boundary dimensions are incompatible");
    }

    PyArrayObject *bg = (PyArrayObject *) PyArray_ContiguousFromObject(bgp.ptr(),
                                                          PyArray_UBYTE, 1, 1);
    if (bg == NULL) {
        Py_XDECREF(x);
        Py_XDECREF(y);
        Py_XDECREF(d);
        throw Py::ValueError("bg is of incorrect type (wanted 1D uint8)");
    }
    if (bg->dimensions[0] != 4) {
        Py_XDECREF(x);
        Py_XDECREF(y);
        Py_XDECREF(d);
        Py_XDECREF(bg);
        throw Py::ValueError("bg must be in RGBA format");
    }


    // Allocate memory for pointer arrays
    int * irows = reinterpret_cast(PyMem_Malloc(sizeof(int)*rows));
    if (irows == NULL) {
        Py_XDECREF(x);
        Py_XDECREF(y);
        Py_XDECREF(d);
        Py_XDECREF(bg);
        throw Py::MemoryError("Cannot allocate memory for lookup table");
    }
    int * jcols = reinterpret_cast(PyMem_Malloc(sizeof(int*)*cols));
    if (jcols == NULL) {
        Py_XDECREF(x);
        Py_XDECREF(y);
        Py_XDECREF(d);
        Py_XDECREF(bg);
        PyMem_Free(irows);
        throw Py::MemoryError("Cannot allocate memory for lookup table");
    }

    // Create output
    Image* imo = new Image;
    imo->rowsIn = rows;
    imo->rowsOut = rows;
    imo->colsIn = cols;
    imo->colsOut = cols;
    size_t NUMBYTES(rows * cols * 4);
    agg::int8u *buffer = new agg::int8u[NUMBYTES];
    if (buffer == NULL) {
        Py_XDECREF(x);
        Py_XDECREF(y);
        Py_XDECREF(d);
        Py_XDECREF(bg);
        PyMem_Free(irows);
        PyMem_Free(jcols);
        throw Py::MemoryError("Could not allocate memory for image");
    }

    // Calculate the pointer arrays to map input x to output x
    int i, j;
    double *x0 = reinterpret_cast(x->data);
    double *y0 = reinterpret_cast(y->data);
    double sx = cols/(x_right - x_left);
    double sy = rows/(y_top - y_bot);
    _bin_indices(jcols, cols, x0, nx, sx, x_left);
    _bin_indices(irows, rows, y0, ny, sy, y_bot);

    // Copy data to output buffer
    agg::int8u * position = buffer;
    unsigned char *start = reinterpret_cast(d->data);
    unsigned char *bgptr = reinterpret_cast(bg->data);
    int s0 = d->strides[0];
    int s1 = d->strides[1];

    for (i=0; ibufferOut = buffer;
    imo->rbufOut->attach(imo->bufferOut, imo->colsOut, imo->rowsOut, imo->colsOut * imo->BPP);

    Py_XDECREF(x);
    Py_XDECREF(y);
    Py_XDECREF(d);
    Py_XDECREF(bg);
    PyMem_Free(irows);
    PyMem_Free(jcols);

    return Py::asObject(imo);
}


#if defined(_MSC_VER)
DL_EXPORT(void)
#elif defined(__cplusplus)
  extern "C" void
#else
void
#endif

init_image(void) {
  _VERBOSE("init_image");

  static _image_module* _image = new _image_module;

  import_array();
  Py::Dict d = _image->moduleDictionary();

  d["NEAREST"] = Py::Int(Image::NEAREST);
  d["BILINEAR"] = Py::Int(Image::BILINEAR);
  d["BICUBIC"] = Py::Int(Image::BICUBIC);
  d["SPLINE16"] = Py::Int(Image::SPLINE16);
  d["SPLINE36"] = Py::Int(Image::SPLINE36);
  d["HANNING"] = Py::Int(Image::HANNING);
  d["HAMMING"] = Py::Int(Image::HAMMING);
  d["HERMITE"] = Py::Int(Image::HERMITE);
  d["KAISER"]   = Py::Int(Image::KAISER);
  d["QUADRIC"]   = Py::Int(Image::QUADRIC);
  d["CATROM"]  = Py::Int(Image::CATROM);
  d["GAUSSIAN"]  = Py::Int(Image::GAUSSIAN);
  d["BESSEL"]  = Py::Int(Image::BESSEL);
  d["MITCHELL"]  = Py::Int(Image::MITCHELL);
  d["SINC"]  = Py::Int(Image::SINC);
  d["LANCZOS"]  = Py::Int(Image::LANCZOS);
  d["BLACKMAN"] = Py::Int(Image::BLACKMAN);

  d["ASPECT_FREE"] = Py::Int(Image::ASPECT_FREE);
  d["ASPECT_PRESERVE"] = Py::Int(Image::ASPECT_PRESERVE);


}



Web Proxy Viewer  |  New URL  |  Original Page