Example #1
0
static int HALF_setitem(PyObject *op, char *ov, PyArrayObject *ap)
{
    npy_half temp; /* ensures alignment */

    if (PyArray_IsScalar(op, Half)) {
        temp = ((PyHalfScalarObject *)op)->obval;
    }
    else {
        temp = MyPyFloat_AsHalf(op);
    }
    if (PyErr_Occurred()) {
        if (PySequence_Check(op)) {
            PyErr_Clear();
            PyErr_SetString(PyExc_ValueError,
                    "setting an array element with a sequence.");
        }
        return -1;
    }
    if (ap == NULL || PyArray_ISBEHAVED(ap))
        *((npy_half *)ov)=temp;
    else {
        ap->descr->f->copyswap(ov, &temp, !PyArray_ISNOTSWAPPED(ap), ap);
    }
    return 0;

}
Example #2
0
static int QUATERNION_setitem(PyObject *op, char *ov, PyArrayObject *ap)
{
    quaternion q;

    if (PyArray_IsScalar(op, Quaternion)) {
        q = ((PyQuaternionScalarObject *)op)->obval;
    }
    else {
        q.w = PyFloat_AsDouble(PyTuple_GetItem(op, 0));
        q.x = PyFloat_AsDouble(PyTuple_GetItem(op, 1));
        q.y = PyFloat_AsDouble(PyTuple_GetItem(op, 2));
        q.z = PyFloat_AsDouble(PyTuple_GetItem(op, 3));
    }
    if (PyErr_Occurred()) {
        if (PySequence_Check(op)) {
            PyErr_Clear();
            PyErr_SetString(PyExc_ValueError,
                    "setting an array element with a sequence.");
        }
        return -1;
    }
    if (ap == NULL || PyArray_ISBEHAVED(ap))
        *((quaternion *)ov)=q;
    else {
        PyArray_Descr *descr;
        descr = PyArray_DescrFromType(NPY_DOUBLE);
        descr->f->copyswap(ov, &q.w, !PyArray_ISNOTSWAPPED(ap), NULL);
        descr->f->copyswap(ov+8, &q.x, !PyArray_ISNOTSWAPPED(ap), NULL);
        descr->f->copyswap(ov+16, &q.y, !PyArray_ISNOTSWAPPED(ap), NULL);
        descr->f->copyswap(ov+24, &q.z, !PyArray_ISNOTSWAPPED(ap), NULL);
        Py_DECREF(descr);
    }

    return 0;
}
Example #3
0
PyObject *
load_png_fast_progressive (char *filename,
                           PyObject *get_buffer_callback)
{
  // Note: we are not using the method that libpng calls "Reading PNG
  // files progressively". That method would involve feeding the data
  // into libpng piece by piece, which is not necessary if we can give
  // libpng a simple FILE pointer.

  png_structp png_ptr = NULL;
  png_infop info_ptr = NULL;
  PyObject * result = NULL;
  FILE *fp = NULL;
  uint32_t width, height;
  uint32_t rows_left;
  png_byte color_type;
  png_byte bit_depth;
  bool have_alpha;
  char *cm_processing = NULL;

  // ICC profile-based colour conversion data.
  png_charp icc_profile_name = NULL;
  int icc_compression_type = 0;
#if PNG_LIBPNG_VER < 10500    // 1.5.0beta36, according to libpng CHANGES
  png_charp icc_profile = NULL;
#else
  png_bytep icc_profile = NULL;
#endif
  png_uint_32 icc_proflen = 0;

  // The sRGB flag has an intent field, which we ignore - 
  // the target gamut is sRGB already.
  int srgb_intent = 0;

  // Generic RGB space conversion params.
  // The assumptions we're making are those of sRGB,
  // but they'll be overridden by gammas or primaries in the file if used.
  bool generic_rgb_have_gAMA = false;
  bool generic_rgb_have_cHRM = false;
  double generic_rgb_file_gamma = 45455 / PNG_gAMA_scale;
  double generic_rgb_white_x = 31270 / PNG_cHRM_scale;
  double generic_rgb_white_y = 32900 / PNG_cHRM_scale;
  double generic_rgb_red_x   = 64000 / PNG_cHRM_scale;
  double generic_rgb_red_y   = 33000 / PNG_cHRM_scale;
  double generic_rgb_green_x = 30000 / PNG_cHRM_scale;
  double generic_rgb_green_y = 60000 / PNG_cHRM_scale;
  double generic_rgb_blue_x  = 15000 / PNG_cHRM_scale;
  double generic_rgb_blue_y  =  6000 / PNG_cHRM_scale;

  // Indicates the case where no CM information was present in the file and we
  // treated it as sRGB.
  bool possible_legacy_png = false;

  // LCMS stuff
  cmsHPROFILE input_buffer_profile = NULL;
  cmsHPROFILE nparray_data_profile = cmsCreate_sRGBProfile();
  cmsHTRANSFORM input_buffer_to_nparray = NULL;
  cmsToneCurve *gamma_transfer_func = NULL;
  cmsUInt32Number input_buffer_format = 0;

  cmsSetLogErrorHandler(log_lcms2_error);

  fp = fopen(filename, "rb");
  if (!fp) {
    PyErr_SetFromErrno(PyExc_IOError);
    //PyErr_Format(PyExc_IOError, "Could not open PNG file for writing: %s",
    //             filename);
    goto cleanup;
  }

  png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
                                    png_read_error_callback, NULL);
  if (!png_ptr) {
    PyErr_SetString(PyExc_MemoryError, "png_create_write_struct() failed");
    goto cleanup;
  }

  info_ptr = png_create_info_struct(png_ptr);
  if (!info_ptr) {
    PyErr_SetString(PyExc_MemoryError, "png_create_info_struct() failed");
    goto cleanup;
  }

  if (setjmp(png_jmpbuf(png_ptr))) {
    goto cleanup;
  }

  png_init_io(png_ptr, fp);

  png_read_info(png_ptr, info_ptr);

  // If there's an embedded ICC profile, use it in preference to any other
  // colour management information present.
  if (png_get_iCCP (png_ptr, info_ptr, &icc_profile_name,
                    &icc_compression_type, &icc_profile,
                    &icc_proflen))
  {
    input_buffer_profile = cmsOpenProfileFromMem(icc_profile, icc_proflen);
    if (! input_buffer_profile) {
      PyErr_SetString(PyExc_MemoryError, "cmsOpenProfileFromMem() failed");
      goto cleanup;
    }
    cm_processing = "iCCP (use embedded colour profile)";
  }

  // Shorthand for sRGB.
  else if (png_get_sRGB (png_ptr, info_ptr, &srgb_intent)) {
    input_buffer_profile = cmsCreate_sRGBProfile();
    cm_processing = "sRGB (explicit sRGB chunk)";
  }

  else {
    // We might have generic RGB transformation information in the form of
    // the chromaticities for R, G and B and a generic gamma curve.

    if (png_get_cHRM (png_ptr, info_ptr,
                      &generic_rgb_white_x, &generic_rgb_white_y,
                      &generic_rgb_red_x, &generic_rgb_red_y,
                      &generic_rgb_green_x, &generic_rgb_green_y,
                      &generic_rgb_blue_x, &generic_rgb_blue_y))
    {
      generic_rgb_have_cHRM = true;
    }
    if (png_get_gAMA(png_ptr, info_ptr, &generic_rgb_file_gamma)) {
      generic_rgb_have_gAMA = true;
    }
    if (generic_rgb_have_gAMA || generic_rgb_have_cHRM) {
      cmsCIExyYTRIPLE primaries = {{generic_rgb_red_x, generic_rgb_red_y},
                                   {generic_rgb_green_x, generic_rgb_green_y},
                                   {generic_rgb_blue_x, generic_rgb_blue_y}};
      cmsCIExyY white_point = {generic_rgb_white_x, generic_rgb_white_y};
      gamma_transfer_func = cmsBuildGamma(NULL, 1.0/generic_rgb_file_gamma);
      cmsToneCurve *transfer_funcs[3] = {gamma_transfer_func,
                                         gamma_transfer_func,
                                         gamma_transfer_func };
      input_buffer_profile = cmsCreateRGBProfile(&white_point, &primaries,
                                                transfer_funcs);
      cm_processing = "cHRM and/or gAMA (generic RGB space)";
    }

    // Possible legacy PNG, or rather one which might have been written with an
    // old version of MyPaint. Treat as sRGB, but flag the strangeness because
    // it might be important for PNGs in old OpenRaster files.
    else {
      possible_legacy_png = true;
      input_buffer_profile = cmsCreate_sRGBProfile();
      cm_processing = "sRGB (no CM chunks present)";
    }
  }

  if (png_get_interlace_type (png_ptr, info_ptr) != PNG_INTERLACE_NONE) {
    PyErr_SetString(PyExc_RuntimeError,
                    "Interlaced PNG files are not supported!");
    goto cleanup;
  }

  color_type = png_get_color_type(png_ptr, info_ptr);
  bit_depth = png_get_bit_depth(png_ptr, info_ptr);
  have_alpha = color_type & PNG_COLOR_MASK_ALPHA;

  if (color_type == PNG_COLOR_TYPE_PALETTE) {
    png_set_palette_to_rgb(png_ptr);
  }

  if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
    png_set_expand_gray_1_2_4_to_8(png_ptr);
  }

  if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
    png_set_tRNS_to_alpha(png_ptr);
    have_alpha = true;
  }

  if (bit_depth < 8) {
    png_set_packing(png_ptr);
  }

  if (!have_alpha) {
    png_set_add_alpha(png_ptr, 0xFF, PNG_FILLER_AFTER);
  }

  if (color_type == PNG_COLOR_TYPE_GRAY ||
      color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
    png_set_gray_to_rgb(png_ptr);
  }

  png_read_update_info(png_ptr, info_ptr);

  // Verify what we have done
  bit_depth = png_get_bit_depth(png_ptr, info_ptr);
  if (! (bit_depth == 8 || bit_depth == 16)) {
    PyErr_SetString(PyExc_RuntimeError, "Failed to convince libpng to convert "
                                        "to 8 or 16 bits per channel");
    goto cleanup;
  }
  if (png_get_color_type(png_ptr, info_ptr) != PNG_COLOR_TYPE_RGB_ALPHA) {
    PyErr_SetString(PyExc_RuntimeError, "Failed to convince libpng to convert "
                                        "to RGBA (wrong color_type)");
    goto cleanup;
  }
  if (png_get_channels(png_ptr, info_ptr) != 4) {
    PyErr_SetString(PyExc_RuntimeError, "Failed to convince libpng to convert "
                                        "to RGBA (wrong number of channels)");
    goto cleanup;
  }

  // PNGs use network byte order, i.e. big-endian in descending order
  // of bit significance. LittleCMS uses whatever's detected for the compiler.
  // ref: http://www.w3.org/TR/2003/REC-PNG-20031110/#7Integers-and-byte-order
  if (bit_depth == 16) {
#ifdef CMS_USE_BIG_ENDIAN
    input_buffer_format = TYPE_RGBA_16;
#else
    input_buffer_format = TYPE_RGBA_16_SE;
#endif
  }
  else {
    input_buffer_format = TYPE_RGBA_8;
  }

  input_buffer_to_nparray = cmsCreateTransform
        (input_buffer_profile, input_buffer_format,
         nparray_data_profile, TYPE_RGBA_8,
         INTENT_PERCEPTUAL, 0);

  width = png_get_image_width(png_ptr, info_ptr);
  height = png_get_image_height(png_ptr, info_ptr);
  rows_left = height;

  while (rows_left) {
    PyObject *pyarr = NULL;
    uint32_t rows = 0;
    uint32_t row = 0;
    const uint8_t input_buf_bytes_per_pixel = (bit_depth==8) ? 4 : 8;
    const uint32_t input_buf_row_stride = sizeof(png_byte) * width
                                          * input_buf_bytes_per_pixel;
    png_byte *input_buffer = NULL;
    png_bytep *input_buf_row_pointers = NULL;

    pyarr = PyObject_CallFunction(get_buffer_callback, "ii", width, height);
    if (! pyarr) {
      PyErr_Format(PyExc_RuntimeError, "Get-buffer callback failed");
      goto cleanup;
    }
#ifdef HEAVY_DEBUG
    //assert(PyArray_ISCARRAY(arr));
    assert(PyArray_NDIM(pyarr) == 3);
    assert(PyArray_DIM(pyarr, 1) == width);
    assert(PyArray_DIM(pyarr, 2) == 4);
    assert(PyArray_TYPE(pyarr) == NPY_UINT8);
    assert(PyArray_ISBEHAVED(pyarr));
    assert(PyArray_STRIDE(pyarr, 1) == 4*sizeof(uint8_t));
    assert(PyArray_STRIDE(pyarr, 2) ==   sizeof(uint8_t));
#endif
    rows = PyArray_DIM(pyarr, 0);

    if (rows > rows_left) {
      PyErr_Format(PyExc_RuntimeError,
                   "Attempt to read %d rows from the PNG, "
                   "but only %d are left",
                   rows, rows_left);
      goto cleanup;
    }

    input_buffer = (png_byte *) malloc(rows * input_buf_row_stride);
    input_buf_row_pointers = (png_bytep *)malloc(rows * sizeof(png_bytep));
    for (row=0; row<rows; row++) {
      input_buf_row_pointers[row] = input_buffer + (row * input_buf_row_stride);
    }

    png_read_rows(png_ptr, input_buf_row_pointers, NULL, rows);
    rows_left -= rows;

    for (row=0; row<rows; row++) {
      uint8_t *pyarr_row = (uint8_t *)PyArray_DATA(pyarr)
                         + row*PyArray_STRIDE(pyarr, 0);
      uint8_t *input_row = input_buf_row_pointers[row];
      // Really minimal fake colour management. Just remaps to sRGB.
      cmsDoTransform(input_buffer_to_nparray, input_row, pyarr_row, width);
      // lcms2 ignores alpha, so copy that verbatim
      // If it's 8bpc RGBA, use A.
      // If it's 16bpc RrGgBbAa, use A.
      for (uint32_t i=0; i<width; ++i) {
        const uint32_t pyarr_alpha_byte = (i*4) + 3;
        const uint32_t buf_alpha_byte = (i*input_buf_bytes_per_pixel)
                                       + ((bit_depth==8) ? 3 : 6);
        pyarr_row[pyarr_alpha_byte] = input_row[buf_alpha_byte];
      }
    }

    free(input_buf_row_pointers);
    free(input_buffer);

    Py_DECREF(pyarr);
  }

  png_read_end(png_ptr, NULL);

  result = Py_BuildValue("{s:b,s:i,s:i,s:s}",
                         "possible_legacy_png", possible_legacy_png,
                         "width", width,
                         "height", height,
                         "cm_conversions_applied", cm_processing);

 cleanup:
  if (info_ptr) png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
  // libpng's style is to free internally allocated stuff like the icc
  // tables in png_destroy_*(). I think.
  if (fp) fclose(fp);
  if (input_buffer_profile) cmsCloseProfile(input_buffer_profile);
  if (nparray_data_profile) cmsCloseProfile(nparray_data_profile);
  if (input_buffer_to_nparray) cmsDeleteTransform(input_buffer_to_nparray);
  if (gamma_transfer_func) cmsFreeToneCurve(gamma_transfer_func);

  return result;
}
Example #4
0
File: cKeo.c Project: paalge/paskil
static PyObject * cKeo_linear_interpolate(PyObject *self, PyObject *args){
    
    PyObject *keo_arr, *data_list;
    int strip_width,max_gap;
    npy_intp keo_arr_dims[2], data_list_dims[1]; 
    int keo_arr_num_dim, data_list_num_dim;
    long int x,y,k;
    int start_pix, end_pix, offset;
    double gradient;
     
    //parse the arguments passed to the function by Python - no increase in ref count
    if(!PyArg_ParseTuple(args, "OOii", &keo_arr, &data_list, &strip_width, &max_gap)){ //no increase to the object's reference count
        PyErr_SetString(PyExc_ValueError,"Invalid parameters");
        return NULL;
    }

    //check that we have been passed array objects
    if (!PyArray_Check(keo_arr)){
    	PyErr_SetString(PyExc_TypeError,"Invalid type for keo_arr argument. Expecting Numpy array.");
    	return NULL;
    }
    if (!PyArray_Check(data_list)){
        	PyErr_SetString(PyExc_TypeError,"Invalid type for data_list argument. Expecting Numpy array.");
        	return NULL;
    }

    //check that keo_arr is two dimensional
    keo_arr_num_dim = PyArray_NDIM(keo_arr);
    if (keo_arr_num_dim != 2){
        PyErr_SetString(PyExc_ValueError,"Keogram array must be two dimensional");
        return NULL;
    }
    
    //check that data_list is 1D
    data_list_num_dim = PyArray_NDIM(data_list);
    if (data_list_num_dim != 1){
        PyErr_SetString(PyExc_ValueError,"Data list array must be one dimensional");
        return NULL;
    }
    
    //check that both are well behaved
    if (! PyArray_ISBEHAVED(keo_arr)){
        PyErr_SetString(PyExc_ValueError,"Keogram array must be well behaved");
        return NULL;
    }   
    if (! PyArray_ISBEHAVED(data_list)){
        PyErr_SetString(PyExc_ValueError,"Data list array must be well behaved");
        return NULL;
    }
    
    //get the dimensions of the keogram and data_list
    keo_arr_dims[0] = PyArray_DIM(keo_arr, 0);
    keo_arr_dims[1] = PyArray_DIM(keo_arr, 1);
    data_list_dims[0] = PyArray_DIM(data_list, 0);

    //do the interpolation
    for(k=0;k<data_list_dims[0]-1;k++){
        start_pix = *((int*)PyArray_GETPTR1(data_list,(int)k))+(strip_width/2);
        end_pix = *((int*)PyArray_GETPTR1(data_list,((int)k)+1))-(strip_width/2);
        
        //check that any interpolation is actually needed
        if (start_pix == end_pix){
            continue;
        }
        
        //check for missing data entries
        if (end_pix-start_pix > max_gap){
            continue; //don't interpolate over large gaps in the data.
        }
        
        for (y=0;y<keo_arr_dims[1];y++){
                offset = keo_arr_dims[1]*y;
                //gradient = (keo_data[(end_pix*y_stride)+(y*x_stride)] - keo_data[(start_pix*y_stride)+(y*x_stride)])/(double)(end_pix-start_pix);
                gradient = (*((int*)PyArray_GETPTR2(keo_arr,end_pix,y))-*((int*)PyArray_GETPTR2(keo_arr,start_pix,y)))/(double)(end_pix-start_pix);
                for(x=start_pix+1;x<end_pix;x++){ 
                    //keo_data[(x*y_stride)+(y*x_stride)] = keo_data[(start_pix*y_stride)+(y*x_stride)] + (x-start_pix)*gradient;
                    *((int*)PyArray_GETPTR2(keo_arr,x,y)) = *((int*)PyArray_GETPTR2(keo_arr,start_pix,y))+ (x-start_pix)*gradient;
                }
        }           
    }
    
    Py_RETURN_NONE;   
}
Example #5
0
File: cKeo.c Project: paalge/paskil
static PyObject * cKeo_ct_lin_interp(PyObject *self, PyObject *args){
    
    PyObject *keo_arr, *data_list,*colour_table;
    int strip_width,max_gap;
    npy_intp keo_arr_dims[2], data_list_dims[1],ct_dims[1]; 
    int keo_arr_num_dim, data_list_num_dim, ct_num_dim;
    long int x,y,k;
    int start_pix, end_pix, index_in_colour_table;
    int start_colour, end_colour;
    double gradient;
     
    //parse the arguments passed to the function by Python
    if(!PyArg_ParseTuple(args, "OOOii", &keo_arr, &data_list,&colour_table, &strip_width, &max_gap)){ //no increase to the object's reference count
        PyErr_SetString(PyExc_ValueError,"Invalid parameters");
        return NULL;
    }

    //check that we have been passed array objects
    if (!PyArray_Check(keo_arr)){
      	PyErr_SetString(PyExc_TypeError,"Invalid type for keo_arr argument. Expecting Numpy array.");
      	return NULL;
    }
    if (!PyArray_Check(data_list)){
        PyErr_SetString(PyExc_TypeError,"Invalid type for data_list argument. Expecting Numpy array.");
        return NULL;
    }
    if (!PyArray_Check(colour_table)){
        PyErr_SetString(PyExc_TypeError,"Invalid type for colour_table argument. Expecting Numpy array.");
        return NULL;
    }

    //check that keo_arr is two dimensional
    keo_arr_num_dim = PyArray_NDIM(keo_arr);
    if (keo_arr_num_dim != 2){
        PyErr_SetString(PyExc_ValueError,"Keogram array must be two dimensional");
        return NULL;
    }
    
    //check that data_list is 1D
    data_list_num_dim = PyArray_NDIM(data_list);
    if (data_list_num_dim != 1){
        PyErr_SetString(PyExc_ValueError,"Data list array must be one dimensional");
        return NULL;
    }
    
    //check the colour_table is 1D
    ct_num_dim = PyArray_NDIM(colour_table);
    if (ct_num_dim != 1){
        PyErr_SetString(PyExc_ValueError,"Colour table array must be one dimensional");
        return NULL;
    }
    
    //check that all are well behaved
    if (! PyArray_ISBEHAVED(keo_arr)){
        PyErr_SetString(PyExc_ValueError,"Keogram array must be well behaved");
        return NULL;
    }   
    if (! PyArray_ISBEHAVED(data_list)){
        PyErr_SetString(PyExc_ValueError,"Data list array must be well behaved");
        return NULL;
    }
    if (! PyArray_ISBEHAVED(colour_table)){
        PyErr_SetString(PyExc_ValueError,"Colour table array must be well behaved");
        return NULL;
    }
    
    //get the dimensions of the keogram, data_list and colour table
    keo_arr_dims[0] = PyArray_DIM(keo_arr, 0);
    keo_arr_dims[1] = PyArray_DIM(keo_arr, 1);
    data_list_dims[0] = PyArray_DIM(data_list, 0);
    ct_dims[0] = PyArray_DIM(colour_table, 0);
    
/*    //check stride of data list array is what we are expecting
    if (((int)PyArray_STRIDE(data_list, 0) != (int)sizeof(int))){
        PyErr_SetString(PyExc_ValueError,"Incorrect stride for data list array");
        return NULL;
    }
    
    //get pointers to array data
    keo_data = (int*)PyArray_DATA(keo_arr);
    data_points = (int*)PyArray_DATA(data_list);
    ct_data = (int*)PyArray_DATA(colour_table);
 */
    //do the interpolation
    for(k=0;k<data_list_dims[0]-1;k++){
        start_pix = *((int*)PyArray_GETPTR1(data_list,(int)k))+(strip_width/2);
        end_pix = *((int*)PyArray_GETPTR1(data_list,((int)k)+1))-(strip_width/2);

 //   	start_pix = data_points[(int)k]+(strip_width/2);
 //       end_pix = data_points[((int)k)+1]-(strip_width/2);
        
        //check that any interpolation is actually needed
        if (start_pix == end_pix){
            continue;
        }
        
        //check for missing data entries
        if (end_pix-start_pix > max_gap){
            continue; //don't interpolate over large gaps in the data.
        }
        
        for (y=0;y<keo_arr_dims[1];y++){
            start_colour = findIndex(colour_table,*((int*)PyArray_GETPTR2(keo_arr,start_pix,y)),ct_dims[0]);
            end_colour = findIndex(colour_table,*((int*)PyArray_GETPTR2(keo_arr,end_pix,y)),ct_dims[0]);
            gradient = (end_colour - start_colour)/(end_pix - start_pix);

            for(x=start_pix+1;x<end_pix;x++){
                index_in_colour_table = (int)(start_colour + ((x-start_pix)*gradient)+0.5);
                *((int*)PyArray_GETPTR2(keo_arr,x,y)) = *((int*)PyArray_GETPTR1(colour_table,index_in_colour_table));
            }   
        }
    }
    
    Py_RETURN_NONE;   
}