Exemplo n.º 1
0
void process(struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, const void *const ivoid,
             void *const ovoid, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out)
{
  dt_iop_watermark_data_t *data = (dt_iop_watermark_data_t *)piece->data;
  float *in = (float *)ivoid;
  float *out = (float *)ovoid;
  const int ch = piece->colors;
  double angle = (M_PI / 180) * -data->rotate;

  /* Load svg if not loaded */
  gchar *svgdoc = _watermark_get_svgdoc(self, data, &piece->pipe->image);
  if(!svgdoc)
  {
    memcpy(ovoid, ivoid, (size_t)sizeof(float) * ch * roi_out->width * roi_out->height);
    return;
  }

  /* create the rsvghandle from parsed svg data */
  GError *error = NULL;
  RsvgHandle *svg = rsvg_handle_new_from_data((const guint8 *)svgdoc, strlen(svgdoc), &error);
  g_free(svgdoc);
  if(!svg || error)
  {
    memcpy(ovoid, ivoid, (size_t)sizeof(float) * ch * roi_out->width * roi_out->height);
    return;
  }

  /* setup stride for performance */
  int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, roi_out->width);

  /* create cairo memory surface */
  guint8 *image = (guint8 *)g_malloc0_n(roi_out->height, stride);
  cairo_surface_t *surface = cairo_image_surface_create_for_data(image, CAIRO_FORMAT_ARGB32, roi_out->width,
                                                                 roi_out->height, stride);
  if(cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS)
  {
    //   fprintf(stderr,"Cairo surface error: %s\n",cairo_status_to_string(cairo_surface_status(surface)));
    g_free(image);
    memcpy(ovoid, ivoid, (size_t)sizeof(float) * ch * roi_out->width * roi_out->height);
    return;
  }

  /* create cairo context and setup transformation/scale */
  cairo_t *cr = cairo_create(surface);

  /* get the dimension of svg */
  RsvgDimensionData dimension;
  rsvg_handle_get_dimensions(svg, &dimension);

  //  width/height of current (possibly cropped) image
  const float iw = piece->buf_in.width;
  const float ih = piece->buf_in.height;
  const float uscale = data->scale / 100.0; // user scale, from GUI in percent

  // wbase, hbase are the base width and height, this is the multiplicator used for the offset computing
  // scale is the scale of the watermark itself and is used only to render it.

  float wbase, hbase, scale;

  if(data->sizeto == DT_SCALE_IMAGE)
  {
    // in image mode, the wbase and hbase are just the image width and height
    wbase = iw;
    hbase = ih;
    if(dimension.width > dimension.height)
      scale = (iw * roi_out->scale) / dimension.width;
    else
      scale = (ih * roi_out->scale) / dimension.height;
  }
  else
  {
    // in larger/smaller side mode, set wbase and hbase to the largest or smallest side of the image
    float larger;
    if(dimension.width > dimension.height)
      larger = (float)dimension.width;
    else
      larger = (float)dimension.height;

    if(iw > ih)
    {
      wbase = hbase = (data->sizeto == DT_SCALE_LARGER_BORDER) ? iw : ih;
      scale = (data->sizeto == DT_SCALE_LARGER_BORDER) ? (iw / larger) : (ih / larger);
    }
    else
    {
      wbase = hbase = (data->sizeto == DT_SCALE_SMALLER_BORDER) ? iw : ih;
      scale = (data->sizeto == DT_SCALE_SMALLER_BORDER) ? (iw / larger) : (ih / larger);
    }
    scale *= roi_out->scale;
  }

  scale *= uscale;

  // compute the width and height of the SVG object in image dimension. This is only used to properly
  // layout the watermark based on the alignment.

  float svg_width, svg_height;

  if(dimension.width > dimension.height)
  {
    if(data->sizeto == DT_SCALE_IMAGE || (iw > ih && data->sizeto == DT_SCALE_LARGER_BORDER)
       || (iw < ih && data->sizeto == DT_SCALE_SMALLER_BORDER))
    {
      svg_width = iw * uscale;
      svg_height = dimension.height * (svg_width / dimension.width);
    }
    else
    {
      svg_width = ih * uscale;
      svg_height = dimension.height * (svg_width / dimension.width);
    }
  }
  else
  {
    if(data->sizeto == DT_SCALE_IMAGE || (ih > iw && data->sizeto == DT_SCALE_LARGER_BORDER)
       || (ih < iw && data->sizeto == DT_SCALE_SMALLER_BORDER))
    {
      svg_height = ih * uscale;
      svg_width = dimension.width * (svg_height / dimension.height);
    }
    else
    {
      svg_height = iw * uscale;
      svg_width = dimension.width * (svg_height / dimension.height);
    }
  }

  // compute bounding box of rotated watermark
  float bb_width, bb_height;
  bb_width = fabs(svg_width * cos(angle)) + fabs(svg_height * sin(angle));
  bb_height = fabs(svg_width * sin(angle)) + fabs(svg_height * cos(angle));
  float bX = bb_width / 2.0 - svg_width / 2.0;
  float bY = bb_height / 2.0 - svg_height / 2.0;

  // compute translation for the given alignment in image dimension

  float ty = 0, tx = 0;
  if(data->alignment >= 0 && data->alignment < 3) // Align to verttop
    ty = bY;
  else if(data->alignment >= 3 && data->alignment < 6) // Align to vertcenter
    ty = (ih / 2.0) - (svg_height / 2.0);
  else if(data->alignment >= 6 && data->alignment < 9) // Align to vertbottom
    ty = ih - svg_height - bY;

  if(data->alignment == 0 || data->alignment == 3 || data->alignment == 6)
    tx = bX;
  else if(data->alignment == 1 || data->alignment == 4 || data->alignment == 7)
    tx = (iw / 2.0) - (svg_width / 2.0);
  else if(data->alignment == 2 || data->alignment == 5 || data->alignment == 8)
    tx = iw - svg_width - bX;

  // translate to position
  cairo_translate(cr, -roi_in->x, -roi_in->y);

  // add translation for the given value in GUI (xoffset,yoffset)
  tx += data->xoffset * wbase;
  ty += data->yoffset * hbase;

  cairo_translate(cr, tx * roi_out->scale, ty * roi_out->scale);

  // compute the center of the svg to rotate from the center
  float cX = svg_width / 2.0 * roi_out->scale;
  float cY = svg_height / 2.0 * roi_out->scale;

  cairo_translate(cr, cX, cY);
  cairo_rotate(cr, angle);
  cairo_translate(cr, -cX, -cY);

  // now set proper scale for the watermark itself
  cairo_scale(cr, scale, scale);

  /* render svg into surface*/
  dt_pthread_mutex_lock(&darktable.plugin_threadsafe);
  rsvg_handle_render_cairo(svg, cr);
  dt_pthread_mutex_unlock(&darktable.plugin_threadsafe);

  cairo_destroy(cr);

  /* ensure that all operations on surface finishing up */
  cairo_surface_flush(surface);

  /* render surface on output */
  guint8 *sd = image;
  float opacity = data->opacity / 100.0;
  /*
  #ifdef _OPENMP
    #pragma omp parallel for default(none) shared(in, out,sd,opacity) schedule(static)
  #endif
  */
  for(int j = 0; j < roi_out->height; j++)
    for(int i = 0; i < roi_out->width; i++)
    {
      float alpha = (sd[3] / 255.0) * opacity;
      /* svg uses a premultiplied alpha, so only use opacity for the blending */
      out[0] = ((1.0 - alpha) * in[0]) + (opacity * (sd[2] / 255.0));
      out[1] = ((1.0 - alpha) * in[1]) + (opacity * (sd[1] / 255.0));
      out[2] = ((1.0 - alpha) * in[2]) + (opacity * (sd[0] / 255.0));
      out[3] = in[3];

      out += ch;
      in += ch;
      sd += 4;
    }


  /* clean up */
  cairo_surface_destroy(surface);
  g_object_unref(svg);
  g_free(image);
}
Exemplo n.º 2
0
void process (struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, void *ivoid, void *ovoid, const dt_iop_roi_t *roi_in, const dt_iop_roi_t *roi_out)
{
  dt_iop_watermark_data_t *data = (dt_iop_watermark_data_t *)piece->data;
  float *in  = (float *)ivoid;
  float *out = (float *)ovoid;
  const int ch = piece->colors;

  /* Load svg if not loaded */
  gchar *svgdoc = _watermark_get_svgdoc (self, data, &piece->pipe->image);
  if (!svgdoc)
  {
    memcpy(ovoid, ivoid, sizeof(float)*ch*roi_out->width*roi_out->height);
    return;
  }

  /* create the rsvghandle from parsed svg data */
  GError *error = NULL;
  RsvgHandle *svg = rsvg_handle_new_from_data ((const guint8 *)svgdoc,strlen (svgdoc),&error);
  g_free (svgdoc);
  if (!svg || error)
  {
    memcpy(ovoid, ivoid, sizeof(float)*ch*roi_out->width*roi_out->height);
    return;
  }

  /* get the dimension of svg */
  RsvgDimensionData dimension;
  rsvg_handle_get_dimensions (svg,&dimension);

  /* calculate aligment of watermark */
  const float iw=piece->buf_in.width*roi_out->scale;
  const float ih=piece->buf_in.height*roi_out->scale;

  float scale=1.0;
  if ((dimension.width/dimension.height)>1.0)
    scale = iw/dimension.width;
  else
    scale = ih/dimension.height;

  scale *= (data->scale/100.0);

  /* setup stride for performance */
  int stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32,roi_out->width);

  /* create cairo memory surface */
  guint8 *image= (guint8 *)g_malloc (stride*roi_out->height);
  memset (image,0,stride*roi_out->height);
  cairo_surface_t *surface = cairo_image_surface_create_for_data (image,CAIRO_FORMAT_ARGB32,roi_out->width,roi_out->height,stride);
  if (cairo_surface_status(surface)!=	CAIRO_STATUS_SUCCESS)
  {
//   fprintf(stderr,"Cairo surface error: %s\n",cairo_status_to_string(cairo_surface_status(surface)));
    g_free (image);
    memcpy(ovoid, ivoid, sizeof(float)*ch*roi_out->width*roi_out->height);
    return;
  }

  /* create cairo context and setup transformation/scale */
  cairo_t *cr = cairo_create (surface);

  float ty=0,tx=0;
  if( data->alignment >=0 && data->alignment <3) // Align to verttop
    ty=0;
  else if( data->alignment >=3 && data->alignment <6) // Align to vertcenter
    ty=(ih/2.0)-((dimension.height*scale)/2.0);
  else if( data->alignment >=6 && data->alignment <9) // Align to vertbottom
    ty=ih-(dimension.height*scale);

  if( data->alignment == 0 ||  data->alignment == 3 || data->alignment==6 )
    tx=0;
  else if( data->alignment == 1 ||  data->alignment == 4 || data->alignment==7 )
    tx=(iw/2.0)-((dimension.width*scale)/2.0);
  else if( data->alignment == 2 ||  data->alignment == 5 || data->alignment==8 )
    tx=iw-(dimension.width*scale);

  /* translate to position */
  cairo_translate (cr,-roi_in->x,-roi_in->y);
  cairo_translate (cr,tx,ty);

  /* scale */
  cairo_scale (cr,scale,scale);

  /* translate x and y offset */
  cairo_translate (cr,data->xoffset*iw/roi_out->scale,data->yoffset*ih/roi_out->scale);

  /* render svg into surface*/
  dt_pthread_mutex_lock(&darktable.plugin_threadsafe);
  rsvg_handle_render_cairo (svg,cr);
  dt_pthread_mutex_unlock(&darktable.plugin_threadsafe);

  /* ensure that all operations on surface finishing up */
  cairo_surface_flush (surface);

  /* render surface on output */
  guint8 *sd = image;
  float opacity = data->opacity/100.0;
  /*
  #ifdef _OPENMP
  	#pragma omp parallel for default(none) shared(roi_out, in, out,sd,opacity) schedule(static)
  #endif
  */
  for(int j=0; j<roi_out->height; j++) for(int i=0; i<roi_out->width; i++)
    {
      float alpha = (sd[3]/255.0)*opacity;
      out[0] = ((1.0-alpha)*in[0]) + (alpha*(sd[2]/255.0));
      out[1] = ((1.0-alpha)*in[1]) + (alpha*(sd[1]/255.0));
      out[2] = ((1.0-alpha)*in[2]) + (alpha*(sd[0]/255.0));
      out[3] = in[3];

      out+=ch;
      in+=ch;
      sd+=4;
    }


  /* clean up */
  cairo_surface_destroy (surface);
  g_object_unref (svg);
  g_free (image);

}