コード例 #1
0
ファイル: png_encoding.c プロジェクト: applitools/oily_png
VALUE oily_png_encode_png_image_pass_to_stream(VALUE self, VALUE stream, VALUE color_mode, VALUE bit_depth, VALUE filtering) {
  
  UNUSED_PARAMETER(bit_depth);
  
  // Get the data
  char depth      = (char) FIX2INT(bit_depth);
  long width      = FIX2LONG(rb_funcall(self, rb_intern("width"), 0));
  long height     = FIX2LONG(rb_funcall(self, rb_intern("height"), 0));
  VALUE pixels    = rb_funcall(self, rb_intern("pixels"), 0);
  
  if (RARRAY_LEN(pixels) != width * height) {
    rb_raise(rb_eRuntimeError, "The number of pixels does not match the canvas dimensions.");
  }

  // Get the encoding palette if we're encoding to an indexed bytestream.
  VALUE encoding_palette = Qnil;
  if (FIX2INT(color_mode) == OILY_PNG_COLOR_INDEXED) {
    encoding_palette = oily_png_encode_palette(self);
  }
  
  char pixel_size = oily_png_pixel_bytesize(FIX2INT(color_mode), depth);
  long line_size  = oily_png_scanline_bytesize(FIX2INT(color_mode), depth, width);
  long pass_size  = oily_png_pass_bytesize(FIX2INT(color_mode), depth, width, height);

  // Allocate memory for the byte array.
  BYTE* bytes = ALLOC_N(BYTE, pass_size);
  
  // Get the scanline encoder function.
  scanline_encoder_func scanline_encoder = oily_png_encode_scanline_func(FIX2INT(color_mode), depth);
  if (scanline_encoder == NULL) {
    rb_raise(rb_eRuntimeError, "No encoder for color mode %d and bit depth %d", FIX2INT(color_mode), depth);
  }

  long y, pos;
  for (y = height - 1; y >= 0; y--) {
    pos = line_size * y;
    bytes[pos] = (BYTE) FIX2INT(filtering);
    scanline_encoder(bytes + pos + 1, pixels, y, width, encoding_palette);
  }
  
  if (FIX2INT(filtering) != OILY_PNG_FILTER_NONE) {

    // Get the scanline filter function
    void (*scanline_filter)(BYTE*, long, long, char) = NULL;
    switch (FIX2INT(filtering)) {
      case OILY_PNG_FILTER_SUB:     scanline_filter = &oily_png_encode_filter_sub; break;
      case OILY_PNG_FILTER_UP:      scanline_filter = &oily_png_encode_filter_up; break;
      case OILY_PNG_FILTER_AVERAGE: scanline_filter = &oily_png_encode_filter_average; break;
      case OILY_PNG_FILTER_PAETH:   scanline_filter = &oily_png_encode_filter_paeth; break;
      default: rb_raise(rb_eRuntimeError, "Unsupported filter type: %d", FIX2INT(filtering));
    }

    for (y = height - 1; y >= 0; y--) {
      scanline_filter(bytes, line_size * y, line_size, pixel_size);
    }
  }
  
  // Append to encoded image pass to the output stream.
  rb_str_cat(stream, (char*) bytes, pass_size);
  xfree(bytes);
  return Qnil;
}
コード例 #2
0
ファイル: zoomdown.c プロジェクト: imod-mirror/IMOD
/*!
 * Reduces an image using the interpolation filter and zoom specified in
 * @@selectZoomFilter@. ^
 * [slines] - array of line pointers for the input image ^
 * [aXsize], [aYsize] - size of input image ^
 * [aXoff], [aYoff] - coordinate in the input image at which the lower left edge of the
 * lower left pixel of the output starts, where input coordinates are zero at the lower
 * left edge of the first input pixel ^
 * [bXsize], [bYsize] - size of output image to be created, potentially from a subset of
 * the input in X or Y and into a subset of the output array ^
 * [bXdim] - X dimension of the full output image array ^
 * [bXoff] - Index of first pixel in X to fill in output array ^
 * [dtype] - Type of data, a SLICE_MODE_... value.  BYTE, FLOAT, RGB, SHORT, and USHORT
 * are allowed ^
 * [outData] - Output array, or address of first line to fill in a larger output array.
 * The array is the same data type as the input unless mapping is being done, in which
 * case it must be unsigned integers. ^
 * [cindex] - Unsigned integer RGBA values to map byte or short data into, or NULL for
 * no mapping ^
 * [bindex] - Byte values to map RGB data into, or NULL for no mapping.  Each channel is
 * mapped the same and a fourth channel is added with zero. ^
 * Returns 1 if no filter has been selected, 2 for an unsupported data type, 3 for an
 * attempt to map float data, 4 if needed input coordinates to compose the output image go
 * out of range, or 5 for a memory allocation error. ^
 * This function is parallelized with OpenMP and uses the same formula as @cubinterp for
 * reducing the number of threads for small images.
 */
int zoomWithFilter(unsigned char **slines, int aXsize, int aYsize, float aXoff,
                   float aYoff, int bXsize, int bYsize, int bXdim, int bXoff, int dtype,
                   void *outData, b3dUInt32 *cindex, unsigned char *bindex)
{
    Weighttab *xweights;  /* sampled filter at each dst x pos; for xfilt*/
    b3dInt16 *xweightSbuf, *xwp;  /* big block of memory addressed by xweights */
    Weighttab yweight[MAX_THREADS];       /* a single sampled filter for current y pos */
    b3dFloat *xweightFbuf, *xwfp;
    b3dInt32 *accumBuf[MAX_THREADS];
    unsigned char *filtBuf[MAX_THREADS];
    unsigned char *lineb, *obufb;
    int mapping = 0;
    int numThreads;
    int psizeAccum, psizeWgt, psizeFilt, bx, by, i, ayf, thr;
    float fweight = 0.;
    b3dInt16 sweight = 0;

    if (!sFilt_func)
        return 1;

    psizeAccum = 4;
    psizeWgt = 2;
    switch (dtype) {
    case SLICE_MODE_BYTE:
        if (cindex)
            mapping = 1;
        psizeFilt = 1;
        break;
    case SLICE_MODE_RGB:
        if (bindex)
            mapping = 1;
        psizeAccum = 12;
        psizeFilt = 3;
        break;
    case SLICE_MODE_FLOAT:
        if (cindex || bindex)
            return 3;
        psizeFilt = 4;
        psizeWgt = 4;
        break;
    case SLICE_MODE_SHORT:
    case SLICE_MODE_USHORT:
        if (cindex)
            mapping = 1;
        psizeFilt = 2;
        psizeWgt = 4;
        break;
    default:
        return 2;
    }

    if (aXoff < 0. || aYoff < 0. || (int)(aXoff + bXsize * sXscale) > aXsize ||
            (int)(aYoff + bYsize * sYscale) > aYsize) {
        /* printf("axo %f bxs %d sc %f xe %f axs %d   ayo %f bys %d ye %f ays %d\n", aXoff,
               bXsize, sXscale, aXoff + bXsize * sXscale, aXsize, aYoff, bYsize,
               aYoff + bYsize * sYscale, aYsize); */
        return 4;
    }

    numThreads = B3DNINT(0.04 * sqrt((double)aXsize * aYsize));
    numThreads = numOMPthreads(B3DMIN(numThreads, MAX_THREADS));

    /* Allocate accumulation, filter output, and weight buffers */
    xweights = B3DMALLOC(Weighttab, bXsize);
    xweightSbuf = (b3dInt16 *)malloc(bXsize * sXwidth * psizeWgt);
    if (!xweightSbuf || !xweights) {
        B3DFREE(xweights);
        B3DFREE(xweightSbuf);
        return 5;
    }

    for (i = 0; i < numThreads; i++) {
        filtBuf[i] = NULL;
        accumBuf[i] = (b3dInt32 *)malloc(aXsize * psizeAccum);
        yweight[i].weight.s = (b3dInt16 *)malloc(sYwidth * psizeWgt);
        if (mapping)
            filtBuf[i] = (unsigned char *)malloc(bXsize * psizeFilt);
        if (!accumBuf[i] || !yweight[i].weight.s || (mapping && !filtBuf[i])) {
            for (by = 0; by <= i; by++) {
                B3DFREE(yweight[by].weight.s);
                B3DFREE(accumBuf[by]);
                B3DFREE(filtBuf[by]);
            }
            return 5;
        }
    }
    xweightFbuf = (b3dFloat *)xweightSbuf;

    /*
     * prepare a weighttab (a sampled filter for source pixels) for
     * each dest x position
     */
    xwfp = xweightFbuf;
    xwp = xweightSbuf;
    for (bx = 0; bx < bXsize; bx++, xwp += sXwidth, xwfp += sXwidth) {
        if (psizeWgt == 4)
            xweights[bx].weight.f = xwfp;
        else
            xweights[bx].weight.s = xwp;
        make_weighttab(bx, aXoff + (bx + 0.5) * sXscale, aXsize, sXscale, sXsupport, dtype,
                       &xweights[bx]);
    }

    #pragma omp parallel for num_threads(numThreads)                    \
    shared(bYsize, aYoff, sYscale, aYsize, dtype, yweight, psizeAccum, accumBuf, \
           aXsize, slines, outData, psizeFilt, bXsize, mapping, filtBuf, xweights, \
           cindex, bindex, sValueScaling, sYsupport)                     \
    private(by, thr, i, ayf, sweight, fweight, lineb, obufb)
    for (by = 0; by < bYsize; by++) {
        thr = b3dOMPthreadNum();

        /* prepare a weighttab for dest y position by */
        make_weighttab(by, aYoff + (by + 0.5) * sYscale, aYsize, sYscale, sYsupport, dtype,
                       &yweight[thr]);

        /* Zero the scanline accum buffer */
        for (i = 0; i < aXsize * psizeAccum / 4; i++)
            accumBuf[thr][i] = 0;

        /* loop over source scanlines that influence this dest scanline */
        for (ayf = yweight[thr].i0; ayf < yweight[thr].i1; ayf++) {
            if (psizeWgt == 2)
                sweight = yweight[thr].weight.s[ayf-yweight[thr].i0];
            else
                fweight = yweight[thr].weight.f[ayf-yweight[thr].i0] * sValueScaling;

            lineb = (unsigned char *)slines[ayf];
            /* add weighted tbuf into accum (these do yfilt) */
            scanline_accum(lineb, dtype, aXsize, accumBuf[thr], sweight, fweight);
        }

        /* and filter it into the appropriate line of output or into filtBuf */
        obufb = (unsigned char *)outData + psizeFilt * (by * bXdim + bXoff);
        if (mapping)
            obufb = filtBuf[thr];
        /*for (i = 30; i < 45; i++)
          printf("%.1f ", *((float *)accumBuf[thr] + i));
          printf("\n"); */
        scanline_filter(accumBuf[thr], dtype, aXsize, obufb, bXsize, xweights, FINALSHIFT);

        /* Map to RGBA output, always 4 bytes, if index tables provided */
        if (mapping) {
            obufb = (unsigned char *)outData + 4 * (by * bXdim + bXoff);
            scanline_remap(filtBuf[thr], dtype, bXsize, obufb, cindex, bindex);
        }
    }

    B3DFREE(xweights);
    B3DFREE(xweightSbuf);
    for (by = 0; by < numThreads; by++) {
        B3DFREE(yweight[by].weight.s);
        B3DFREE(accumBuf[by]);
        B3DFREE(filtBuf[by]);
    }
    return 0;
}