Example #1
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, (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_malloc (stride*roi_out->height);
  memset (image,0,(size_t)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, (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 translation for the given alignment in image dimension

  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)-(svg_height/2.0);
  else if( data->alignment >=6 && data->alignment <9) // Align to vertbottom
    ty=ih-svg_height;

  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)-(svg_width/2.0);
  else if( data->alignment == 2 ||  data->alignment == 5 || data->alignment==8 )
    tx=iw-svg_width;

  // 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);

  // 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);

  /* 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;
      /* 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);

}
Example #2
0
int main (int argc, char ** argv) {
	init_shmemfonts();

	yutani_t * y = yutani_init();

	if (!y) {
		fprintf(stderr, "[glogin] Connection to server failed.\n");
		return 1;
	}

	/* Load config */
	{
		confreader_t * conf = confreader_load("/etc/glogin.conf");

		LOGO_FINAL_OFFSET = confreader_intd(conf, "style", "logo_padding", LOGO_FINAL_OFFSET);
		BOX_WIDTH = confreader_intd(conf, "style", "box_width", BOX_WIDTH);
		BOX_HEIGHT = confreader_intd(conf, "style", "box_height", BOX_HEIGHT);
		BOX_ROUNDNESS = confreader_intd(conf, "style", "box_roundness", BOX_ROUNDNESS);
		CENTER_BOX_X = confreader_intd(conf, "style", "center_box_x", CENTER_BOX_X);
		CENTER_BOX_Y = confreader_intd(conf, "style", "center_box_y", CENTER_BOX_Y);
		BOX_LEFT = confreader_intd(conf, "style", "box_left", BOX_LEFT);
		BOX_RIGHT = confreader_intd(conf, "style", "box_right", BOX_RIGHT);
		BOX_TOP = confreader_intd(conf, "style", "box_top", BOX_TOP);
		BOX_BOTTOM = confreader_intd(conf, "style", "box_bottom", BOX_BOTTOM);
		BOX_COLOR_R = confreader_intd(conf, "style", "box_color_r", BOX_COLOR_R);
		BOX_COLOR_G = confreader_intd(conf, "style", "box_color_g", BOX_COLOR_G);
		BOX_COLOR_B = confreader_intd(conf, "style", "box_color_b", BOX_COLOR_B);
		BOX_COLOR_A = confreader_intd(conf, "style", "box_color_a", BOX_COLOR_A);

		WALLPAPER = confreader_getd(conf, "image", "wallpaper", WALLPAPER);
		LOGO = confreader_getd(conf, "image", "logo", LOGO);

		confreader_free(conf);

		TRACE("Loading complete");
	}

	TRACE("Loading logo...");
	load_sprite_png(&logo, LOGO);
	TRACE("... done.");

	/* Generate surface for background */
	sprite_t * bg_sprite;

	int width  = y->display_width;
	int height = y->display_height;
	int skip_animation = 0;

	/* Do something with a window */
	TRACE("Connecting to window server...");
	yutani_window_t * wina = yutani_window_create(y, width, height);
	assert(wina);
	yutani_set_stack(y, wina, 0);
	ctx = init_graphics_yutani_double_buffer(wina);
	draw_fill(ctx, rgba(0,0,0,255));
	yutani_flip(y, wina);
	TRACE("... done.");


redo_everything:
	win_width = width;
	win_height = height;

	cairo_surface_t * cs = cairo_image_surface_create_for_data((void*)ctx->backbuffer, CAIRO_FORMAT_ARGB32, ctx->width, ctx->height, cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, ctx->width));
	cairo_t * cr = cairo_create(cs);


	TRACE("Loading wallpaper...");
	{
		sprite_t * wallpaper = malloc(sizeof(sprite_t));
		load_sprite_png(wallpaper, WALLPAPER);

		float x = (float)width  / (float)wallpaper->width;
		float y = (float)height / (float)wallpaper->height;

		int nh = (int)(x * (float)wallpaper->height);
		int nw = (int)(y * (float)wallpaper->width);;

		bg_sprite = create_sprite(width, height, ALPHA_OPAQUE);
		gfx_context_t * bg = init_graphics_sprite(bg_sprite);

		if (nw > width) {
			draw_sprite_scaled(bg, wallpaper, (width - nw) / 2, 0, nw, height);
		} else {
			draw_sprite_scaled(bg, wallpaper, 0, (height - nh) / 2, width, nh);
		}

		/* Three box blurs = good enough approximation of a guassian, but faster*/
		blur_context_box(bg, 20);
		blur_context_box(bg, 20);
		blur_context_box(bg, 20);

		free(bg);
		free(wallpaper);
	}
	TRACE("... done.");

	while (1) {

		yutani_set_stack(y, wina, 0);
		yutani_focus_window(y, wina->wid);

		draw_fill(ctx, rgb(0,0,0));
		draw_sprite(ctx, bg_sprite, center_x(width), center_y(height));
		flip(ctx);
		yutani_flip(y, wina);

		char * foo = malloc(sizeof(uint32_t) * width * height);
		memcpy(foo, ctx->backbuffer, sizeof(uint32_t) * width * height);

		TRACE("Begin animation.");
		if (!skip_animation) {
			struct timeval start;
			gettimeofday(&start, NULL);

			while (1) {
				uint32_t tick;
				struct timeval t;
				gettimeofday(&t, NULL);

				uint32_t sec_diff = t.tv_sec - start.tv_sec;
				uint32_t usec_diff = t.tv_usec - start.tv_usec;

				if (t.tv_usec < start.tv_usec) {
					sec_diff -= 1;
					usec_diff = (1000000 + t.tv_usec) - start.tv_usec;
				}

				tick = (uint32_t)(sec_diff * 1000 + usec_diff / 1000);
				int i = (float)LOGO_FINAL_OFFSET * (float)tick / 700.0f;
				if (i >= LOGO_FINAL_OFFSET) break;

				memcpy(ctx->backbuffer, foo, sizeof(uint32_t) * width * height);
				draw_sprite(ctx, &logo, center_x(logo.width), center_y(logo.height) - i);
				flip(ctx);
				yutani_flip_region(y, wina, center_x(logo.width), center_y(logo.height) - i, logo.width, logo.height + 5);
				usleep(10000);
			}
		}
		TRACE("End animation.");
		skip_animation = 0;

		size_t buf_size = wina->width * wina->height * sizeof(uint32_t);
		char * buf = malloc(buf_size);

		uint32_t i = 0;

		uint32_t black = rgb(0,0,0);
		uint32_t white = rgb(255,255,255);

		int x_offset = 65;
		int y_offset = 64;

		int fuzz = 3;

		char username[INPUT_SIZE] = {0};
		char password[INPUT_SIZE] = {0};
		char hostname[512];

		// we do it here to calculate the final string position
		get_updated_hostname_with_time_info(hostname);

		char kernel_v[512];

		{
			struct utsname u;
			uname(&u);
			/* UTF-8 Strings FTW! */
			uint8_t * os_name_ = "とあるOS";
			uint32_t l = snprintf(kernel_v, 512, "%s %s", os_name_, u.release);
		}

		uid = 0;

		int box_x, box_y;

		if (CENTER_BOX_X) {
			box_x = center_x(BOX_WIDTH);
		} else if (BOX_LEFT == -1) {
			box_x = win_width - BOX_RIGHT - BOX_WIDTH;
		} else {
			box_x = BOX_LEFT;
		}
		if (CENTER_BOX_Y) {
			box_y = center_y(0) + 8;
		} else if (BOX_TOP == -1) {
			box_y = win_width - BOX_BOTTOM - BOX_HEIGHT;
		} else {
			box_y = BOX_TOP;
		}

		int focus = 0;

		set_font_size(11);
		int hostname_label_left = width - 10 - draw_string_width(hostname);
		int kernel_v_label_left = 10;

		struct text_box username_box = { (BOX_WIDTH - 170) / 2, 30, 170, 20, rgb(0,0,0), NULL, 0, 0, 0, username, "Username" };
		struct text_box password_box = { (BOX_WIDTH - 170) / 2, 58, 170, 20, rgb(0,0,0), NULL, 0, 1, 0, password, "Password" };

		struct login_container lc = { box_x, box_y, BOX_WIDTH, BOX_HEIGHT, &username_box, &password_box, 0 };

		username_box.parent = &lc;
		password_box.parent = &lc;

		while (1) {
			focus = 0;
			memset(username, 0x0, INPUT_SIZE);
			memset(password, 0x0, INPUT_SIZE);

			while (1) {

				// update time info
				get_updated_hostname_with_time_info(hostname);

				memcpy(ctx->backbuffer, foo, sizeof(uint32_t) * width * height);
				draw_sprite(ctx, &logo, center_x(logo.width), center_y(logo.height) - LOGO_FINAL_OFFSET);

				set_font_size(11);
				draw_string_shadow(ctx, hostname_label_left, height - 12, white, hostname, rgb(0,0,0), 2, 1, 1, 3.0);
				draw_string_shadow(ctx, kernel_v_label_left, height - 12, white, kernel_v, rgb(0,0,0), 2, 1, 1, 3.0);

				if (focus == USERNAME_BOX) {
					username_box.is_focused = 1;
					password_box.is_focused = 0;
				} else if (focus == PASSWORD_BOX) {
					username_box.is_focused = 0;
					password_box.is_focused = 1;
				} else {
					username_box.is_focused = 0;
					password_box.is_focused = 0;
				}

				draw_login_container(cr, &lc);

				flip(ctx);
				yutani_flip(y, wina);

				struct yutani_msg_key_event kbd;
				struct yutani_msg_window_mouse_event mou;
				int msg_type = 0;
collect_events:
				do {
					yutani_msg_t * msg = yutani_poll(y);
					switch (msg->type) {
						case YUTANI_MSG_KEY_EVENT:
							{
								struct yutani_msg_key_event * ke = (void*)msg->data;
								if (ke->event.action == KEY_ACTION_DOWN) {
									memcpy(&kbd, ke, sizeof(struct yutani_msg_key_event));
									msg_type = 1;
								}
							}
							break;
						case YUTANI_MSG_WINDOW_MOUSE_EVENT:
							{
								struct yutani_msg_window_mouse_event * me = (void*)msg->data;
								memcpy(&mou, me, sizeof(struct yutani_msg_mouse_event));
								msg_type = 2;
							}
							break;
						case YUTANI_MSG_WELCOME:
							{
								struct yutani_msg_welcome * mw = (void*)msg->data;
								yutani_window_resize(y, wina, mw->display_width, mw->display_height);
							}
							break;
						case YUTANI_MSG_RESIZE_OFFER:
							{
								struct yutani_msg_window_resize * wr = (void*)msg->data;
								width = wr->width;
								height = wr->height;
								yutani_window_resize_accept(y, wina, width, height);
								reinit_graphics_yutani(ctx, wina);
								yutani_window_resize_done(y, wina);

								sprite_free(bg_sprite);
								cairo_destroy(cr);
								cairo_surface_destroy(cs);

								skip_animation = 1;
								goto redo_everything;
							}
							break;
					}
					free(msg);
				} while (!msg_type);

				if (msg_type == 1) {

					if (kbd.event.keycode == '\n') {
						if (focus == USERNAME_BOX) {
							focus = PASSWORD_BOX;
							continue;
						} else if (focus == PASSWORD_BOX) {
							break;
						} else {
							focus = USERNAME_BOX;
							continue;
						}
					}

					if (kbd.event.keycode == '\t') {
						if (focus == USERNAME_BOX) {
							focus = PASSWORD_BOX;
						} else {
							focus = USERNAME_BOX;
						}
						continue;
					}

					if (kbd.event.key) {

						if (!focus) {
							focus = USERNAME_BOX;
						}

						if (focus == USERNAME_BOX) {
							buffer_put(username, kbd.event.key);
						} else if (focus == PASSWORD_BOX) {
							buffer_put(password, kbd.event.key);
						}

					}

				} else if (msg_type == 2) {

					if ((mou.command == YUTANI_MOUSE_EVENT_DOWN
					     && mou.buttons & YUTANI_MOUSE_BUTTON_LEFT)
					    || (mou.command == YUTANI_MOUSE_EVENT_CLICK)) {
						/* Determine if we were inside of a text box */

						if (mou.new_x >= lc.x + username_box.x &&
						    mou.new_x <= lc.x + username_box.x + username_box.width &&
						    mou.new_y >= lc.y + username_box.y &&
						    mou.new_y <= lc.y + username_box.y + username_box.height) {
							/* Ensure this box is focused. */
							focus = USERNAME_BOX;
							continue;
						} else if (mou.new_x >= lc.x + password_box.x &&
						    mou.new_x <= lc.x + password_box.x + password_box.width &&
						    mou.new_y >= lc.y + password_box.y &&
						    mou.new_y <= lc.y + password_box.y + password_box.height) {
							/* Ensure this box is focused. */
							focus = PASSWORD_BOX;
							continue;
						} else {
							focus = 0;
							continue;
						}

					} else {
						goto collect_events;
					}
				}

			}

			uid = toaru_auth_check_pass(username, password);

			if (uid >= 0) {
				break;
			}
			lc.show_error = 1;
		}

		memcpy(ctx->backbuffer, foo, sizeof(uint32_t) * width * height);
		flip(ctx);
		yutani_flip(y, wina);
		syscall_yield();

		pid_t _session_pid = fork();
		if (!_session_pid) {
			setuid(uid);
			toaru_auth_set_vars();
			char * args[] = {"/bin/gsession", NULL};
			execvp(args[0], args);
		}

		free(foo);
		free(buf);

		waitpid(_session_pid, NULL, 0);
	}

	yutani_close(y, wina);


	return 0;
}
Example #3
0
static GstFlowReturn
gst_rsvg_decode_image (GstRsvgDec * rsvg, const guint8 * data, guint size,
    GstBuffer ** buffer)
{
  GstFlowReturn ret = GST_FLOW_OK;
  cairo_t *cr;
  cairo_surface_t *surface;
  RsvgHandle *handle;
  GError *error = NULL;
  RsvgDimensionData dimension;
  gdouble scalex, scaley;

  GST_LOG_OBJECT (rsvg, "parsing svg");

  handle = rsvg_handle_new_from_data (data, size, &error);
  if (!handle) {
    GST_ERROR_OBJECT (rsvg, "Failed to parse SVG image: %s", error->message);
    g_error_free (error);
    return GST_FLOW_ERROR;
  }

  rsvg_handle_get_dimensions (handle, &dimension);
  if (rsvg->width != dimension.width || rsvg->height != dimension.height) {
    GstCaps *caps1, *caps2, *caps3;
    GstStructure *s;

    GST_LOG_OBJECT (rsvg, "resolution changed, updating caps");

    caps1 = gst_caps_copy (gst_pad_get_pad_template_caps (rsvg->srcpad));
    caps2 = gst_pad_peer_get_caps (rsvg->srcpad);
    if (caps2) {
      caps3 = gst_caps_intersect (caps1, caps2);
      gst_caps_unref (caps1);
      gst_caps_unref (caps2);
      caps1 = caps3;
      caps3 = NULL;
    }

    if (gst_caps_is_empty (caps1)) {
      GST_ERROR_OBJECT (rsvg, "Unable to negotiate a format");
      gst_caps_unref (caps1);
      g_object_unref (handle);
      return GST_FLOW_NOT_NEGOTIATED;
    }

    caps2 = gst_caps_copy (gst_pad_get_pad_template_caps (rsvg->srcpad));
    s = gst_caps_get_structure (caps2, 0);
    gst_structure_set (s, "width", G_TYPE_INT, dimension.width, "height",
        G_TYPE_INT, dimension.height, "framerate", GST_TYPE_FRACTION, 0, 1,
        NULL);
    caps3 = gst_caps_intersect (caps1, caps2);
    if (!gst_caps_is_empty (caps3)) {
      gst_caps_truncate (caps3);
      gst_pad_set_caps (rsvg->srcpad, caps3);
      gst_caps_unref (caps1);
      gst_caps_unref (caps2);
      gst_caps_unref (caps3);
      rsvg->width = dimension.width;
      rsvg->height = dimension.height;
    } else {
      gst_caps_unref (caps2);
      gst_caps_unref (caps3);
      gst_caps_truncate (caps1);

      s = gst_caps_get_structure (caps1, 0);
      gst_structure_set (s, "framerate", GST_TYPE_FRACTION, 0, 1, NULL);

      if (!gst_caps_is_fixed (caps1)
          && (!gst_structure_fixate_field_nearest_int (s, "width",
                  dimension.width)
              || !gst_structure_fixate_field_nearest_int (s, "height",
                  dimension.height))) {
        g_object_unref (handle);
        GST_ERROR_OBJECT (rsvg, "Failed to fixate caps");
        return GST_FLOW_NOT_NEGOTIATED;
      }
      gst_pad_set_caps (rsvg->srcpad, caps1);
      gst_structure_get_int (s, "width", &rsvg->width);
      gst_structure_get_int (s, "height", &rsvg->height);
      gst_caps_unref (caps1);
    }
  }

  if ((ret = gst_pad_alloc_buffer_and_set_caps (rsvg->srcpad,
              GST_BUFFER_OFFSET_NONE,
              rsvg->width * rsvg->height * 4,
              GST_PAD_CAPS (rsvg->srcpad), buffer)) != GST_FLOW_OK) {
    g_object_unref (handle);
    GST_ERROR_OBJECT (rsvg, "Buffer allocation failed %s",
        gst_flow_get_name (ret));
    return ret;
  }

  GST_LOG_OBJECT (rsvg, "render image at %d x %d", rsvg->height, rsvg->width);

  surface =
      cairo_image_surface_create_for_data (GST_BUFFER_DATA (*buffer),
      CAIRO_FORMAT_ARGB32, rsvg->width, rsvg->height, rsvg->width * 4);

  cr = cairo_create (surface);
  cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
  cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.0);
  cairo_paint (cr);
  cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
  cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0);

  scalex = scaley = 1.0;
  if (rsvg->width != dimension.width) {
    scalex = ((gdouble) rsvg->width) / ((gdouble) dimension.width);
  }
  if (rsvg->height != dimension.height) {
    scaley = ((gdouble) rsvg->height) / ((gdouble) dimension.height);
  }
  cairo_scale (cr, scalex, scaley);
  rsvg_handle_render_cairo (handle, cr);

  g_object_unref (handle);
  cairo_destroy (cr);
  cairo_surface_destroy (surface);

  /* Now unpremultiply Cairo's ARGB to match GStreamer's */
  gst_rsvg_decode_unpremultiply (GST_BUFFER_DATA (*buffer), rsvg->width,
      rsvg->height);

  return ret;
}
Example #4
0
static void
ui_update (BubblemonApplet *applet)
{
  int w, h, i;
  const bubblemon_picture_t *bubblePic;
  bubblemon_color_t *pixel;
  guchar *p;

  cairo_t *cr;
  int stride;
  cairo_surface_t *surface;

  GtkWidget *drawingArea = applet->drawingArea;

  if((drawingArea == NULL) ||
     !gtk_widget_get_realized(drawingArea) ||
     !gtk_widget_is_drawable(drawingArea) ||
     applet->width <= 0)
  {
    return;
  }

  bubblePic = bubblemon_getPicture(applet->bubblemon);
  if ((bubblePic == NULL) ||
      (bubblePic->width == 0) ||
      (bubblePic->pixels == 0))
  {
    return;
  }
  w = bubblePic->width;
  h = bubblePic->height;

  /* CAIRO_FORMAT_RGB24 lays each pixel out as 4 bytes: unused; R; G; B */
  p = applet->rgb_buffer;
  pixel = bubblePic->pixels;
  for(i = 0; i < w * h; i++) {
#  if BYTE_ORDER == BIG_ENDIAN
    p++;/* a (unused; CAIRO_FORMAT_RGB24 lays pixel format: unused; R; G; B) */
    *(p++) = pixel->components.r;
    *(p++) = pixel->components.g;
    *(p++) = pixel->components.b;
#  else
    *(p++) = pixel->components.b;
    *(p++) = pixel->components.g;
    *(p++) = pixel->components.r;
    p++;/* a (unused; CAIRO_FORMAT_RGB24 lays pixel format: B; G; R; unused) */
#  endif /* BYTE_ORDER */
    pixel++;
  }

  cr = gdk_cairo_create(gtk_widget_get_window(drawingArea));
  /*surface = cairo_get_target(cr);
  if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS)
  {
    return;
  }
  s_stride = cairo_image_surface_get_stride( surface );
  s_pixels = cairo_image_surface_get_data( surface );*/
  stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, bubblePic->width);
  surface = cairo_image_surface_create_for_data(applet->rgb_buffer, CAIRO_FORMAT_RGB24, applet->width, applet->height, stride);
  cairo_set_source_surface(cr, surface, 0, 0);
  cairo_paint(cr);
  cairo_surface_destroy(surface);
  cairo_destroy(cr);

}
Example #5
0
static GstFlowReturn
gst_rsvg_decode_image (GstRsvgDec * rsvg, GstBuffer * buffer,
    GstVideoCodecFrame * frame)
{
  GstVideoDecoder *decoder = GST_VIDEO_DECODER (rsvg);
  GstFlowReturn ret = GST_FLOW_OK;
  cairo_t *cr;
  cairo_surface_t *surface;
  RsvgHandle *handle;
  GError *error = NULL;
  RsvgDimensionData dimension;
  gdouble scalex, scaley;
  GstMapInfo minfo;
  GstVideoFrame vframe;
  GstVideoCodecState *output_state;

  GST_LOG_OBJECT (rsvg, "parsing svg");

  if (!gst_buffer_map (buffer, &minfo, GST_MAP_READ)) {
    GST_ERROR_OBJECT (rsvg, "Failed to get SVG image");
    return GST_FLOW_ERROR;
  }
  handle = rsvg_handle_new_from_data (minfo.data, minfo.size, &error);
  if (!handle) {
    GST_ERROR_OBJECT (rsvg, "Failed to parse SVG image: %s", error->message);
    g_error_free (error);
    return GST_FLOW_ERROR;
  }

  rsvg_handle_get_dimensions (handle, &dimension);

  output_state = gst_video_decoder_get_output_state (decoder);
  if ((output_state == NULL)
      || GST_VIDEO_INFO_WIDTH (&output_state->info) != dimension.width
      || GST_VIDEO_INFO_HEIGHT (&output_state->info) != dimension.height) {

    /* Create the output state */
    if (output_state)
      gst_video_codec_state_unref (output_state);
    output_state =
        gst_video_decoder_set_output_state (decoder, GST_RSVG_VIDEO_FORMAT,
        dimension.width, dimension.height, rsvg->input_state);
  }

  ret = gst_video_decoder_allocate_output_frame (decoder, frame);

  if (ret != GST_FLOW_OK) {
    g_object_unref (handle);
    gst_video_codec_state_unref (output_state);
    GST_ERROR_OBJECT (rsvg, "Buffer allocation failed %s",
        gst_flow_get_name (ret));
    return ret;
  }

  GST_LOG_OBJECT (rsvg, "render image at %d x %d",
      GST_VIDEO_INFO_HEIGHT (&output_state->info),
      GST_VIDEO_INFO_WIDTH (&output_state->info));


  if (!gst_video_frame_map (&vframe,
          &output_state->info, frame->output_buffer, GST_MAP_READWRITE)) {
    GST_ERROR_OBJECT (rsvg, "Failed to get SVG image");
    g_object_unref (handle);
    gst_video_codec_state_unref (output_state);
    return GST_FLOW_ERROR;
  }
  surface =
      cairo_image_surface_create_for_data (GST_VIDEO_FRAME_PLANE_DATA (&vframe,
          0), CAIRO_FORMAT_ARGB32, GST_VIDEO_FRAME_WIDTH (&vframe),
      GST_VIDEO_FRAME_HEIGHT (&vframe), GST_VIDEO_FRAME_PLANE_STRIDE (&vframe,
          0));

  cr = cairo_create (surface);
  cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
  cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.0);
  cairo_paint (cr);
  cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
  cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0);

  scalex = scaley = 1.0;
  if (GST_VIDEO_INFO_WIDTH (&output_state->info) != dimension.width) {
    scalex =
        ((gdouble) GST_VIDEO_INFO_WIDTH (&output_state->info)) /
        ((gdouble) dimension.width);
  }
  if (GST_VIDEO_INFO_HEIGHT (&output_state->info) != dimension.height) {
    scaley =
        ((gdouble) GST_VIDEO_INFO_HEIGHT (&output_state->info)) /
        ((gdouble) dimension.height);
  }
  cairo_scale (cr, scalex, scaley);
  rsvg_handle_render_cairo (handle, cr);

  g_object_unref (handle);
  cairo_destroy (cr);
  cairo_surface_destroy (surface);

  /* Now unpremultiply Cairo's ARGB to match GStreamer's */
  gst_rsvg_decode_unpremultiply (GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0),
      GST_VIDEO_FRAME_WIDTH (&vframe), GST_VIDEO_FRAME_HEIGHT (&vframe));

  gst_video_codec_state_unref (output_state);
  gst_buffer_unmap (buffer, &minfo);
  gst_video_frame_unmap (&vframe);

  return ret;
}
static void
gst_validate_ssim_save_out (GstValidateSsim * self, GstBuffer * buffer,
    const gchar * ref_file, const gchar * file, const gchar * outfolder)
{
  GstVideoFrame frame, converted;

  if (!g_file_test (outfolder, G_FILE_TEST_IS_DIR)) {
    if (g_mkdir_with_parents (outfolder, 0755) != 0) {

      GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR,
          "Could not create output directory %s", outfolder);
      return;
    }
  }

  if (self->priv->outconverter_info.converter == NULL ||
      self->priv->width != self->priv->outconverter_info.out_info.width ||
      self->priv->height != self->priv->outconverter_info.out_info.height) {

    if (self->priv->outconverter_info.converter)
      gst_video_converter_free (self->priv->outconverter_info.converter);

    gst_video_info_init (&self->priv->outconverter_info.in_info);
    gst_video_info_set_format (&self->priv->outconverter_info.in_info,
        GST_VIDEO_FORMAT_GRAY8, self->priv->width, self->priv->height);

    gst_video_info_init (&self->priv->outconverter_info.out_info);
    gst_video_info_set_format (&self->priv->outconverter_info.out_info,
        GST_VIDEO_FORMAT_RGBx, self->priv->width, self->priv->height);

    self->priv->outconverter_info.converter =
        gst_video_converter_new (&self->priv->outconverter_info.in_info,
        &self->priv->outconverter_info.out_info, NULL);
  }

  if (!gst_video_frame_map (&frame, &self->priv->outconverter_info.in_info,
          buffer, GST_MAP_READ)) {
    GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR,
        "Could not map output frame");

    return;
  }

  if (gst_validate_ssim_convert (self, &self->priv->outconverter_info,
          &frame, &converted)) {
    cairo_status_t status;
    cairo_surface_t *surface;
    gchar *bn1 = g_path_get_basename (ref_file);
    gchar *bn2 = g_path_get_basename (file);
    gchar *fname = g_strdup_printf ("%s.VS.%s.result.png", bn1, bn2);
    gchar *outfile = g_build_path (G_DIR_SEPARATOR_S, outfolder, fname, NULL);

    surface =
        cairo_image_surface_create_for_data (GST_VIDEO_FRAME_PLANE_DATA
        (&converted, 0), CAIRO_FORMAT_RGB24, GST_VIDEO_FRAME_WIDTH (&converted),
        GST_VIDEO_FRAME_HEIGHT (&converted),
        GST_VIDEO_FRAME_PLANE_STRIDE (&converted, 0));

    if ((status = cairo_surface_write_to_png (surface, outfile)) !=
        CAIRO_STATUS_SUCCESS) {
      GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR,
          "Could not save '%s', cairo status is '%s'", outfile,
          cairo_status_to_string (status));
    }

    cairo_surface_destroy (surface);
    gst_video_frame_unmap (&frame);
    gst_video_frame_unmap (&converted);
    g_free (bn1);
    g_free (bn2);
    g_free (fname);
    g_free (outfile);
  }
}
int main(int argc, char **argv) {
  int    hres, vres, width, height, pixels;
  double aspect, scale;

  SDL_Surface    *sdl_surface;
  Uint32         next_frame;
  cairo_t        *cr;
  cairo_matrix_t cm_display, cm_field, cm_panel;

  int missed_frames = 0;

  int running = true;
  int subdiv  = 1;

  struct part part = {
    NULL, NULL, NULL, NULL, PATH_MOVE, 0, 0, 0, 0
  };

  struct path_segment *segment = (struct path_segment *)
    &part.paths.segments.base; /* first segment of the first path */
  struct path         *path    = &part.paths;

  struct pos *pen = &part.paths.segments.p;

  /* SETUP */

  SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);

  { /* acquire video information */
    /* TODO: correct pixel format */
    SDL_Rect **modes = SDL_ListModes(NULL, SDL_VIDEO_FLAGS);

    if (NULL == modes) {
      fprintf(stderr, "no video modes available\n");
      exit(0);
    }

    if ( (SDL_Rect **) -1 == modes ) {
      hres = 640;
      vres = 480;
    } else {
      hres = modes[0]->w;
      vres = modes[0]->h;
    }

    width  = hres;
    height = vres;
    aspect = (double) hres / vres;
    pixels = hres * vres;
    scale  = sqrt(pixels);

    /* TODO: cap resolution if possible */
  }

  sdl_surface = SDL_SetVideoMode(hres, vres, 32, SDL_VIDEO_FLAGS);

  { /* Cairo */
    cairo_surface_t *cr_surface;
    cr_surface = cairo_image_surface_create_for_data(
        sdl_surface->pixels,
        CAIRO_FORMAT_RGB24,
        sdl_surface->w,
        sdl_surface->h,
        sdl_surface->pitch );
    cr = cairo_create(cr_surface);
    cairo_surface_destroy(cr_surface);
  }

  { /* screen-space transformation */
    cairo_matrix_t *m = &cm_display;

    cairo_matrix_init_identity(m);

    /* Cartesian */
    cairo_matrix_translate(m, hres/2.0, vres/2.0);
    cairo_matrix_scale(m, 1, -1);

    /* fixed scale */
    cairo_matrix_scale(m,
        scale * hres / width,
        scale * vres / height );
  }

  { /* field transformation */
    cairo_matrix_t *m = &cm_field;

    double scale = 1.0 / (2.0) / aspect;

    cairo_matrix_init_identity(m);
    cairo_matrix_multiply(m, m, &cm_display);

    cairo_matrix_scale(m, scale, scale);
  }

  { /* delay */
    Uint32 now = SDL_GetTicks();

    next_frame = now + 1000.0 / FRAMERATE;
  }

  fprintf(stderr, "-- MARK -- setup complete\n");

  SDL_LockSurface(sdl_surface);

  while (running) {

    { /* Render Frame */

      /* clear screen */
      cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
      cairo_paint(cr);
      cairo_set_operator(cr, CAIRO_OPERATOR_OVER);

      /* Render Field */

      cairo_set_matrix(cr, &cm_field);

      render_1x1_box(cr);
      render_part(cr, &part);
      render_dots(cr, subdiv);
      render_pen(cr, pen);
    }

    { /* Update Display */
      SDL_UnlockSurface(sdl_surface);
      SDL_Flip(sdl_surface);
      SDL_LockSurface(sdl_surface);
    }

    { /* Delay */
      Uint32 now = SDL_GetTicks();

      if (now < next_frame) {
        missed_frames = 0;
        SDL_Delay(next_frame - now);
        next_frame = next_frame + 1000.0 / FRAMERATE;
      } else {
        missed_frames = missed_frames + 1;
        if (1 + TOLERATE_N_MISSED_FRAMES == missed_frames) {
          fprintf(stderr, "delay counter reset\n");
          next_frame = now + 1000.0 / FRAMERATE;
        } else {
          next_frame = next_frame + 1000.0 / FRAMERATE;
        }
      }
    }

    { /* Handle Events */
      SDL_Event event;

      while ( SDL_PollEvent(&event) ) {
        switch (event.type) {
          case SDL_QUIT:
            running = 0;
            break;
          case SDL_KEYDOWN:
            switch (event.key.keysym.sym) {
              case SDLK_q:
                running = 0;
                break;
              case SDLK_1:
                subdiv = 1;
                break;
              case SDLK_2:
                subdiv = 2;
                break;
              case SDLK_3:
                subdiv = 3;
                break;
              case SDLK_4:
                subdiv = 4;
                break;
              case SDLK_LEFT:
                pen->x = pen->x - 1.0 / (1 << subdiv);
                break;
              case SDLK_RIGHT:
                pen->x = pen->x + 1.0 / (1 << subdiv);
                break;
              case SDLK_DOWN:
                pen->y = pen->y - 1.0 / (1 << subdiv);
                break;
              case SDLK_UP:
                pen->y = pen->y + 1.0 / (1 << subdiv);
                break;
              case SDLK_RETURN:
                segment = (struct path_segment *)
                  path_segment_line_append(segment, &pen);
                fprintf(stderr, "-- MARK -- new segment created\n");
                break;
              case SDLK_c:
                path->color = 1 - path->color;
                break;
              case SDLK_f:
                path->fill  = 1 - path->fill;
                break;
            }
            break;
        }
      }
    }

  }

  SDL_UnlockSurface(sdl_surface);

  /* CLEANUP */

  cairo_destroy(cr);
  SDL_Quit();

  return 0;
}
Example #8
0
static gint OnImageCheckButtonClicked(GtkWidget *widget, GdkEventButton *event, gpointer data)
{
	IMAGE_CHECK_BUTTON* button = (IMAGE_CHECK_BUTTON*)data;
	GdkPixbuf* pixbuf;
	gint width, height;
	uint8* pixels;
	int i, j;

	button->state = !button->state;

	pixbuf = gtk_image_get_pixbuf(GTK_IMAGE(button->image));
	width = gdk_pixbuf_get_width(pixbuf);
	height = gdk_pixbuf_get_height(pixbuf);
	pixels = gdk_pixbuf_get_pixels(pixbuf);
	(void)memset(pixels, 0, height * width * 3);
	for(i=0; i<CHECK_BUTTON_BORDER_WIDTH; i++)
	{
		for(j=0; j<width; j++)
		{
			pixels[i*width*4+j*4+3] = 0xff;
		}
	}
	for(i=height-CHECK_BUTTON_BORDER_WIDTH; i<height; i++)
	{
		for(j=0; j<width; j++)
		{
			pixels[i*width*4+j*4+3] = 0xff;
		}
	}
	for(i=CHECK_BUTTON_BORDER_WIDTH; i<height-CHECK_BUTTON_BORDER_WIDTH; i++)
	{
		(void)memset(&pixels[i*width*4+CHECK_BUTTON_BORDER_WIDTH*4], 0xff,
			(width - CHECK_BUTTON_BORDER_WIDTH*2) * 4);
		for(j=0; j<CHECK_BUTTON_BORDER_WIDTH; j++)
		{
			pixels[i*width*4+j*4+3] = 0xff;
		}
		for(j=width-CHECK_BUTTON_BORDER_WIDTH; j<width; j++)
		{
			pixels[i*width*4+j*4+3] = 0xff;
		}
	}

	if(button->state != 0)
	{
		cairo_surface_t* surface_p = cairo_image_surface_create_for_data(
			pixels, CAIRO_FORMAT_ARGB32, width, height, width*4);
		cairo_t* cairo_p = cairo_create(surface_p);
		
		gdk_cairo_set_source_pixbuf(cairo_p, button->pixbuf, 0, 0);
		cairo_paint(cairo_p);

		cairo_destroy(cairo_p);
		cairo_surface_destroy(surface_p);

		// WindowsならRGB→BGR
#if defined(USE_BGR_COLOR_SPACE) && USE_BGR_COLOR_SPACE != 0
		{
			uint8 r;
			for(i=0; i<width*height; i++)
			{
				r = pixels[i*4];
				pixels[i*4] = pixels[i*4+2];
				pixels[i*4+2] = r;
			}
		}
#endif
	}

	if(button->func != NULL)
	{
		(void)button->func(button, button->data);
	}

	gtk_image_set_from_pixbuf(GTK_IMAGE(button->image), pixbuf);

	// イメージの再描画
#if GTK_MAJOR_VERSION <= 2
	if(button->image->window != NULL)
	{
		gdk_window_process_updates(button->image->window, FALSE);
	}
#else
	if(gtk_widget_get_window(button->image) != NULL)
	{
		gdk_window_process_updates(gtk_widget_get_window(button->image), FALSE);
	}
#endif

	return TRUE;
}
Example #9
0
void drvCAIRO::show_image(const PSImage & image)
{
  // first retrieve bounding box
  Point lowerLeft, upperRight;
  image.getBoundingBox(lowerLeft, upperRight);
  
  // not only bounding box must account for scale,
  // but also transformation matrix!

  // scale bounding box
  lowerLeft.x_ *= getScale();
  lowerLeft.y_ *= getScale();
  upperRight.x_ *= getScale();
  upperRight.y_ *= getScale();

  const long width  = abs(i_transX(upperRight.x_) - i_transX(lowerLeft.x_));
  const long height = abs(i_transY(upperRight.y_) - i_transY(lowerLeft.y_));
  
  if (Verbose()) {
    errf << "image.Width:" << image.width << " image.Height: " << image.height << endl;
    errf << "Width:" << width << " Height: " << height << endl;
  }
  
#if 0

  // This is an example of how to take image data and get it into a cairo surface.
  // If I ever figure out the pstoedit end, I can try one of these.
  int stride;
  unsigned char *data;
  cairo_surface_t *surface;
  g_double w, h;
    /*
    CAIRO_FORMAT_ARGB32,
    CAIRO_FORMAT_RGB24,
    CAIRO_FORMAT_A8,
    CAIRO_FORMAT_A1
  */

  stride = cairo_format_stride_for_width (format, width);
  data = malloc (stride * height);
  surface = cairo_image_surface_create_for_data (data, format,
						 width, height,
						 stride);
  surface = cairo_image_surface_create_from_png_stream (data, format,
						 width, height,
						 stride);
#endif


  // calc long-padded size of scanline 
  const long scanlineLen = ((width * 3) + 3) & ~3L;

  // now lets get some mem
  unsigned char *const output = new unsigned char[scanlineLen * height];

  for (long i = 0; i < scanlineLen * height; i++)
    output[i] = 255;		// default is background (white)    
  
  if (!output) {
    errf << "ERROR: Cannot allocate memory for image" << endl;
    return;
  }
  // setup inverse transformation matrix (scaled, too!)
  const float matrixScale(image.normalizedImageCurrentMatrix[0] *
			  image.normalizedImageCurrentMatrix[3] -
			  image.normalizedImageCurrentMatrix[2] *
			  image.normalizedImageCurrentMatrix[1]);
  const float inverseMatrix[] = {
    image.normalizedImageCurrentMatrix[3] / matrixScale / getScale(),
    -image.normalizedImageCurrentMatrix[1] / matrixScale / getScale(),
    -image.normalizedImageCurrentMatrix[2] / matrixScale / getScale(),
    image.normalizedImageCurrentMatrix[0] / matrixScale / getScale(),
    (image.normalizedImageCurrentMatrix[2] *
     image.normalizedImageCurrentMatrix[5] -
     image.normalizedImageCurrentMatrix[4] *
     image.normalizedImageCurrentMatrix[3]) / matrixScale,
    (image.normalizedImageCurrentMatrix[4] *
     image.normalizedImageCurrentMatrix[1] -
     image.normalizedImageCurrentMatrix[0] *
     image.normalizedImageCurrentMatrix[5]) / matrixScale
  };

  // now transform image
  for (long ypos = 0; ypos < height; ypos++) {
    // buffer current output scanline (saves us some multiplications)
    unsigned char *const currOutput = &output[scanlineLen * ypos];
    
    for (long xpos = 0; xpos < width; xpos++) {
      // now transform from device coordinate space to image space
      
      // apply transformation
      const Point currPoint = Point(xpos + lowerLeft.x_,
				    ypos + lowerLeft.y_).transform(inverseMatrix);
      
      // round to integers
      const long sourceX = (long) (currPoint.x_ + .5);
      const long sourceY = (long) (currPoint.y_ + .5);
      
      // is the pixel out of bounds? If yes, no further processing necessary
      if (sourceX >= 0L && (unsigned long) sourceX < image.width &&
	  sourceY >= 0L && (unsigned long) sourceY < image.height) {
	// okay, fetch source pixel value into 
	// RGB triplet
	
	unsigned char r(255), g(255), b(255), c, m, y, k;
	
	// how many components?
	switch (image.ncomp) {
	case 1:
	  r = g = b = image.getComponent(sourceX, sourceY, 0);
	  break;
	  
	case 3:
	  r = image.getComponent(sourceX, sourceY, 0);
	  g = image.getComponent(sourceX, sourceY, 1);
	  b = image.getComponent(sourceX, sourceY, 2);
	  break;
	  
	case 4:
	  c = image.getComponent(sourceX, sourceY, 0);
	  m = image.getComponent(sourceX, sourceY, 1);
	  y = image.getComponent(sourceX, sourceY, 2);
	  k = image.getComponent(sourceX, sourceY, 3);
	  
	  // account for key
	  c += k;
	  m += k;
	  y += k;
	  
	  // convert color
	  r = 255 - c;
	  g = 255 - m;
	  b = 255 - y;
	  break;
	  
	default:
	  errf << "\t\tFatal: unexpected case in drvcairo (line "
	       << __LINE__ << ")" << endl;
	  abort();
	  return;
	}
	
	// set color triple
	currOutput[3 * xpos] = b;
	currOutput[3 * xpos + 1] = g;
	currOutput[3 * xpos + 2] = r;
      }
    }
  }
  
  delete[]output;
}
//--------------------------------------------
void ofCairoRenderer::draw(const ofPixels & raw, float x, float y, float z, float w, float h, float sx, float sy, float sw, float sh) const{
	bool shouldCrop = sx != 0 || sy != 0 || sw != w || sh != h;
	ofPixels cropped;
	if(shouldCrop) {
		cropped.allocate(sw, sh, raw.getPixelFormat());
		raw.cropTo(cropped, sx, sy, sw, sh);
	}
	const ofPixels & pix = shouldCrop ? cropped : raw;

	ofCairoRenderer * mut_this = const_cast<ofCairoRenderer*>(this);
	mut_this->pushMatrix();
	mut_this->translate(x,y,z);
	mut_this->scale(w/pix.getWidth(),h/pix.getHeight());
	cairo_surface_t *image;
	int stride=0;
	int picsize = pix.getWidth()* pix.getHeight();
	const unsigned char *imgPix = pix.getData();

	vector<unsigned char> swapPixels;

	switch(pix.getImageType()){
	case OF_IMAGE_COLOR:
#ifdef TARGET_LITTLE_ENDIAN
		swapPixels.resize(picsize * 4);

		for(int p= 0; p<picsize; p++) {
			swapPixels[p*4] = imgPix[p*3 +2];
			swapPixels[p*4 +1] = imgPix[p*3 +1];
			swapPixels[p*4 +2] = imgPix[p*3];
		}
#else
		swapPixels.resize(picsize * 4);

		for(int p= 0; p<picsize; p++) {
			swapPixels[p*4] = imgPix[p*3];
			swapPixels[p*4 +1] = imgPix[p*3 +1];
			swapPixels[p*4 +2] = imgPix[p*3 +2];
		}
#endif
		stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, pix.getWidth());
		image = cairo_image_surface_create_for_data(&swapPixels[0], CAIRO_FORMAT_RGB24, pix.getWidth(), pix.getHeight(), stride);
		break;
	case OF_IMAGE_COLOR_ALPHA:
#ifdef TARGET_LITTLE_ENDIAN
		swapPixels.resize(picsize * 4);

		for(int p= 0; p<picsize; p++) {
			swapPixels[p*4] = imgPix[p*4+2];
			swapPixels[p*4 +1] = imgPix[p*4+1];
			swapPixels[p*4 +2] = imgPix[p*4];
			swapPixels[p*4 +3] = imgPix[p*4+3];
		}
		stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, pix.getWidth());
		image = cairo_image_surface_create_for_data(&swapPixels[0], CAIRO_FORMAT_ARGB32, pix.getWidth(), pix.getHeight(), stride);
#else
		stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, pix.getWidth());
		image = cairo_image_surface_create_for_data(pix.getData(), CAIRO_FORMAT_ARGB32, pix.getWidth(), pix.getHeight(), stride);
#endif
		break;
	case OF_IMAGE_GRAYSCALE:
		swapPixels.resize(picsize * 4);

		for(int p= 0; p<picsize; p++) {
			swapPixels[p*4] = imgPix[p];
			swapPixels[p*4 +1] = imgPix[p];
			swapPixels[p*4 +2] = imgPix[p];
		}
		stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, pix.getWidth());
		image = cairo_image_surface_create_for_data(&swapPixels[0], CAIRO_FORMAT_RGB24, pix.getWidth(), pix.getHeight(), stride);
		break;
	case OF_IMAGE_UNDEFINED:
	default:
		ofLogError("ofCairoRenderer") << "draw(): trying to draw undefined image type " << pix.getImageType();
		mut_this->popMatrix();
		return;
		break;
	}
	cairo_set_source_surface (cr, image, 0,0);
	cairo_paint (cr);
	cairo_surface_flush(image);
	cairo_surface_destroy (image);
	mut_this->popMatrix();
}
Example #11
0
cairo_surface_t* cairocks_distance_field_create(
	cairo_surface_t* surface,
	int              scan_size,
	int              block_size
) {
	int surface_width  = cairo_image_surface_get_width(surface);
	int surface_height = cairo_image_surface_get_height(surface);
	int width          = surface_width / block_size;
	int height         = surface_height / block_size;

	double* distances = 0;

	unsigned char* output = 0;

	int x;
	int y;
	int stride;

	double mind  = 0.0f;
	double maxd  = 0.0f;
	double scale = 0.0f;

	/* Image MUST be square (for now). */
	if(surface_width != surface_height) return 0;

	/* Furthermore, the image must be evenly divisible by the block_size. */
	if(surface_width % block_size) return 0;

	distances = (double*)(malloc(width * height * sizeof(double)));

	for(x = 0; x < width; x++) {
		for(y = 0; y < height; y++) {
			distances[(x * width) + y] = find_signed_distance(
				(x * block_size) + (block_size / 2),
				(y * block_size) + (block_size / 2),
				surface,
				scan_size,
				scan_size
			);
		}
	}

	for(x = 0; x < width; x++) {
		for(y = 0; y < height; y++) {
			double d = distances[(x * width) + y];

			if(d != MAX_VALUE && d > maxd) maxd = d;
		}
	}

	for(x = 0; x < width; x++) {
		for(y = 0; y < height; y++) {
			double d = distances[(x * width) + y];

			if(d != MIN_VALUE && d < mind) mind = d;
		}
	}

	scale = max(fabs(mind), fabs(maxd));

	for(x = 0; x < width; x++) {
		for(y = 0; y < height; y++) {
			double d = distances[(x * width) + y];

			if(d == MAX_VALUE) d = 1.0f;

			else if (d == MIN_VALUE) d = 0.0f;

			else {
				d /= scale;
				d /= 2.0f;
				d += 0.5f;
			}

			distances[(x * width) + y] = d;
		}
	}

	/* Here is where things get tricky. Since we use A8 surface, the stride may actually
	be bigger than what we expect, so we'll need to make sure we set the data appropriately. */
	stride = cairo_format_stride_for_width(CAIRO_FORMAT_A8, width);
	output = (unsigned char*)(malloc(stride * height));

	memset(output, 0, stride * height);

	for(x = 0; x < width; x++) {
		for(y = 0; y < height; y++) {
			unsigned int    offset = (x * width) + y;
			volatile double d      = distances[offset];

			if(d != d) d = 0.0f;

			output[offset + (x * (stride - width))] = (unsigned char)(floor(d * 255));
		}
	}

	free(distances);

	return cairo_image_surface_create_for_data(output, CAIRO_FORMAT_A8, width, height, stride);
}
void ofCairoRenderer::setup(string _filename, Type _type, bool multiPage_, bool b3D_, ofRectangle _viewport){
	if( _viewport.width == 0 || _viewport.height == 0 ){
		_viewport.set(0, 0, ofGetViewportWidth(), ofGetViewportHeight());
	}

	filename = _filename;
	type = _type;
	streamBuffer.clear();

	if(type == FROM_FILE_EXTENSION){
		string ext = ofFilePath::getFileExt(filename);
		if(ofToLower(ext)=="svg"){
			type = SVG;
		}else if(ofToLower(ext)=="pdf"){
			type = PDF;
		}else{ // default to image
			type = IMAGE;
		}
	}

	if(filename != "") {
		switch(type) {
			case PDF:
			case SVG:
			case IMAGE:
				ofFilePath::createEnclosingDirectory(filename);
			case FROM_FILE_EXTENSION:
				break;
		}
	}

	switch(type){
	case PDF:
		if(filename==""){
			surface = cairo_pdf_surface_create_for_stream(&ofCairoRenderer::stream_function,this,_viewport.width, _viewport.height);
		}else{
			surface = cairo_pdf_surface_create(ofToDataPath(filename).c_str(),_viewport.width, _viewport.height);
		}
		break;
	case SVG:
		if(filename==""){
			surface = cairo_svg_surface_create_for_stream(&ofCairoRenderer::stream_function,this,_viewport.width, _viewport.height);
		}else{
			surface = cairo_svg_surface_create(ofToDataPath(filename).c_str(),_viewport.width, _viewport.height);
		}
		break;
	case IMAGE:
		imageBuffer.allocate(_viewport.width, _viewport.height, OF_PIXELS_BGRA);
		imageBuffer.set(0);
		surface = cairo_image_surface_create_for_data(imageBuffer.getData(),CAIRO_FORMAT_ARGB32,_viewport.width, _viewport.height,_viewport.width*4);
		break;
	case FROM_FILE_EXTENSION:
		ofLogFatalError("ofCairoRenderer") << "setup(): couldn't determine type from extension for filename: \"" << _filename << "\"!";
		break;
	default:
		ofLogError("ofCairoRenderer") << "setup(): encountered unknown type for filename \"" << _filename << "\"";
		break;
	}

	cr = cairo_create(surface);
	cairo_set_antialias(cr,CAIRO_ANTIALIAS_SUBPIXEL);
	viewportRect = _viewport;
	originalViewport = _viewport;
	viewport(viewportRect);
	page = 0;
	b3D = b3D_;
	multiPage = multiPage_;
	setStyle(currentStyle);
	clear();
}
Example #13
0
/* This function is adapted from Gtk's gdk_cairo_set_source_pixbuf() you can
 * find in gdk/gdkcairo.c.
 * Copyright (C) Red Had, Inc.
 * LGPLv2+ */
static cairo_surface_t *
_cairo_new_surface_from_pixbuf (const GdkPixbuf *pixbuf)
{
  int              width         = gdk_pixbuf_get_width (pixbuf);
  int              height        = gdk_pixbuf_get_height (pixbuf);
  guchar          *gdk_pixels    = gdk_pixbuf_get_pixels (pixbuf);
  int              gdk_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
  int              n_channels    = gdk_pixbuf_get_n_channels (pixbuf);
  int              cairo_stride;
  guchar          *cairo_pixels;

  cairo_format_t   format;
  cairo_surface_t *surface;
  static const     cairo_user_data_key_t key;
  int              j;

  if (n_channels == 3)
    format = CAIRO_FORMAT_RGB24;
  else
    format = CAIRO_FORMAT_ARGB32;

  cairo_stride = cairo_format_stride_for_width (format, width);
  cairo_pixels = g_malloc (height * cairo_stride);
  surface = cairo_image_surface_create_for_data ((unsigned char *)cairo_pixels,
                                                 format,
                                                 width, height, cairo_stride);

  cairo_surface_set_user_data (surface, &key,
			       cairo_pixels, (cairo_destroy_func_t)g_free);

  for (j = height; j; j--)
    {
      guchar *p = gdk_pixels;
      guchar *q = cairo_pixels;

      if (n_channels == 3)
	      {
          guchar *end = p + 3 * width;

          while (p < end)
            {
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
              q[0] = p[2];
              q[1] = p[1];
              q[2] = p[0];
#else
              q[1] = p[0];
              q[2] = p[1];
              q[3] = p[2];
#endif
              p += 3;
              q += 4;
            }
	      }
      else
        {
          guchar *end = p + 4 * width;
          guint t1,t2,t3;

#define MULT(d,c,a,t) G_STMT_START { t = c * a + 0x7f; d = ((t >> 8) + t) >> 8; } G_STMT_END

          while (p < end)
            {
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
              MULT(q[0], p[2], p[3], t1);
              MULT(q[1], p[1], p[3], t2);
              MULT(q[2], p[0], p[3], t3);
              q[3] = p[3];
#else
              q[0] = p[3];
              MULT(q[1], p[0], p[3], t1);
              MULT(q[2], p[1], p[3], t2);
              MULT(q[3], p[2], p[3], t3);
#endif

              p += 4;
              q += 4;
            }

#undef MULT
        }

      gdk_pixels += gdk_rowstride;
      cairo_pixels += cairo_stride;
    }
  return surface;
}
Example #14
0
static void _view_map_post_expose(cairo_t *cri, int32_t width_i, int32_t height_i,
                                  int32_t pointerx, int32_t pointery, gpointer user_data)
{
  const int ts = 64;
  OsmGpsMapPoint bb[2], *l=NULL, *center=NULL;
  int px,py;
  dt_map_t *lib = (dt_map_t *)user_data;

  /* get bounding box coords */
  osm_gps_map_get_bbox(lib->map, &bb[0], &bb[1]);
  float bb_0_lat = 0.0, bb_0_lon = 0.0, bb_1_lat = 0.0, bb_1_lon = 0.0;
  osm_gps_map_point_get_degrees(&bb[0], &bb_0_lat, &bb_0_lon);
  osm_gps_map_point_get_degrees(&bb[1], &bb_1_lat, &bb_1_lon);

  /* make the bounding box a little bigger to the west and south */
  float lat0 = 0.0, lon0 = 0.0, lat1 = 0.0, lon1 = 0.0;
  OsmGpsMapPoint *pt0 = osm_gps_map_point_new_degrees(0.0, 0.0), *pt1 = osm_gps_map_point_new_degrees(0.0, 0.0);
  osm_gps_map_convert_screen_to_geographic(lib->map, 0, 0, pt0);
  osm_gps_map_convert_screen_to_geographic(lib->map, 1.5*ts, 1.5*ts, pt1);
  osm_gps_map_point_get_degrees(pt0, &lat0, &lon0);
  osm_gps_map_point_get_degrees(pt1, &lat1, &lon1);
  osm_gps_map_point_free(pt0);
  osm_gps_map_point_free(pt1);
  double south_border = lat0 - lat1, west_border = lon1 - lon0;

  /* get map view state and store  */
  int zoom = osm_gps_map_get_zoom(lib->map);
  center = osm_gps_map_get_center(lib->map);
  dt_conf_set_float("plugins/map/longitude", center->rlon);
  dt_conf_set_float("plugins/map/latitude", center->rlat);
  dt_conf_set_int("plugins/map/zoom", zoom);
  osm_gps_map_point_free(center);

  /* let's reset and reuse the main_query statement */
  DT_DEBUG_SQLITE3_CLEAR_BINDINGS(lib->statements.main_query);
  DT_DEBUG_SQLITE3_RESET(lib->statements.main_query);

  /* bind bounding box coords for the main query */
  DT_DEBUG_SQLITE3_BIND_DOUBLE(lib->statements.main_query, 1, bb_0_lon - west_border);
  DT_DEBUG_SQLITE3_BIND_DOUBLE(lib->statements.main_query, 2, bb_1_lon);
  DT_DEBUG_SQLITE3_BIND_DOUBLE(lib->statements.main_query, 3, bb_0_lat);
  DT_DEBUG_SQLITE3_BIND_DOUBLE(lib->statements.main_query, 4, bb_1_lat - south_border);

  /* query collection ids */
  while(sqlite3_step(lib->statements.main_query) == SQLITE_ROW)
  {
    int32_t imgid = sqlite3_column_int(lib->statements.main_query, 0);

    cairo_set_source_rgba(cri, 0, 0, 0, 0.4);

    /* free l if allocated */
    if (l)
      osm_gps_map_point_free(l);

    /* for each image check if within bbox */
    const dt_image_t *cimg = dt_image_cache_read_get(darktable.image_cache, imgid);
    double longitude = cimg->longitude;
    double latitude  = cimg->latitude;
    dt_image_cache_read_release(darktable.image_cache, cimg);
    if(isnan(latitude) || isnan(longitude))
      continue;
    l = osm_gps_map_point_new_degrees(latitude, longitude);

    /* translate l into screen coords */
    osm_gps_map_convert_geographic_to_screen(lib->map, l, &px, &py);

    /* dependent on scale draw different overlays */
    if (zoom >= 14)
    {
      dt_mipmap_buffer_t buf;
      dt_mipmap_size_t mip = dt_mipmap_cache_get_matching_size(darktable.mipmap_cache, ts, ts);
      dt_mipmap_cache_read_get(darktable.mipmap_cache, &buf, imgid, mip, 0);

      cairo_surface_t *surface = NULL;
      if(buf.buf)
      {
        float ms = fminf(
                     ts/(float)buf.width,
                     ts/(float)buf.height);

#if 0
        // this doesn't work since osm-gps-map always gives 0/0 as mouse coords :(
        /* find out if the cursor is over the image */
        if(pointerx >= px && pointerx <= (px + buf.width*ms + 4) && pointery <= (py - 8) && pointery >= (py - buf.height*ms - 8 - 4))
        {
          printf("over\n");
          cairo_set_source_rgba(cri, 1, 0, 0, 0.7);
        }
//         else
//           printf("%d/%d, %d/%d\n", px, py, pointerx, pointery);
#endif
        const int32_t stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, buf.width);
        surface = cairo_image_surface_create_for_data (buf.buf, CAIRO_FORMAT_RGB24,
                  buf.width, buf.height, stride);

        cairo_pattern_set_filter(cairo_get_source(cri), CAIRO_FILTER_NEAREST);
        cairo_save(cri);

        /* first of lets draw a pin */
        cairo_move_to(cri, px, py);
        cairo_line_to(cri, px+8, py-8);
        cairo_line_to(cri, px+4, py-8);
        cairo_fill(cri);

        /* and the frame around image */
        cairo_move_to(cri, px+2, py-8);
        cairo_line_to(cri, px+2 + (buf.width*ms) + 4, py-8);
        cairo_line_to(cri, px+2 + (buf.width*ms) + 4 , py-8-(buf.height*ms) - 4);
        cairo_line_to(cri, px+2 , py-8-(buf.height*ms) - 4);
        cairo_fill(cri);


        /* draw image*/
        cairo_translate(cri, px+4, py - 8 - (buf.height*ms) - 2);
        cairo_scale(cri, ms, ms);
        cairo_set_source_surface (cri, surface, 0, 0);
        cairo_paint(cri);

        cairo_restore(cri);

        cairo_surface_destroy(surface);

      }
    }
    else
    {
      /* just draw a patch indicating that there is images at the location */
      cairo_rectangle(cri, px-8, py-8, 16, 16);
      cairo_fill(cri);
    }
  }

}
Example #15
0
static gboolean
dt_iop_zonesystem_preview_expose (GtkWidget *widget, GdkEventExpose *event, dt_iop_module_t *self)
{
  const int inset = 2;
  int width = widget->allocation.width, height = widget->allocation.height;

  dt_iop_zonesystem_gui_data_t *g = (dt_iop_zonesystem_gui_data_t *)self->gui_data;
  dt_iop_zonesystem_params_t *p = (dt_iop_zonesystem_params_t *)self->params;

  cairo_surface_t *cst = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
  cairo_t *cr = cairo_create(cst);

  /* clear background */
  GtkStateType state = gtk_widget_get_state(self->expander);
  GtkStyle *style = gtk_widget_get_style(self->expander);
  cairo_set_source_rgb (cr, style->bg[state].red/65535.0, style->bg[state].green/65535.0, style->bg[state].blue/65535.0);
  cairo_paint (cr);

  width -= 2*inset;
  height -= 2*inset;
  cairo_translate(cr, inset, inset);

  dt_pthread_mutex_lock(&g->lock);
  if( g->preview_buffer && self->enabled)
  {
    /* calculate the zonemap */
    float zonemap[MAX_ZONE_SYSTEM_SIZE]= {-1};
    _iop_zonesystem_calculate_zonemap (p,zonemap);

    /* let's generate a pixbuf from pixel zone buffer */
    guchar *image = g_malloc ((g->preview_width*g->preview_height)*4);
    for (int k=0; k<g->preview_width*g->preview_height; k++)
    {
      int zone = 255*CLIP (((1.0/(p->size-1))*g->preview_buffer[k]));
      image[4*k+2] = (g->hilite_zone && g->preview_buffer[k]==g->zone_under_mouse)?255:zone;
      image[4*k+1] = (g->hilite_zone && g->preview_buffer[k]==g->zone_under_mouse)?255:zone;
      image[4*k+0] = (g->hilite_zone && g->preview_buffer[k]==g->zone_under_mouse)?0:zone;
    }
    dt_pthread_mutex_unlock(&g->lock);

    const int wd = g->preview_width, ht = g->preview_height;
    const float scale = fminf(width/(float)wd, height/(float)ht);
    const int stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, wd);
    cairo_surface_t *surface = cairo_image_surface_create_for_data (image, CAIRO_FORMAT_RGB24, wd, ht, stride);
    cairo_translate(cr, width/2.0, height/2.0f);
    cairo_scale(cr, scale, scale);
    cairo_translate(cr, -.5f*wd, -.5f*ht);

    cairo_rectangle(cr, 1, 1, wd-2, ht-2);
    cairo_set_source_surface (cr, surface, 0, 0);
    cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_GOOD);
    cairo_fill_preserve(cr);
    cairo_surface_destroy (surface);

    cairo_set_line_width(cr, 1.0);
    cairo_set_source_rgb(cr, .1, .1, .1);
    cairo_stroke(cr);

    g_free(image);
  }
  else
    dt_pthread_mutex_unlock(&g->lock);

  cairo_destroy(cr);
  cairo_t *cr_pixmap = gdk_cairo_create(gtk_widget_get_window(widget));
  cairo_set_source_surface (cr_pixmap, cst, 0, 0);
  cairo_paint(cr_pixmap);
  cairo_destroy(cr_pixmap);
  cairo_surface_destroy(cst);

  return TRUE;
}
Example #16
0
int main(int argc, char** argv) {

  int c;
  float col_r, col_g, col_b = -1.0f;
  Options opt;

  while ((c = getopt(argc, argv, "a:x:y:f:s:t:n:w:r:g:b:c:h:i:j:o:v")) != -1) {
    switch(c) {
      /* verbose */
      /* ------------------------------------------------------- */
      case 'v': {
        opt.verbose = 0;
        break;
      }

      /* color */
      /* ------------------------------------------------------- */
      case 'r': {
        col_r = convert_type<float>(optarg);
        break;
      }
      case 'g': {
        col_g = convert_type<float>(optarg);
        break;
      }
      case 'b': {
        col_b = convert_type<float>(optarg);
        break;
      }

      /* ------------------------------------------------------- */
      /* hashtag */
      case 'h': {
        opt.hashtag = convert_type<std::string>(optarg);
        break;
      }
      case 'i': {
        opt.hashtag_x = convert_type<int>(optarg);
        break;
      }
      case 'j': {
        opt.hashtag_y = convert_type<int>(optarg);
        break;
      }
      
      /* ------------------------------------------------------- */
      /* foreground */
      case 'c': {
        opt.foreground_file = convert_type<std::string>(optarg);
        break;
      }
      /* ------------------------------------------------------- */
      /* background */
      case 'x': {
        opt.background_x = convert_type<int>(optarg);
        break;
      }
      case 'y': {
        opt.background_y = convert_type<int>(optarg);
        break;
      }
      case 'f': {
        opt.background_file = convert_type<std::string>(optarg);
        break;
      }

      /* ------------------------------------------------------- */
      /* visible size */
      case 'a': {
        opt.visible_size = convert_type<float>(optarg);
        break;
      }

      /* ------------------------------------------------------- */
      /* output */
      case 'o': {
        opt.output_file = convert_type<std::string>(optarg);
        break;
      }

      /* ------------------------------------------------------- */
      /* name */
      case 'n': {
        opt.name = convert_type<std::string>(optarg);

        /* we expect that r,g,b has been set */
        if (0 > col_r) {
          printf("Error: you haven't set -r -g -b for the name.\n");
          exit(EXIT_FAILURE);
        }
        opt.name_r = col_r;
        opt.name_g = col_g;
        opt.name_b = col_b;
        break;
      }
      /* name x position */
      case 's': {
        opt.name_x = convert_type<int>(optarg);
        break;
      }
      /* name y position */
      case 't': {
        opt.name_y = convert_type<int>(optarg);
        break;
      }
      /* name font size */
      case 'w': {
        opt.name_font_size = convert_type<float>(optarg);
        break;
      }
      default: {
        printf("Unkown option\n");
        break;
      }
    }
  }
  
  if (false == opt.validate()) {
    printf("+ error: cannot validate the given options.\n");
    exit(EXIT_FAILURE);
  }

  opt.print();

  /* ------------------------------------------------------------------------------------ */

  Image img;
  std::string path;
  std::string ext;
  cairo_surface_t* surf_bg = NULL;
  cairo_format_t img_format = CAIRO_FORMAT_INVALID;

  path = opt.foreground_file;
  if (false == rx_file_exists(path)) {
    printf("+ error: cannot find the file: %s\n", path.c_str());
    exit(EXIT_FAILURE);
  }

  cairo_surface_t* surf_overlay = cairo_image_surface_create_from_png(path.c_str());
  if (NULL == surf_overlay) {
    printf("Error: cannot create s1\n");
    exit(EXIT_FAILURE);
  }

  path = opt.background_file;
  if (false == rx_file_exists(path)) {
    printf("Error: file doesn't exist: %s\n", path.c_str());
    exit(EXIT_FAILURE);
  }
  
  /* check what file type was given. */
  ext = rx_get_file_ext(path);
  if (ext == "jpg") {

    printf("+ warning: jpg as input doesn't seem to work\n");

    /* cairo doesn't have support for PNG? */
    if (0 > rx_load_jpg(path, &img.pixels, img.width, img.height, img.channels)) {
      printf("Error: failed to load: %s\n", path.c_str());
      exit(EXIT_FAILURE);
    }
    if (0 == img.width || 0 == img.height || 0 == img.channels) {
      printf("Error: image has invalid flags: %d x %d, channels: %d\n", img.width, img.height, img.channels);
      exit(EXIT_FAILURE);
    }

    if (3 == img.channels) {
      img_format = CAIRO_FORMAT_RGB24;
      printf("+ Using RGB24\n");
    }  
    else if(4 == img.channels) {
      img_format = CAIRO_FORMAT_ARGB32;
      printf("+ Using ARGB32\n");
    }
    else {
      printf("Error: unsupported number of channels: %d.\n", img.channels);
      exit(EXIT_FAILURE);
    }

    if (NULL != img.pixels && NULL == surf_bg) {

        printf("Stride: %d\n", cairo_format_stride_for_width(img_format, img.width));
        printf("Info: creating %d x %d, channels: %d\n", img.width, img.height, img.channels);

        surf_bg = cairo_image_surface_create_for_data(img.pixels, 
                                                      img_format, 
                                                      img.width, 
                                                      img.height, 
                                                      cairo_format_stride_for_width(img_format, img.width));

#if 0
      /* TESTING */
      cairo_t* cr = cairo_create(surf_bg);
      if (NULL == cr) { 
        printf("Error: cannot create the cairo");
        exit(EXIT_FAILURE);
      }
      path = rx_get_exe_path() +"/generated_polaroid.png";
      cairo_surface_write_to_png(surf_bg, path.c_str());
      printf("Created\n");
      exit(0);
      /* END TESTING */
#endif
    }
  }
  else if (ext == "png") {

    /* use cairo png load feature. */
    surf_bg = cairo_image_surface_create_from_png(path.c_str());
    if (NULL == surf_bg) {
      printf("Error: cannot create s2\n");
      exit(EXIT_FAILURE);
    }

  }
  else {
    printf("Error: unsupported file format: %s\n", ext.c_str());
    exit(EXIT_FAILURE);
  }


  /* make sure the background is loaded correctly (aka the photo) */
  if (NULL == surf_bg) {
    printf("Error: cannot create background surface.\n");
    exit(EXIT_FAILURE);
  }

  if (CAIRO_STATUS_SUCCESS != cairo_surface_status(surf_bg)) {
    printf("Error: something went wrong: %d\n", cairo_surface_status(surf_bg));
    exit(EXIT_FAILURE);
  }

  float source_width = cairo_image_surface_get_width(surf_bg);
  float source_height = cairo_image_surface_get_height(surf_bg);

  /* create output */
  int dest_width = cairo_image_surface_get_width(surf_overlay);
  int dest_height = cairo_image_surface_get_height(surf_overlay);

  if (0 == opt.verbose) {
    printf("+ Output size: %d x %d\n", dest_width, dest_height);
  }

  cairo_surface_t* surf_out = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, dest_width, dest_height);
  if (NULL == surf_out) {
    printf("Error: cannot create cairo_surface_t\n");
    exit(EXIT_FAILURE);
  }

  if (0 == opt.verbose) {
    printf("+ Info: creating output surface: %d x %d\n", dest_width, dest_height);
  }

  cairo_t* cr = cairo_create(surf_out);
  if (NULL == cr) { 
    printf("Error: cannot create the cairo");
    exit(EXIT_FAILURE);
  }

  float scale_factor = opt.visible_size / source_width;
  if (0 == opt.verbose) {
    printf("+ Scale factor: %f\n", scale_factor);
  }

  /* paint background */  
  cairo_save(cr);
  cairo_scale(cr, scale_factor, scale_factor);
  cairo_set_source_surface(cr, surf_bg, opt.background_x, opt.background_y);
  cairo_rectangle(cr, 0, 0, img.width, img.height);
  cairo_paint(cr);
  cairo_restore(cr);

  /* paint overlay */
  cairo_set_source_surface(cr, surf_overlay, 0, 0);
  cairo_paint(cr);
  cairo_surface_flush(surf_out);

  /* font settings. */
  cairo_font_options_t* font_options = cairo_font_options_create();
  if (NULL == font_options) {
    printf("+ Error: cannot create font options. Cannot create polaroid.\n");
    exit(EXIT_FAILURE);
  }
  

  cairo_font_options_set_antialias(font_options, CAIRO_ANTIALIAS_BEST);
  cairo_font_options_set_hint_metrics(font_options, CAIRO_HINT_METRICS_DEFAULT);
  cairo_set_font_options (cr, font_options);
  cairo_select_font_face(cr, "Platform", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
  cairo_set_source_rgba(cr, opt.name_r, opt.name_g, opt.name_b, 1.0); 

  /* name */
  if (0 != opt.name.size()) {
    cairo_move_to(cr, opt.name_x, opt.name_y);
    cairo_set_font_size(cr, opt.name_font_size);
    cairo_show_text(cr, opt.name.c_str());

    cairo_stroke(cr);
    cairo_fill(cr);
  }

  /* hashtag */
  if (0 != opt.hashtag.size()) {
    cairo_select_font_face(cr, "Platform", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
    cairo_move_to(cr, opt.hashtag_x, opt.hashtag_y);
    cairo_set_font_size(cr, opt.name_font_size);
    cairo_show_text(cr, opt.hashtag.c_str());

    cairo_stroke(cr);
    cairo_fill(cr);
  }

  cairo_surface_flush(surf_out);

  /* write out */
  path = opt.output_file;
  cairo_surface_write_to_png(surf_out, path.c_str());

  /* cleanup */
  cairo_surface_destroy(surf_out);
  cairo_surface_destroy(surf_bg);
  cairo_surface_destroy(surf_overlay);
  cairo_destroy(cr);
  
  if (0 == opt.verbose) {
    printf("\n");
  }
  return 0;
}
Example #17
0
  cairo_surface_t* LoadPNG(const std::string& filename)
  {
    std::FILE       *file;
    png_structp     png_ptr;
    png_infop       info_ptr;
    png_uint_32     width, height;
    int             bit_depth,color_type;
    int             channels,intent;
    double          screen_gamma;
    png_uint_32     rowbytes;
    png_bytepp      row_pointers=NULL;
    unsigned char   *image_data=NULL;
    unsigned char   *data;
    cairo_surface_t *image;
    bool            littleEndian;

    int endian=1;

    littleEndian=IsLowerByteSet((unsigned char*)&endian);

    /* open the file */
    file=std::fopen(filename.c_str(),"rb");

    if (file==NULL) {
      return NULL;
    }

    /* could pass pointers to user-defined error handlers instead of NULLs: */

    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
    if (!png_ptr) {
      std::fclose(file);
      return NULL;   /* out of memory */
    }

    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
      png_destroy_read_struct(&png_ptr,NULL,NULL);
      std::fclose(file);
      return NULL;   /* out of memory */
    }

    if (setjmp(png_jmpbuf(png_ptr))) {
      png_destroy_read_struct(&png_ptr,&info_ptr,NULL);
      std::fclose(file);
      return NULL;
    }

    png_init_io(png_ptr,file);
    png_read_info(png_ptr,info_ptr);

    png_get_IHDR(png_ptr,info_ptr,&width,&height,&bit_depth,&color_type,
                 NULL,NULL,NULL);

    if (setjmp(png_jmpbuf(png_ptr))) {
      png_destroy_read_struct(&png_ptr,&info_ptr,NULL);
      std::fclose(file);
      return NULL;
    }

    /* We always want RGB or RGBA */
    if (color_type==PNG_COLOR_TYPE_PALETTE) {
      png_set_expand(png_ptr);
    }

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

    if (png_get_valid(png_ptr,info_ptr,PNG_INFO_tRNS)) {
      png_set_expand(png_ptr);
    }

    if (bit_depth==16) {
      png_set_strip_16(png_ptr);
    }

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

    screen_gamma=2.2; /* TODO: Make it configurable */

    if (png_get_sRGB(png_ptr,info_ptr,&intent)) {
      png_set_gamma(png_ptr,screen_gamma,0.45455);
    }
    else {
      double image_gamma;
      if (png_get_gAMA(png_ptr,info_ptr,&image_gamma)) {
        png_set_gamma(png_ptr,screen_gamma,image_gamma);
      }
      else {
        png_set_gamma(png_ptr,screen_gamma,0.45455);
      }
    }

    png_read_update_info(png_ptr, info_ptr);

    rowbytes=png_get_rowbytes(png_ptr,info_ptr);
    channels=(int)png_get_channels(png_ptr,info_ptr);

    if ((image_data=(unsigned char *)malloc(rowbytes*height)) == NULL) {
      png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
      std::fclose(file);
      return NULL;
    }

    if ((row_pointers=(png_bytepp)malloc(height*sizeof(png_bytep))) == NULL) {
      png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
      free(image_data);
      std::fclose(file);
      return NULL;
    }

    for (size_t i=0;  i<height; ++i) {
      row_pointers[i]=image_data+i*rowbytes;
    }

    png_read_image(png_ptr,row_pointers);

    free(row_pointers);
    row_pointers=NULL;

    png_read_end(png_ptr,NULL);

#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 6, 0)
    int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32,width);
#else
    int stride = width*4;
#endif
    data=(unsigned char *)malloc(stride*height);

    // TODO: Handle stride offsets

    /*
      Calculate premultiplied alpha values and handle endian specific
      byte packging for cairo.
    */

    size_t off=0; // Index in cairo data
    size_t s=0;   // Index in PNG data
    while (s<width*height*channels) {
      unsigned int alpha;
      unsigned char red;
      unsigned char green;
      unsigned char blue;

      red=image_data[s];
      s++;
      green=image_data[s];
      s++;
      blue=image_data[s];
      s++;

      if (channels==4) {
        alpha=image_data[s];
        s++;
      }
      else {
        alpha=255;
      }

      red=red*alpha/256;
      green=green*alpha/256;
      blue=blue*alpha/256;

      if (littleEndian) {
        data[off]=blue;
        off++;
        data[off]=green;
        off++;
        data[off]=red;
        off++;
        data[off]=alpha;
        off++;
      }
      else {
        data[off]=alpha;
        off++;
        data[off]=red;
        off++;
        data[off]=green;
        off++;
        data[off]=blue;
        off++;
      }
    }

    image=cairo_image_surface_create_for_data(data,
                                              CAIRO_FORMAT_ARGB32,
                                              width,height,stride);
    if (image!=NULL) {
      cairo_surface_set_user_data(image,&imageDataKey,
                                  data,&free);
    }
    else {
      free(data);
    }

    png_destroy_read_struct(&png_ptr,&info_ptr,NULL);
    free(image_data);
    std::fclose(file);

    return image;
  }
static cairo_status_t
_get_image_surface (cairo_xcb_surface_t     *surface,
		    cairo_rectangle_int16_t *interest_rect,
		    cairo_image_surface_t  **image_out,
		    cairo_rectangle_int16_t *image_rect)
{
    cairo_image_surface_t *image;
    XCBGetImageRep *imagerep;
    int bpp, bytes_per_line;
    int x1, y1, x2, y2;
    unsigned char *data;
    cairo_format_t format;
    cairo_format_masks_t masks;

    x1 = 0;
    y1 = 0;
    x2 = surface->width;
    y2 = surface->height;

    if (interest_rect) {
	cairo_rectangle_int16_t rect;

	rect.x = interest_rect->x;
	rect.y = interest_rect->y;
	rect.width = interest_rect->width;
	rect.height = interest_rect->height;

	if (rect.x > x1)
	    x1 = rect.x;
	if (rect.y > y1)
	    y1 = rect.y;
	if (rect.x + rect.width < x2)
	    x2 = rect.x + rect.width;
	if (rect.y + rect.height < y2)
	    y2 = rect.y + rect.height;

	if (x1 >= x2 || y1 >= y2) {
	    *image_out = NULL;
	    return CAIRO_STATUS_SUCCESS;
	}
    }

    if (image_rect) {
	image_rect->x = x1;
	image_rect->y = y1;
	image_rect->width = x2 - x1;
	image_rect->height = y2 - y1;
    }

    /* XXX: This should try to use the XShm extension if available */

    if (surface->use_pixmap == 0)
    {
	XCBGenericError *error;
	imagerep = XCBGetImageReply(surface->dpy,
				    XCBGetImage(surface->dpy, XCBImageFormatZPixmap,
						surface->drawable,
						x1, y1,
						x2 - x1, y2 - y1,
						AllPlanes), &error);

	/* If we get an error, the surface must have been a window,
	 * so retry with the safe code path.
	 */
	if (error)
	    surface->use_pixmap = CAIRO_ASSUME_PIXMAP;
    }
    else
    {
	surface->use_pixmap--;
	imagerep = NULL;
    }

    if (!imagerep)
    {
	/* XCBGetImage from a window is dangerous because it can
	 * produce errors if the window is unmapped or partially
	 * outside the screen. We could check for errors and
	 * retry, but to keep things simple, we just create a
	 * temporary pixmap
	 */
	XCBDRAWABLE drawable;
	drawable.pixmap = XCBPIXMAPNew (surface->dpy);
	XCBCreatePixmap (surface->dpy,
			 surface->depth,
			 drawable.pixmap,
			 surface->drawable,
			 x2 - x1, y2 - y1);
	_cairo_xcb_surface_ensure_gc (surface);

	XCBCopyArea (surface->dpy, surface->drawable, drawable, surface->gc,
		     x1, y1, 0, 0, x2 - x1, y2 - y1);

	imagerep = XCBGetImageReply(surface->dpy,
				    XCBGetImage(surface->dpy, XCBImageFormatZPixmap,
						drawable,
						x1, y1,
						x2 - x1, y2 - y1,
						AllPlanes), 0);
	XCBFreePixmap (surface->dpy, drawable.pixmap);

    }
    if (!imagerep)
	return CAIRO_STATUS_NO_MEMORY;

    bpp = _bits_per_pixel(surface->dpy, imagerep->depth);
    bytes_per_line = _bytes_per_line(surface->dpy, surface->width, bpp);

    data = malloc (bytes_per_line * surface->height);
    if (data == NULL) {
	free (imagerep);
	return CAIRO_STATUS_NO_MEMORY;
    }

    memcpy (data, XCBGetImageData (imagerep), bytes_per_line * surface->height);
    free (imagerep);

    /*
     * Compute the pixel format masks from either an XCBVISUALTYPE or
     * a XCBRenderPCTFORMINFO, failing we assume the drawable is an
     * alpha-only pixmap as it could only have been created that way
     * through the cairo_xlib_surface_create_for_bitmap function.
     */
    if (surface->visual) {
	masks.bpp = bpp;
	masks.alpha_mask = 0;
	masks.red_mask = surface->visual->red_mask;
	masks.green_mask = surface->visual->green_mask;
	masks.blue_mask = surface->visual->blue_mask;
    } else if (surface->has_format) {
	masks.bpp = bpp;
	masks.red_mask = (unsigned long)surface->format.direct.red_mask << surface->format.direct.red_shift;
	masks.green_mask = (unsigned long)surface->format.direct.green_mask << surface->format.direct.green_shift;
	masks.blue_mask = (unsigned long)surface->format.direct.blue_mask << surface->format.direct.blue_shift;
	masks.alpha_mask = (unsigned long)surface->format.direct.alpha_mask << surface->format.direct.alpha_shift;
    } else {
	masks.bpp = bpp;
	masks.red_mask = 0;
	masks.green_mask = 0;
	masks.blue_mask = 0;
	if (surface->depth < 32)
	    masks.alpha_mask = (1 << surface->depth) - 1;
	else
	    masks.alpha_mask = 0xffffffff;
    }

    /*
     * Prefer to use a standard pixman format instead of the
     * general masks case.
     */
    if (_CAIRO_MASK_FORMAT (&masks, &format)) {
	image = (cairo_image_surface_t *)
	    cairo_image_surface_create_for_data (data,
						 format,
						 x2 - x1,
						 y2 - y1,
						 bytes_per_line);
	if (image->base.status)
	    goto FAIL;
    } else {
	/*
	 * XXX This can't work.  We must convert the data to one of the
	 * supported pixman formats.  Pixman needs another function
	 * which takes data in an arbitrary format and converts it
	 * to something supported by that library.
	 */
	image = (cairo_image_surface_t *)
	    _cairo_image_surface_create_with_masks (data,
						    &masks,
						    x2 - x1,
						    y2 - y1,
						    bytes_per_line);
	if (image->base.status)
	    goto FAIL;
    }

    /* Let the surface take ownership of the data */
    _cairo_image_surface_assume_ownership_of_data (image);

    *image_out = image;
    return CAIRO_STATUS_SUCCESS;

 FAIL:
    free (data);
    return CAIRO_STATUS_NO_MEMORY;
}
//--------------------------------------------
void ofCairoRenderer::draw(ofImage & img, float x, float y, float z, float w, float h){
	ofPixelsRef pix = img.getPixelsRef();
	pushMatrix();
	translate(x,y,z);
	scale(w/pix.getWidth(),h/pix.getHeight());
	cairo_surface_t *image;
	int stride=0;
	int picsize = pix.getWidth()* pix.getHeight();
	unsigned char *imgPix = pix.getPixels();

	static vector<unsigned char> swapPixels;

	switch(pix.getImageType()){
	case OF_IMAGE_COLOR:
#ifdef TARGET_LITTLE_ENDIAN
		swapPixels.resize(picsize * 4);

		for(int p= 0; p<picsize; p++) {
			swapPixels[p*4] = imgPix[p*3 +2];
			swapPixels[p*4 +1] = imgPix[p*3 +1];
			swapPixels[p*4 +2] = imgPix[p*3];
		}
#else
		swapPixels.resize(picsize * 4);

		for(int p= 0; p<picsize; p++) {
			swapPixels[p*4] = imgPix[p*3];
			swapPixels[p*4 +1] = imgPix[p*3 +1];
			swapPixels[p*4 +2] = imgPix[p*3 +2];
		}
#endif
		stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, pix.getWidth());
		image = cairo_image_surface_create_for_data(&swapPixels[0], CAIRO_FORMAT_RGB24, pix.getWidth(), pix.getHeight(), stride);
		break;
	case OF_IMAGE_COLOR_ALPHA:
#ifdef TARGET_LITTLE_ENDIAN
		swapPixels.resize(picsize * 4);

		for(int p= 0; p<picsize; p++) {
			swapPixels[p*4] = imgPix[p*4+2];
			swapPixels[p*4 +1] = imgPix[p*4+1];
			swapPixels[p*4 +2] = imgPix[p*4];
			swapPixels[p*4 +3] = imgPix[p*4+3];
		}
		stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, pix.getWidth());
		image = cairo_image_surface_create_for_data(&swapPixels[0], CAIRO_FORMAT_ARGB32, pix.getWidth(), pix.getHeight(), stride);
#else
		stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, pix.getWidth());
		image = cairo_image_surface_create_for_data(pix.getPixels(), CAIRO_FORMAT_ARGB32, pix.getWidth(), pix.getHeight(), stride);
#endif
		break;
	case OF_IMAGE_GRAYSCALE:
		swapPixels.resize(picsize * 4);

		for(int p= 0; p<picsize; p++) {
			swapPixels[p*4] = imgPix[p];
			swapPixels[p*4 +1] = imgPix[p];
			swapPixels[p*4 +2] = imgPix[p];
		}
		stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, pix.getWidth());
		image = cairo_image_surface_create_for_data(&swapPixels[0], CAIRO_FORMAT_RGB24, pix.getWidth(), pix.getHeight(), stride);
		break;
	case OF_IMAGE_UNDEFINED:
		ofLog(OF_LOG_ERROR,"ofCairoRenderer: trying to render undefined type image");
		popMatrix();
		return;
		break;
	}
	cairo_set_source_surface (cr, image, 0,0);
	cairo_paint (cr);
	cairo_surface_flush(image);
	cairo_surface_destroy (image);
	popMatrix();
}
Example #20
0
/**
 * _st_create_shadow_cairo_pattern:
 * @shadow_spec: the definition of the shadow
 * @src_pattern: surface pattern for which we create the shadow
 *               (must be a surface pattern)
 *
 * This is a utility function for creating shadows used by
 * st-theme-node.c; it's in this file to share the gaussian
 * blur implementation. The usage of this function is quite different
 * depending on whether shadow_spec->inset is %TRUE or not. If
 * shadow_spec->inset is %TRUE, the caller should pass in a @src_pattern
 * which is the <i>inverse</i> of what they want shadowed, and must take
 * care of the spread and offset from the shadow spec themselves. If
 * shadow_spec->inset is %FALSE then the caller should pass in what they
 * want shadowed directly, and this function takes care of the spread and
 * the offset.
 */
cairo_pattern_t *
_st_create_shadow_cairo_pattern (StShadow        *shadow_spec,
                                 cairo_pattern_t *src_pattern)
{
  static cairo_user_data_key_t shadow_pattern_user_data;
  cairo_t *cr;
  cairo_surface_t *src_surface;
  cairo_surface_t *surface_in;
  cairo_surface_t *surface_out;
  cairo_pattern_t *dst_pattern;
  guchar          *pixels_in, *pixels_out;
  gint             width_in, height_in, rowstride_in;
  gint             width_out, height_out, rowstride_out;
  cairo_matrix_t   shadow_matrix;
  int i, j;

  g_return_val_if_fail (shadow_spec != NULL, NULL);
  g_return_val_if_fail (src_pattern != NULL, NULL);

  cairo_pattern_get_surface (src_pattern, &src_surface);

  width_in  = cairo_image_surface_get_width  (src_surface);
  height_in = cairo_image_surface_get_height (src_surface);

  /* We want the output to be a color agnostic alpha mask,
   * so we need to strip the color channels from the input
   */
  if (cairo_image_surface_get_format (src_surface) != CAIRO_FORMAT_A8)
    {
      surface_in = cairo_image_surface_create (CAIRO_FORMAT_A8,
                                               width_in, height_in);

      cr = cairo_create (surface_in);
      cairo_set_source_surface (cr, src_surface, 0, 0);
      cairo_paint (cr);
      cairo_destroy (cr);
    }
  else
    {
      surface_in = cairo_surface_reference (src_surface);
    }

  pixels_in = cairo_image_surface_get_data (surface_in);
  rowstride_in = cairo_image_surface_get_stride (surface_in);

  pixels_out = blur_pixels (pixels_in, width_in, height_in, rowstride_in,
                            shadow_spec->blur,
                            &width_out, &height_out, &rowstride_out);
  cairo_surface_destroy (surface_in);

  /* Invert pixels for inset shadows */
  if (shadow_spec->inset)
    {
      for (j = 0; j < height_out; j++)
        {
          guchar *p = pixels_out + rowstride_out * j;
          for (i = 0; i < width_out; i++, p++)
            *p = ~*p;
        }
    }

  surface_out = cairo_image_surface_create_for_data (pixels_out,
                                                     CAIRO_FORMAT_A8,
                                                     width_out,
                                                     height_out,
                                                     rowstride_out);
  cairo_surface_set_user_data (surface_out, &shadow_pattern_user_data,
                               pixels_out, (cairo_destroy_func_t) g_free);

  dst_pattern = cairo_pattern_create_for_surface (surface_out);
  cairo_surface_destroy (surface_out);

  cairo_pattern_get_matrix (src_pattern, &shadow_matrix);

  if (shadow_spec->inset)
    {
      /* For inset shadows, offsets and spread radius have already been
       * applied to the original pattern, so all left to do is shift the
       * blurred image left, so that it aligns centered under the
       * unblurred one
       */
      cairo_matrix_translate (&shadow_matrix,
                              (width_out - width_in) / 2.0,
                              (height_out - height_in) / 2.0);
      cairo_pattern_set_matrix (dst_pattern, &shadow_matrix);
      return dst_pattern;
    }

  /* Read all the code from the cairo_pattern_set_matrix call
   * at the end of this function to here from bottom to top,
   * because each new affine transformation is applied in
   * front of all the previous ones */

  /* 6. Invert the matrix back */
  cairo_matrix_invert (&shadow_matrix);

  /* 5. Adjust based on specified offsets */
  cairo_matrix_translate (&shadow_matrix,
                          shadow_spec->xoffset,
                          shadow_spec->yoffset);

  /* 4. Recenter the newly scaled image */
  cairo_matrix_translate (&shadow_matrix,
                          - shadow_spec->spread,
                          - shadow_spec->spread);

  /* 3. Scale up the blurred image to fill the spread */
  cairo_matrix_scale (&shadow_matrix,
                      (width_in + 2.0 * shadow_spec->spread) / width_in,
                      (height_in + 2.0 * shadow_spec->spread) / height_in);

  /* 2. Shift the blurred image left, so that it aligns centered
   * under the unblurred one */
  cairo_matrix_translate (&shadow_matrix,
                          - (width_out - width_in) / 2.0,
                          - (height_out - height_in) / 2.0);

  /* 1. Invert the matrix so we can work with it in pattern space
   */
  cairo_matrix_invert (&shadow_matrix);

  cairo_pattern_set_matrix (dst_pattern, &shadow_matrix);

  return dst_pattern;
}
Example #21
0
void GraphicsContext3DPrivate::paintToTextureMapper(TextureMapper* textureMapper, const FloatRect& targetRect, const TransformationMatrix& matrix, float opacity)
{
    if (!m_glContext)
        return;

    ASSERT(m_renderStyle == GraphicsContext3D::RenderOffscreen);

    m_context->markLayerComposited();

    // FIXME: We do not support mask for the moment with TextureMapperImageBuffer.
    if (textureMapper->accelerationMode() != TextureMapper::OpenGLMode) {
        GraphicsContext* context = textureMapper->graphicsContext();
        context->save();
        context->platformContext()->setGlobalAlpha(opacity);

        const int height = m_context->m_currentHeight;
        const int width = m_context->m_currentWidth;
        int totalBytes = width * height * 4;

        OwnArrayPtr<unsigned char> pixels = adoptArrayPtr(new unsigned char[totalBytes]);
        if (!pixels)
            return;

        // OpenGL keeps the pixels stored bottom up, so we need to flip the image here.
        context->translate(0, height);
        context->scale(FloatSize(1, -1));

        context->concatCTM(matrix.toAffineTransform());

        m_context->readRenderingResults(pixels.get(), totalBytes);

        // Premultiply alpha.
        for (int i = 0; i < totalBytes; i += 4)
            if (pixels[i + 3] != 255) {
                pixels[i + 0] = min(255, pixels[i + 0] * pixels[i + 3] / 255);
                pixels[i + 1] = min(255, pixels[i + 1] * pixels[i + 3] / 255);
                pixels[i + 2] = min(255, pixels[i + 2] * pixels[i + 3] / 255);
            }

        RefPtr<cairo_surface_t> imageSurface = adoptRef(cairo_image_surface_create_for_data(
            const_cast<unsigned char*>(pixels.get()), CAIRO_FORMAT_ARGB32, width, height, width * 4));

        context->platformContext()->drawSurfaceToContext(imageSurface.get(), targetRect, IntRect(0, 0, width, height), context);

        context->restore();
        return;
    }

#if USE(TEXTURE_MAPPER_GL)
    if (m_context->m_attrs.antialias && m_context->m_state.boundFBO == m_context->m_multisampleFBO) {
        GLContext* previousActiveContext = GLContext::getCurrent();
        if (previousActiveContext != m_glContext)
            m_context->makeContextCurrent();

        m_context->resolveMultisamplingIfNecessary();
        ::glBindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_context->m_state.boundFBO);

        if (previousActiveContext && previousActiveContext != m_glContext)
            previousActiveContext->makeContextCurrent();
    }

    TextureMapperGL* texmapGL = static_cast<TextureMapperGL*>(textureMapper);
    TextureMapperGL::Flags flags = TextureMapperGL::ShouldFlipTexture | (m_context->m_attrs.alpha ? TextureMapperGL::ShouldBlend : 0);
    IntSize textureSize(m_context->m_currentWidth, m_context->m_currentHeight);
    texmapGL->drawTexture(m_context->m_texture, flags, textureSize, targetRect, matrix, opacity);
#endif // USE(ACCELERATED_COMPOSITING_GL)
}
Example #22
0
static void
image_set_from_surface (GtkImage        *gtkimage,
			cairo_surface_t *surface)
{
	GdkPixbuf       *pixbuf;
	cairo_surface_t *image;
	cairo_t         *cr;
	gboolean         has_alpha;
	gint             width, height;
	cairo_format_t   surface_format;
	gint             pixbuf_n_channels;
	gint             pixbuf_rowstride;
	guchar          *pixbuf_pixels;
	gint             x, y;

	width = cairo_image_surface_get_width (surface);
	height = cairo_image_surface_get_height (surface);
	
	surface_format = cairo_image_surface_get_format (surface);
	has_alpha = (surface_format == CAIRO_FORMAT_ARGB32);

	pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
				 TRUE, 8,
				 width, height);
	pixbuf_n_channels = gdk_pixbuf_get_n_channels (pixbuf);
	pixbuf_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
	pixbuf_pixels = gdk_pixbuf_get_pixels (pixbuf);

	image = cairo_image_surface_create_for_data (pixbuf_pixels,
						     surface_format,
						     width, height,
						     pixbuf_rowstride);
	cr = cairo_create (image);
	cairo_set_source_surface (cr, surface, 0, 0);

	if (has_alpha)
		cairo_mask_surface (cr, surface, 0, 0);
	else
		cairo_paint (cr);

	cairo_destroy (cr);
	cairo_surface_destroy (image);

	for (y = 0; y < height; y++) {
		guchar *p = pixbuf_pixels + y * pixbuf_rowstride;

		for (x = 0; x < width; x++) {
			guchar tmp;
			
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
			tmp = p[0];
			p[0] = p[2];
			p[2] = tmp;
			p[3] = (has_alpha) ? p[3] : 0xff;
#else
			tmp = p[0];
			p[0] = (has_alpha) ? p[3] : 0xff;
			p[3] = p[2];
			p[2] = p[1];
			p[1] = tmp;
#endif			
			p += pixbuf_n_channels;
		}
	}

	gtk_image_set_from_pixbuf (gtkimage, pixbuf);
	g_object_unref (pixbuf);
}
Example #23
0
static gboolean
gtk_gst_widget_draw (GtkWidget * widget, cairo_t * cr)
{
  GtkGstWidget *gst_widget = (GtkGstWidget *) widget;
  guint widget_width, widget_height;
  cairo_surface_t *surface;
  GstVideoFrame frame;

  widget_width = gtk_widget_get_allocated_width (widget);
  widget_height = gtk_widget_get_allocated_height (widget);

  g_mutex_lock (&gst_widget->priv->lock);

  /* failed to map the video frame */
  if (gst_widget->priv->negotiated && gst_widget->priv->buffer
      && gst_video_frame_map (&frame, &gst_widget->priv->v_info,
          gst_widget->priv->buffer, GST_MAP_READ)) {
    gdouble scale_x = (gdouble) widget_width / gst_widget->priv->display_width;
    gdouble scale_y =
        (gdouble) widget_height / gst_widget->priv->display_height;
    GstVideoRectangle result;
    cairo_format_t format;

    gst_widget->priv->v_info = frame.info;
    if (frame.info.finfo->format == GST_VIDEO_FORMAT_ARGB ||
        frame.info.finfo->format == GST_VIDEO_FORMAT_BGRA) {
      format = CAIRO_FORMAT_ARGB32;
    } else {
      format = CAIRO_FORMAT_RGB24;
    }

    surface = cairo_image_surface_create_for_data (frame.data[0],
        format, frame.info.width, frame.info.height, frame.info.stride[0]);

    if (gst_widget->priv->force_aspect_ratio) {
      GstVideoRectangle src, dst;

      src.x = 0;
      src.y = 0;
      src.w = gst_widget->priv->display_width;
      src.h = gst_widget->priv->display_height;

      dst.x = 0;
      dst.y = 0;
      dst.w = widget_width;
      dst.h = widget_height;

      gst_video_sink_center_rect (src, dst, &result, TRUE);

      scale_x = scale_y = MIN (scale_x, scale_y);
    } else {
      result.x = 0;
      result.y = 0;
      result.w = widget_width;
      result.h = widget_height;
    }

    if (gst_widget->priv->ignore_alpha) {
      GdkRGBA color = { 0.0, 0.0, 0.0, 1.0 };

      gdk_cairo_set_source_rgba (cr, &color);
      if (result.x > 0) {
        cairo_rectangle (cr, 0, 0, result.x, widget_height);
        cairo_fill (cr);
      }
      if (result.y > 0) {
        cairo_rectangle (cr, 0, 0, widget_width, result.y);
        cairo_fill (cr);
      }
      if (result.w < widget_width) {
        cairo_rectangle (cr, result.x + result.w, 0, widget_width - result.w,
            widget_height);
        cairo_fill (cr);
      }
      if (result.h < widget_height) {
        cairo_rectangle (cr, 0, result.y + result.h, widget_width,
            widget_height - result.h);
        cairo_fill (cr);
      }
    }

    scale_x *=
        (gdouble) gst_widget->priv->display_width / (gdouble) frame.info.width;
    scale_y *=
        (gdouble) gst_widget->priv->display_height /
        (gdouble) frame.info.height;

    cairo_translate (cr, result.x, result.y);
    cairo_scale (cr, scale_x, scale_y);
    cairo_rectangle (cr, 0, 0, result.w, result.h);
    cairo_set_source_surface (cr, surface, 0, 0);
    cairo_paint (cr);

    cairo_surface_destroy (surface);

    gst_video_frame_unmap (&frame);
  } else {
    GdkRGBA color;

    if (gst_widget->priv->ignore_alpha) {
      color.red = color.blue = color.green = 0.0;
      color.alpha = 1.0;
    } else {
      gtk_style_context_get_color (gtk_widget_get_style_context (widget),
          GTK_STATE_FLAG_NORMAL, &color);
    }
    gdk_cairo_set_source_rgba (cr, &color);
    cairo_rectangle (cr, 0, 0, widget_width, widget_height);
    cairo_fill (cr);
  }

  g_mutex_unlock (&gst_widget->priv->lock);
  return FALSE;
}
Example #24
0
int main(int argc, char *argv[]) {
    struct passwd *pw;
    char *username;
    char *image_path = NULL;
    int ret;
    struct pam_conv conv = {conv_callback, NULL};
    int curs_choice = CURS_NONE;
    int o;
    int optind = 0;
    struct option longopts[] = {
        {"version", no_argument, NULL, 'v'},
        {"nofork", no_argument, NULL, 'n'},
        {"beep", no_argument, NULL, 'b'},
        {"dpms", no_argument, NULL, 'd'},
        {"color", required_argument, NULL, 'c'},
        {"pointer", required_argument, NULL, 'p'},
        {"debug", no_argument, NULL, 0},
        {"help", no_argument, NULL, 'h'},
        {"no-unlock-indicator", no_argument, NULL, 'u'},
        {"image", required_argument, NULL, 'i'},
        {"tiling", no_argument, NULL, 't'},
        {"ignore-empty-password", no_argument, NULL, 'e'},
        {"inactivity-timeout", required_argument, NULL, 'I'},
        {"show-failed-attempts", no_argument, NULL, 'f'},
        {NULL, no_argument, NULL, 0}};

    if ((pw = getpwuid(getuid())) == NULL)
        err(EXIT_FAILURE, "getpwuid() failed");
    if ((username = pw->pw_name) == NULL)
        errx(EXIT_FAILURE, "pw->pw_name is NULL.\n");

    char *optstring = "hvnbdc:p:ui:teI:f";
    while ((o = getopt_long(argc, argv, optstring, longopts, &optind)) != -1) {
        switch (o) {
            case 'v':
                errx(EXIT_SUCCESS, "version " VERSION " © 2010 Michael Stapelberg");
            case 'n':
                dont_fork = true;
                break;
            case 'b':
                beep = true;
                break;
            case 'd':
                fprintf(stderr, "DPMS support has been removed from i3lock. Please see the manpage i3lock(1).\n");
                break;
            case 'I': {
                int time = 0;
                if (sscanf(optarg, "%d", &time) != 1 || time < 0)
                    errx(EXIT_FAILURE, "invalid timeout, it must be a positive integer\n");
                inactivity_timeout = time;
                break;
            }
            case 'c': {
                char *arg = optarg;

                /* Skip # if present */
                if (arg[0] == '#')
                    arg++;

                if (strlen(arg) != 6 || sscanf(arg, "%06[0-9a-fA-F]", color) != 1)
                    errx(EXIT_FAILURE, "color is invalid, it must be given in 3-byte hexadecimal format: rrggbb\n");

                break;
            }
            case 'u':
                unlock_indicator = false;
                break;
            case 'i':
                image_path = strdup(optarg);
                break;
            case 't':
                tile = true;
                break;
            case 'p':
                if (!strcmp(optarg, "win")) {
                    curs_choice = CURS_WIN;
                } else if (!strcmp(optarg, "default")) {
                    curs_choice = CURS_DEFAULT;
                } else {
                    errx(EXIT_FAILURE, "i3lock: Invalid pointer type given. Expected one of \"win\" or \"default\".\n");
                }
                break;
            case 'e':
                ignore_empty_password = true;
                break;
            case 0:
                if (strcmp(longopts[optind].name, "debug") == 0)
                    debug_mode = true;
                break;
            case 'f':
                show_failed_attempts = true;
                break;
            default:
                errx(EXIT_FAILURE, "Syntax: i3lock [-v] [-n] [-b] [-d] [-c color] [-u] [-p win|default]"
                                   " [-i image.png] [-t] [-e] [-I timeout] [-f]");
        }
    }

    /* We need (relatively) random numbers for highlighting a random part of
     * the unlock indicator upon keypresses. */
    srand(time(NULL));

    /* Initialize PAM */
    if ((ret = pam_start("i3lock", username, &conv, &pam_handle)) != PAM_SUCCESS)
        errx(EXIT_FAILURE, "PAM: %s", pam_strerror(pam_handle, ret));

    if ((ret = pam_set_item(pam_handle, PAM_TTY, getenv("DISPLAY"))) != PAM_SUCCESS)
        errx(EXIT_FAILURE, "PAM: %s", pam_strerror(pam_handle, ret));

/* Using mlock() as non-super-user seems only possible in Linux. Users of other
 * operating systems should use encrypted swap/no swap (or remove the ifdef and
 * run i3lock as super-user). */
#if defined(__linux__)
    /* Lock the area where we store the password in memory, we don’t want it to
     * be swapped to disk. Since Linux 2.6.9, this does not require any
     * privileges, just enough bytes in the RLIMIT_MEMLOCK limit. */
    if (mlock(password, sizeof(password)) != 0)
        err(EXIT_FAILURE, "Could not lock page in memory, check RLIMIT_MEMLOCK");
#endif

    /* Double checking that connection is good and operatable with xcb */
    int screennr;
    if ((conn = xcb_connect(NULL, &screennr)) == NULL ||
        xcb_connection_has_error(conn))
        errx(EXIT_FAILURE, "Could not connect to X11, maybe you need to set DISPLAY?");

    if (xkb_x11_setup_xkb_extension(conn,
                                    XKB_X11_MIN_MAJOR_XKB_VERSION,
                                    XKB_X11_MIN_MINOR_XKB_VERSION,
                                    0,
                                    NULL,
                                    NULL,
                                    &xkb_base_event,
                                    &xkb_base_error) != 1)
        errx(EXIT_FAILURE, "Could not setup XKB extension.");

    static const xcb_xkb_map_part_t required_map_parts =
        (XCB_XKB_MAP_PART_KEY_TYPES |
         XCB_XKB_MAP_PART_KEY_SYMS |
         XCB_XKB_MAP_PART_MODIFIER_MAP |
         XCB_XKB_MAP_PART_EXPLICIT_COMPONENTS |
         XCB_XKB_MAP_PART_KEY_ACTIONS |
         XCB_XKB_MAP_PART_VIRTUAL_MODS |
         XCB_XKB_MAP_PART_VIRTUAL_MOD_MAP);

    static const xcb_xkb_event_type_t required_events =
        (XCB_XKB_EVENT_TYPE_NEW_KEYBOARD_NOTIFY |
         XCB_XKB_EVENT_TYPE_MAP_NOTIFY |
         XCB_XKB_EVENT_TYPE_STATE_NOTIFY);

    xcb_xkb_select_events(
        conn,
        xkb_x11_get_core_keyboard_device_id(conn),
        required_events,
        0,
        required_events,
        required_map_parts,
        required_map_parts,
        0);

    /* When we cannot initially load the keymap, we better exit */
    if (!load_keymap())
        errx(EXIT_FAILURE, "Could not load keymap");

    const char *locale = getenv("LC_ALL");
    if (!locale)
        locale = getenv("LC_CTYPE");
    if (!locale)
        locale = getenv("LANG");
    if (!locale) {
        if (debug_mode)
            fprintf(stderr, "Can't detect your locale, fallback to C\n");
        locale = "C";
    }

    load_compose_table(locale);

    xinerama_init();
    xinerama_query_screens();

    screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;

    last_resolution[0] = screen->width_in_pixels;
    last_resolution[1] = screen->height_in_pixels;

    xcb_change_window_attributes(conn, screen->root, XCB_CW_EVENT_MASK,
                                 (uint32_t[]){XCB_EVENT_MASK_STRUCTURE_NOTIFY});

    if (image_path) {
        IMG_Init(IMG_INIT_TIF);
        sdl_surface = IMG_Load(image_path);
        /* Create a pixmap to render on, fill it with the background color */
        img = cairo_image_surface_create_for_data(
            (unsigned char*)sdl_surface->pixels,
            CAIRO_FORMAT_RGB24,
            sdl_surface->w,
            sdl_surface->h,
            sdl_surface->pitch);
        /* In case loading failed, we just pretend no -i was specified. */
        if (cairo_surface_status(img) != CAIRO_STATUS_SUCCESS) {
            fprintf(stderr, "Could not load image \"%s\": %s\n",
                    image_path, cairo_status_to_string(cairo_surface_status(img)));
            img = NULL;
        }
    }

    /* Pixmap on which the image is rendered to (if any) */
    xcb_pixmap_t bg_pixmap = draw_image(last_resolution);

    /* open the fullscreen window, already with the correct pixmap in place */
    win = open_fullscreen_window(conn, screen, color, bg_pixmap);
    xcb_free_pixmap(conn, bg_pixmap);

    pid_t pid = fork();
    /* The pid == -1 case is intentionally ignored here:
     * While the child process is useful for preventing other windows from
     * popping up while i3lock blocks, it is not critical. */
    if (pid == 0) {
        /* Child */
        close(xcb_get_file_descriptor(conn));
        raise_loop(win);
        exit(EXIT_SUCCESS);
    }

    cursor = create_cursor(conn, screen, win, curs_choice);

    grab_pointer_and_keyboard(conn, screen, cursor);
    /* Load the keymap again to sync the current modifier state. Since we first
     * loaded the keymap, there might have been changes, but starting from now,
     * we should get all key presses/releases due to having grabbed the
     * keyboard. */
    (void)load_keymap();

    /* Initialize the libev event loop. */
    main_loop = EV_DEFAULT;
    if (main_loop == NULL)
        errx(EXIT_FAILURE, "Could not initialize libev. Bad LIBEV_FLAGS?\n");

    struct ev_io *xcb_watcher = calloc(sizeof(struct ev_io), 1);
    struct ev_check *xcb_check = calloc(sizeof(struct ev_check), 1);
    struct ev_prepare *xcb_prepare = calloc(sizeof(struct ev_prepare), 1);

    ev_io_init(xcb_watcher, xcb_got_event, xcb_get_file_descriptor(conn), EV_READ);
    ev_io_start(main_loop, xcb_watcher);

    ev_check_init(xcb_check, xcb_check_cb);
    ev_check_start(main_loop, xcb_check);

    ev_prepare_init(xcb_prepare, xcb_prepare_cb);
    ev_prepare_start(main_loop, xcb_prepare);

    /* Invoke the event callback once to catch all the events which were
     * received up until now. ev will only pick up new events (when the X11
     * file descriptor becomes readable). */
    ev_invoke(main_loop, xcb_check, 0);
    ev_loop(main_loop, 0);
}
Example #25
0
void guac_rdp_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt) {

    guac_client* client = ((rdp_freerdp_context*) context)->client;
    guac_common_surface* current_surface = ((rdp_guac_client_data*) client->data)->current_surface;
    guac_rdp_bitmap* bitmap = (guac_rdp_bitmap*) memblt->bitmap;

    int x = memblt->nLeftRect;
    int y = memblt->nTopRect;
    int w = memblt->nWidth;
    int h = memblt->nHeight;

    int x_src = memblt->nXSrc;
    int y_src = memblt->nYSrc;

    /* Make sure that the recieved bitmap is not NULL before processing */
    if (bitmap == NULL) {
        guac_client_log(client, GUAC_LOG_INFO, "NULL bitmap found in memblt instruction.");
        return;
    }

    switch (memblt->bRop) {

        /* If blackness, send black rectangle */
        case 0x00:
            guac_common_surface_rect(current_surface, x, y, w, h, 0, 0, 0);
            break;

        /* If NOP, do nothing */
        case 0xAA:
            break;

        /* If operation is just SRC, simply copy */
        case 0xCC: 

            /* If not cached, cache if necessary */
            if (bitmap->surface == NULL && bitmap->used >= 1)
                guac_rdp_cache_bitmap(context, memblt->bitmap);

            /* If not cached, send as PNG */
            if (bitmap->surface == NULL) {
                if (memblt->bitmap->data != NULL) {

                    /* Create surface from image data */
                    cairo_surface_t* surface = cairo_image_surface_create_for_data(
                        memblt->bitmap->data + 4*(x_src + y_src*memblt->bitmap->width),
                        CAIRO_FORMAT_RGB24, w, h, 4*memblt->bitmap->width);

                    /* Send surface to buffer */
                    guac_common_surface_draw(current_surface, x, y, surface);

                    /* Free surface */
                    cairo_surface_destroy(surface);

                }
            }

            /* Otherwise, copy */
            else
                guac_common_surface_copy(bitmap->surface, x_src, y_src, w, h,
                                         current_surface, x, y);

            /* Increment usage counter */
            ((guac_rdp_bitmap*) bitmap)->used++;

            break;

        /* If whiteness, send white rectangle */
        case 0xFF:
            guac_common_surface_rect(current_surface, x, y, w, h, 0xFF, 0xFF, 0xFF);
            break;

        /* Otherwise, use transfer */
        default:

            /* If not available as a surface, make available. */
            if (bitmap->surface == NULL)
                guac_rdp_cache_bitmap(context, memblt->bitmap);

            guac_common_surface_transfer(bitmap->surface, x_src, y_src, w, h,
                                         guac_rdp_rop3_transfer_function(client, memblt->bRop),
                                         current_surface, x, y);

            /* Increment usage counter */
            ((guac_rdp_bitmap*) bitmap)->used++;

    }

}
Example #26
0
                    uint32 a = penalpha * glyph->glm_BitMap[top_mod_left + x] / 255;
                    if (a) {
                        uint32 oldARGB = (*glyphRGBABuffer)[(imgoffsety + y) * imagewidth + offsetinimg + imgoffsetx + x];
                        if (oldARGB)
                            a = std::max((oldARGB >> 24), a);
                        (*glyphRGBABuffer)[(imgoffsety + y) * imagewidth + offsetinimg + imgoffsetx + x] = (a << 24) | ((penr * a / 255) << 16) | ((peng * a / 255) << 8) | (penb * a / 255);
                    }
                }
        }

        offsetinimg += glyphBuffer.advanceAt(from + i);

        IDiskfont->EReleaseInfo(&curface->olf_EEngine, OT_GlyphMap8Bit, glyph, TAG_END);
    }

    cairo_surface_t *surface = cairo_image_surface_create_for_data((unsigned char *)glyphRGBABuffer->data(), CAIRO_FORMAT_ARGB32, imagewidth, height, imagewidth * 4);
    if (surface) {
        cairo_t* cr = context->platformContext();

        cairo_set_source_surface(cr, surface, point.x() - shiftleft + shadowx, point.y() - ascent + shadowy);
        cairo_paint(cr);

        cairo_surface_destroy(surface);
    }

    delete glyphRGBABuffer;
}

void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
                      int from, int numGlyphs, const FloatPoint& point) const
{
static inline PassRefPtr<cairo_surface_t> createSurfaceFromData(void* data, const WebCore::IntSize& size)
{
    const int stride = cairo_format_stride_for_width(cairoFormat, size.width());
    return adoptRef(cairo_image_surface_create_for_data(static_cast<unsigned char*>(data), cairoFormat, size.width(), size.height(), stride));
}
void cairo_container::draw_background( litehtml::uint_ptr hdc, const litehtml::background_paint& bg )
{
	cairo_t* cr = (cairo_t*) hdc;
	cairo_save(cr);
	apply_clip(cr);

	rounded_rectangle(cr, bg.border_box, bg.border_radius);
	cairo_clip(cr);

	cairo_rectangle(cr, bg.clip_box.x, bg.clip_box.y, bg.clip_box.width, bg.clip_box.height);
	cairo_clip(cr);

	if(bg.color.alpha)
	{
		set_color(cr, bg.color);
		cairo_paint(cr);
	}

	std::wstring url;
	t_make_url(bg.image.c_str(), bg.baseurl.c_str(), url);

	lock_images_cache();
	images_map::iterator img_i = m_images.find(url.c_str());
	if(img_i != m_images.end() && img_i->second)
	{
		image_ptr bgbmp = img_i->second;
		
		image_ptr new_img;
		if(bg.image_size.width != bgbmp->getWidth() || bg.image_size.height != bgbmp->getHeight())
		{
			new_img = image_ptr(new CTxDIB);
			bgbmp->resample(bg.image_size.width, bg.image_size.height, new_img.get());
			bgbmp = new_img;
		}


		cairo_surface_t* img = cairo_image_surface_create_for_data((unsigned char*) bgbmp->getBits(), CAIRO_FORMAT_ARGB32, bgbmp->getWidth(), bgbmp->getHeight(), bgbmp->getWidth() * 4);
		cairo_pattern_t *pattern = cairo_pattern_create_for_surface(img);
		cairo_matrix_t flib_m;
		cairo_matrix_init(&flib_m, 1, 0, 0, -1, 0, 0);
		cairo_matrix_translate(&flib_m, -bg.position_x, -bg.position_y);
		cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
		cairo_pattern_set_matrix (pattern, &flib_m);

		switch(bg.repeat)
		{
		case litehtml::background_repeat_no_repeat:
			draw_txdib(cr, bgbmp.get(), bg.position_x, bg.position_y, bgbmp->getWidth(), bgbmp->getHeight());
			break;

		case litehtml::background_repeat_repeat_x:
			cairo_set_source(cr, pattern);
			cairo_rectangle(cr, bg.clip_box.left(), bg.position_y, bg.clip_box.width, bgbmp->getHeight());
			cairo_fill(cr);
			break;

		case litehtml::background_repeat_repeat_y:
			cairo_set_source(cr, pattern);
			cairo_rectangle(cr, bg.position_x, bg.clip_box.top(), bgbmp->getWidth(), bg.clip_box.height);
			cairo_fill(cr);
			break;

		case litehtml::background_repeat_repeat:
			cairo_set_source(cr, pattern);
			cairo_rectangle(cr, bg.clip_box.left(), bg.clip_box.top(), bg.clip_box.width, bg.clip_box.height);
			cairo_fill(cr);
			break;
		}

		cairo_pattern_destroy(pattern);
		cairo_surface_destroy(img);
	}
	unlock_images_cache();
	cairo_restore(cr);
}
int main(int argc, char** args) {
    int c;
    char* wcsfn = NULL;
    char* outfn = NULL;
    char* infn = NULL;
    sip_t sip;
    double scale = 1.0;
    anbool pngformat = TRUE;

    char* hdpath = NULL;
    anbool HD = FALSE;

    cairos_t thecairos;
    cairos_t* cairos = &thecairos;

    cairo_surface_t* target = NULL;
    cairo_t* cairot = NULL;

    cairo_surface_t* surfbg = NULL;
    cairo_t* cairobg = NULL;

    cairo_surface_t* surfshapes = NULL;
    cairo_t* cairoshapes = NULL;

    cairo_surface_t* surfshapesmask = NULL;
    cairo_t* cairoshapesmask = NULL;

    cairo_surface_t* surffg = NULL;
    cairo_t* cairo = NULL;

    double lw = 2.0;
    // circle linewidth.
    double cw = 2.0;

    double ngc_fraction = 0.02;

    // NGC linewidth
    double nw = 2.0;

    // leave a gap short of connecting the points.
    double endgap = 5.0;
    // circle radius.
    double crad = endgap;

    double fontsize = 14.0;

    double label_offset = 15.0;

    int W = 0, H = 0;
    unsigned char* img = NULL;

    anbool NGC = FALSE, constell = FALSE;
    anbool bright = FALSE;
    anbool common_only = FALSE;
    anbool print_common_only = FALSE;
    int Nbright = 0;
    double ra, dec, px, py;
    int i, N;
    anbool justlist = FALSE;
    anbool only_messier = FALSE;

    anbool grid = FALSE;
    double gridspacing = 0.0;
    double gridcolor[3] = { 0.2, 0.2, 0.2 };

    int loglvl = LOG_MSG;

	char halign = 'L';
	char valign = 'C';
    sl* json = NULL;

    anbool whitetext = FALSE;

    while ((c = getopt(argc, args, OPTIONS)) != -1) {
        switch (c) {
		case 'V':
			valign = optarg[0];
			break;
		case 'O':
			halign = optarg[0];
			break;
        case 'F':
            ngc_fraction = atof(optarg);
            break;
        case 'h':
            print_help(args[0]);
            exit(0);
        case 'J':
            json = sl_new(4);
            break;
        case 'G':
            gridspacing = atof(optarg);
            break;
        case 'g':
            {
            char *tail = NULL;
            gridcolor[0] = strtod(optarg,&tail);
            if (*tail) { tail++; gridcolor[1] = strtod(tail,&tail); }
            if (*tail) { tail++; gridcolor[2] = strtod(tail,&tail); }
            }
            break;
        case 'D':
            HD = TRUE;
            break;
        case 'd':
            hdpath = optarg;
            break;
        case 'M':
            only_messier = TRUE;
            break;
        case 'n':
            nw = atof(optarg);
            break;
        case 'f':
            fontsize = atof(optarg);
            break;
        case 'L':
            justlist = TRUE;
            outfn = NULL;
            break;
        case 'x':
        	whitetext = TRUE;
        	break;
        case 'v':
            loglvl++;
            break;
            break;
        case 'j':
            print_common_only = TRUE;
            break;
        case 'c':
            common_only = TRUE;
            break;
        case 'b':
            Nbright = atoi(optarg);
            break;
        case 'B':
            bright = TRUE;
            break;
        case 'N':
            NGC = TRUE;
            break;
        case 'C':
            constell = TRUE;
            break;
        case 'p':
            pngformat = FALSE;
            break;
        case 's':
            scale = atof(optarg);
            break;
        case 'o':
            outfn = optarg;
            break;
        case 'i':
            infn = optarg;
            break;
        case 'w':
            wcsfn = optarg;
            break;
        case 'W':
            W = atoi(optarg);
            break;
        case 'H':
            H = atoi(optarg);
            break;
        }
    }

    log_init(loglvl);
    log_to(stderr);
    fits_use_error_system();

    if (optind != argc) {
        print_help(args[0]);
        exit(-1);
    }

    if (!(outfn || justlist) || !wcsfn) {
        logerr("Need (-o or -L) and -w args.\n");
        print_help(args[0]);
        exit(-1);
    }

    // read WCS.
    logverb("Trying to parse SIP/TAN header from %s...\n", wcsfn);
    if (!file_exists(wcsfn)) {
        ERROR("No such file: \"%s\"", wcsfn);
        exit(-1);
    }
    if (sip_read_header_file(wcsfn, &sip)) {
        logverb("Got SIP header.\n");
    } else {
        ERROR("Failed to parse SIP/TAN header from %s", wcsfn);
        exit(-1);
    }

    if (!(NGC || constell || bright || HD || grid)) {
        logerr("Neither constellations, bright stars, HD nor NGC/IC overlays selected!\n");
        print_help(args[0]);
        exit(-1);
    }

    if (gridspacing > 0.0)
        grid = TRUE;

    // adjust for scaling...
    lw /= scale;
    cw /= scale;
    nw /= scale;
    crad /= scale;
    endgap /= scale;
    fontsize /= scale;
    label_offset /= scale;

    if (!W || !H) {
        W = sip.wcstan.imagew;
        H = sip.wcstan.imageh;
    }
    if (!(infn || (W && H))) {
        logerr("Image width/height unspecified, and no input image given.\n");
        exit(-1);
    }


    if (infn) {
		cairoutils_fake_ppm_init();
        img = cairoutils_read_ppm(infn, &W, &H);
        if (!img) {
            ERROR("Failed to read input image %s", infn);
            exit(-1);
        }
        cairoutils_rgba_to_argb32(img, W, H);
    } else if (!justlist) {
        // Allocate a black image.
        img = calloc(4 * W * H, 1);
        if (!img) {
            SYSERROR("Failed to allocate a blank image on which to plot!");
            exit(-1);
        }
    }

    if (HD && !hdpath) {
        logerr("If you specify -D (plot Henry Draper objs), you also have to give -d (path to Henry Draper catalog)\n");
        exit(-1);
    }

    if (!justlist) {
        /*
         Cairo layers:

         -background: surfbg / cairobg
         --> gets drawn first, in black, masked by surfshapesmask

         -shapes: surfshapes / cairoshapes
         --> gets drawn second, masked by surfshapesmask

         -foreground/text: surffg / cairo
         --> gets drawn last.
         */
        surffg = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, W, H);
        cairo = cairo_create(surffg);
        cairo_set_line_join(cairo, CAIRO_LINE_JOIN_BEVEL);
        cairo_set_antialias(cairo, CAIRO_ANTIALIAS_GRAY);
        cairo_set_source_rgba(cairo, 1.0, 1.0, 1.0, 1.0);
        cairo_scale(cairo, scale, scale);
        //cairo_select_font_face(cairo, "helvetica", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
        cairo_select_font_face(cairo, "DejaVu Sans Mono Book", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
        cairo_set_font_size(cairo, fontsize);

        surfshapes = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, W, H);
        cairoshapes = cairo_create(surfshapes);
        cairo_set_line_join(cairoshapes, CAIRO_LINE_JOIN_BEVEL);
        cairo_set_antialias(cairoshapes, CAIRO_ANTIALIAS_GRAY);
        cairo_set_source_rgba(cairoshapes, 1.0, 1.0, 1.0, 1.0);
        cairo_scale(cairoshapes, scale, scale);
        cairo_select_font_face(cairoshapes, "DejaVu Sans Mono Book", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
        cairo_set_font_size(cairoshapes, fontsize);

        surfshapesmask = cairo_image_surface_create(CAIRO_FORMAT_A8, W, H);
        cairoshapesmask = cairo_create(surfshapesmask);
        cairo_set_line_join(cairoshapesmask, CAIRO_LINE_JOIN_BEVEL);
        cairo_set_antialias(cairoshapesmask, CAIRO_ANTIALIAS_GRAY);
        cairo_set_source_rgba(cairoshapesmask, 1.0, 1.0, 1.0, 1.0);
        cairo_scale(cairoshapesmask, scale, scale);
        cairo_select_font_face(cairoshapesmask, "DejaVu Sans Mono Book", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
        cairo_set_font_size(cairoshapesmask, fontsize);
        cairo_paint(cairoshapesmask);
        cairo_stroke(cairoshapesmask);

        surfbg = cairo_image_surface_create(CAIRO_FORMAT_A8, W, H);
        cairobg = cairo_create(surfbg);
        cairo_set_line_join(cairobg, CAIRO_LINE_JOIN_BEVEL);
        cairo_set_antialias(cairobg, CAIRO_ANTIALIAS_GRAY);
        cairo_set_source_rgba(cairobg, 0, 0, 0, 1);
        cairo_scale(cairobg, scale, scale);
        cairo_select_font_face(cairobg, "DejaVu Sans Mono Book", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
        cairo_set_font_size(cairobg, fontsize);

        cairos->bg = cairobg;
        cairos->fg = cairo;
        cairos->shapes = cairoshapes;
        cairos->shapesmask = cairoshapesmask;
        cairos->imgW = (float)W/scale;
        cairos->imgH = (float)H/scale;
//    }

    if (grid) {
        double ramin, ramax, decmin, decmax;
        double ra, dec;
        double rastep = gridspacing / 60.0;
        double decstep = gridspacing / 60.0;
        // how many line segments
        int N = 10;
        double px, py;
        int i;

        cairo_set_source_rgba(cairo, gridcolor[0], gridcolor[1], gridcolor[2], 1.0);

        sip_get_radec_bounds(&sip, 100, &ramin, &ramax, &decmin, &decmax);
		logverb("Plotting grid lines from RA=%g to %g in steps of %g; Dec=%g to %g in steps of %g\n",
				ramin, ramax, rastep, decmin, decmax, decstep);
        for (dec = decstep * floor(decmin / decstep); dec<=decmax; dec+=decstep) {
			logverb("  dec=%g\n", dec);
            for (i=0; i<=N; i++) {
                ra = ramin + ((double)i / (double)N) * (ramax - ramin);
                if (!sip_radec2pixelxy(&sip, ra, dec, &px, &py))
                    continue;
                // first time, move_to; else line_to
                ((ra == ramin) ? cairo_move_to : cairo_line_to)(cairo, px, py);
            }
            cairo_stroke(cairo);
        }
        for (ra = rastep * floor(ramin / rastep); ra <= ramax; ra += rastep) {
            //for (dec=decmin; dec<=decmax; dec += (decmax - decmin)/(double)N) {
			logverb("  ra=%g\n", ra);
            for (i=0; i<=N; i++) {
                dec = decmin + ((double)i / (double)N) * (decmax - decmin);
                if (!sip_radec2pixelxy(&sip, ra, dec, &px, &py))
                    continue;
                // first time, move_to; else line_to
                ((dec == decmin) ? cairo_move_to : cairo_line_to)(cairo, px, py);
            }
            cairo_stroke(cairo);
        }

        cairo_set_source_rgba(cairo, 1.0, 1.0, 1.0, 1.0);
    }
  }

    if (constell) {
        N = constellations_n();

        logverb("Checking %i constellations.\n", N);
        for (c=0; c<N; c++) {
            const char* shortname = NULL;
            const char* longname;
            il* lines;
            il* uniqstars;
            il* inboundstars;
            float r,g,b;
            int Ninbounds;
            int Nunique;
            cairo_text_extents_t textents;
            double cmass[3];

            uniqstars = constellations_get_unique_stars(c);
            inboundstars = il_new(16);

            Nunique = il_size(uniqstars);
            debug("%s: %zu unique stars.\n", shortname, il_size(uniqstars));

            // Count the number of unique stars belonging to this contellation
            // that are within the image bounds
            Ninbounds = 0;
            for (i=0; i<il_size(uniqstars); i++) {
                int star;
                star = il_get(uniqstars, i);
                constellations_get_star_radec(star, &ra, &dec);
                debug("star %i: ra,dec (%g,%g)\n", il_get(uniqstars, i), ra, dec);
                if (!sip_radec2pixelxy(&sip, ra, dec, &px, &py))
                    continue;
                if (px < 0 || py < 0 || px*scale > W || py*scale > H)
                    continue;
                Ninbounds++;
                il_append(inboundstars, star);
            }
            il_free(uniqstars);
            debug("%i are in-bounds.\n", Ninbounds);
            // Only draw this constellation if at least 2 of its stars
            // are within the image bounds.
            if (Ninbounds < 2) {
                il_free(inboundstars);
                continue;
            }

            // Set the color based on the location of the first in-bounds star.
            // This is a hack -- we have two different constellation
            // definitions with different numbering schemes!
            if (!justlist && (il_size(inboundstars) > 0)) {
                // This is helpful for videos: ensuring that the same
                // color is chosen for a constellation in each frame.
                int star = il_get(inboundstars, 0);
                constellations_get_star_radec(star, &ra, &dec);
                if (whitetext) {
                	r = g = b = 1;
                } else {
                	color_for_radec(ra, dec, &r, &g, &b);
                }
                cairo_set_source_rgba(cairoshapes, r,g,b,0.8);
                cairo_set_line_width(cairoshapes, cw);
                cairo_set_source_rgba(cairo, r,g,b,0.8);
                cairo_set_line_width(cairo, cw);
            }

            // Draw circles around each star.
            // Find center of mass (of the in-bounds stars)
            cmass[0] = cmass[1] = cmass[2] = 0.0;
            for (i=0; i<il_size(inboundstars); i++) {
                double xyz[3];
                int star = il_get(inboundstars, i);
                constellations_get_star_radec(star, &ra, &dec);
                if (!sip_radec2pixelxy(&sip, ra, dec, &px, &py))
                    continue;
                if (px < 0 || py < 0 || px*scale > W || py*scale > H)
                    continue;
                if (!justlist) {
                    cairo_arc(cairobg, px, py, crad+1.0, 0.0, 2.0*M_PI);
                    cairo_stroke(cairobg);
                    cairo_arc(cairoshapes, px, py, crad, 0.0, 2.0*M_PI);
                    cairo_stroke(cairoshapes);
                }
                radecdeg2xyzarr(ra, dec, xyz);
                cmass[0] += xyz[0];
                cmass[1] += xyz[1];
                cmass[2] += xyz[2];
            }
            cmass[0] /= il_size(inboundstars);
            cmass[1] /= il_size(inboundstars);
            cmass[2] /= il_size(inboundstars);
            xyzarr2radecdeg(cmass, &ra, &dec);

            il_free(inboundstars);

            if (!sip_radec2pixelxy(&sip, ra, dec, &px, &py))
                continue;

            shortname = constellations_get_shortname(c);
            longname = constellations_get_longname(c);
            assert(shortname && longname);

            logverb("%s at (%g, %g)\n", longname, px, py);

            if (Ninbounds == Nunique) {
                printf("The constellation %s (%s)\n", longname, shortname);
            } else {
                printf("Part of the constellation %s (%s)\n", longname, shortname);
            }

            if (justlist)
                continue;

            // If the label will be off-screen, move it back on.
            cairo_text_extents(cairo, shortname, &textents);
			
            if (px < 0)
                px = 0;
            if (py < textents.height)
                py = textents.height;
            if ((px + textents.width)*scale > W)
                px = W/scale - textents.width;
            if ((py+textents.height)*scale > H)
                py = H/scale - textents.height;
            logverb("%s at (%g, %g)\n", shortname, px, py);

            add_text(cairos, longname, px, py, halign, valign);

            // Draw the lines.
            cairo_set_line_width(cairo, lw);
            lines = constellations_get_lines(c);
            for (i=0; i<il_size(lines)/2; i++) {
                int star1, star2;
                double ra1, dec1, ra2, dec2;
                double px1, px2, py1, py2;
                double dx, dy;
                double dist;
                double gapfrac;
                star1 = il_get(lines, i*2+0);
                star2 = il_get(lines, i*2+1);
                constellations_get_star_radec(star1, &ra1, &dec1);
                constellations_get_star_radec(star2, &ra2, &dec2);
                if (!sip_radec2pixelxy(&sip, ra1, dec1, &px1, &py1) ||
                    !sip_radec2pixelxy(&sip, ra2, dec2, &px2, &py2))
                    continue;
                dx = px2 - px1;
                dy = py2 - py1;
                dist = hypot(dx, dy);
                gapfrac = endgap / dist;
                cairo_move_to(cairoshapes, px1 + dx*gapfrac, py1 + dy*gapfrac);
                cairo_line_to(cairoshapes, px1 + dx*(1.0-gapfrac), py1 + dy*(1.0-gapfrac));
                cairo_stroke(cairoshapes);
            }
            il_free(lines);
        }
        logverb("done constellations.\n");
    }

    if (bright) {
        double dy = 0;
        cairo_font_extents_t extents;
        pl* brightstars = pl_new(16);

        if (!justlist) {
            cairo_set_source_rgba(cairoshapes, 0.75, 0.75, 0.75, 0.8);
            cairo_font_extents(cairo, &extents);
            dy = extents.ascent * 0.5;
            cairo_set_line_width(cairoshapes, cw);
        }

        N = bright_stars_n();
        logverb("Checking %i bright stars.\n", N);

        for (i=0; i<N; i++) {
            const brightstar_t* bs = bright_stars_get(i);

            if (!sip_radec2pixelxy(&sip, bs->ra, bs->dec, &px, &py))
                continue;
            if (px < 0 || py < 0 || px*scale > W || py*scale > H)
                continue;
            if (!(bs->name && strlen(bs->name)))
                continue;
            if (common_only && !(bs->common_name && strlen(bs->common_name)))
                continue;

            if (strcmp(bs->common_name, "Maia") == 0)
                continue;

            pl_append(brightstars, bs);
        }

        // keep only the Nbright brightest?
        if (Nbright && (pl_size(brightstars) > Nbright)) {
            pl_sort(brightstars, sort_by_mag);
            pl_remove_index_range(brightstars, Nbright, pl_size(brightstars)-Nbright);
        }

        for (i=0; i<pl_size(brightstars); i++) {
            char* text;
            const brightstar_t* bs = pl_get(brightstars, i);

            if (!sip_radec2pixelxy(&sip, bs->ra, bs->dec, &px, &py))
                continue;
            if (bs->common_name && strlen(bs->common_name))
                if (print_common_only || common_only)
                    text = strdup(bs->common_name);
                else
                    asprintf_safe(&text, "%s (%s)", bs->common_name, bs->name);
            else
                text = strdup(bs->name);

            logverb("%s at (%g, %g)\n", text, px, py);

            if (json) {
                sl* names = sl_new(4);
                char* namearr;
                if (bs->common_name && strlen(bs->common_name))
                    sl_append(names, bs->common_name);
                if (bs->name)
					sl_append(names, bs->name);
				
                namearr = sl_join(names, "\", \"");

                sl_appendf(json,
                           "{ \"type\"  : \"star\", "
                           "  \"pixelx\": %g,       "
                           "  \"pixely\": %g,       "
                           "  \"name\"  : \"%s\",   "
                           "  \"names\" : [ \"%s\" ] } "
                           , px, py,
                           (bs->common_name && strlen(bs->common_name)) ? bs->common_name : bs->name,
                           namearr);
                free(namearr);
                sl_free2(names);
            }

            if (bs->common_name && strlen(bs->common_name))
                printf("The star %s (%s)\n", bs->common_name, bs->name);
            else
                printf("The star %s\n", bs->name);

            if (!justlist) {
                float r,g,b;
                // set color based on RA,Dec to match constellations above.
                if (whitetext) {
                	r = g = b = 1;
                } else {
                	color_for_radec(bs->ra, bs->dec, &r, &g, &b);
                }
                cairo_set_source_rgba(cairoshapes, r,g,b,0.8);
                cairo_set_source_rgba(cairo, r,g,b, 0.8);
            }

            if (!justlist)
                add_text(cairos, text, px + label_offset, py + dy,
						 halign, valign);

            free(text);

            if (!justlist) {
                // plot a black circle behind the light circle...
                cairo_arc(cairobg, px, py, crad+1.0, 0.0, 2.0*M_PI);
                cairo_stroke(cairobg);

                cairo_arc(cairoshapes, px, py, crad, 0.0, 2.0*M_PI);
                cairo_stroke(cairoshapes);
            }
        }
        pl_free(brightstars);
    }

    if (NGC) {
        double imscale;
        double imsize;
        double dy = 0;
        cairo_font_extents_t extents;

        if (!justlist) {
            cairo_set_source_rgb(cairoshapes, 1.0, 1.0, 1.0);
            cairo_set_source_rgb(cairo, 1.0, 1.0, 1.0);
            cairo_set_line_width(cairo, nw);
            cairo_font_extents(cairo, &extents);
            dy = extents.ascent * 0.5;
        }

        // arcsec/pixel
        imscale = sip_pixel_scale(&sip);
        // arcmin
        imsize = imscale * (imin(W, H) / scale) / 60.0;
        N = ngc_num_entries();

        logverb("Checking %i NGC/IC objects.\n", N);

        for (i=0; i<N; i++) {
            ngc_entry* ngc = ngc_get_entry(i);
            sl* str;
            sl* names;
            double pixsize;
            float ara, adec;
            char* text;

            if (!ngc)
                break;
            if (ngc->size < imsize * ngc_fraction)
                continue;

            if (ngcic_accurate_get_radec(ngc->is_ngc, ngc->id, &ara, &adec) == 0) {
                ngc->ra = ara;
                ngc->dec = adec;
            }

            if (!sip_radec2pixelxy(&sip, ngc->ra, ngc->dec, &px, &py))
                continue;
            if (px < 0 || py < 0 || px*scale > W || py*scale > H)
                continue;

            str = sl_new(4);
            //sl_appendf(str, "%s %i", (ngc->is_ngc ? "NGC" : "IC"), ngc->id);
            names = ngc_get_names(ngc, NULL);
            if (names) {
                int n;
                for (n=0; n<sl_size(names); n++) {
                    if (only_messier && strncmp(sl_get(names, n), "M ", 2))
                        continue;
                    sl_append(str, sl_get(names, n));
                }
            }
            sl_free2(names);

            text = sl_implode(str, " / ");

            printf("%s\n", text);

            pixsize = ngc->size * 60.0 / imscale;

            if (!justlist) {
                // black circle behind the white one...
                cairo_arc(cairobg, px, py, pixsize/2.0+1.0, 0.0, 2.0*M_PI);
                cairo_stroke(cairobg);

                cairo_move_to(cairoshapes, px + pixsize/2.0, py);
                cairo_arc(cairoshapes, px, py, pixsize/2.0, 0.0, 2.0*M_PI);
                debug("size: %f arcsec, pixsize: %f pixels\n", ngc->size, pixsize);
                cairo_stroke(cairoshapes);

                add_text(cairos, text, px + label_offset, py + dy,
						 halign, valign);
            }

            if (json) {
                char* namelist = sl_implode(str, "\", \"");
                sl_appendf(json,
                           "{ \"type\"   : \"ngc\", "
                           "  \"names\"  : [ \"%s\" ], "
                           "  \"pixelx\" : %g, "
                           "  \"pixely\" : %g, "
                           "  \"radius\" : %g }"
                           , namelist, px, py, pixsize/2.0);
                free(namelist);
            }

            free(text);
            sl_free2(str);
        }
    }

    if (HD) {
        double rac, decc, ra2, dec2;
        double arcsec;
        hd_catalog_t* hdcat;
        bl* hdlist;
        int i;

        if (!justlist)
            cairo_set_source_rgb(cairo, 1.0, 1.0, 1.0);

		logverb("Reading HD catalog: %s\n", hdpath);
        hdcat = henry_draper_open(hdpath);
        if (!hdcat) {
            ERROR("Failed to open HD catalog");
            exit(-1);
        }
		logverb("Got %i HD stars\n", henry_draper_n(hdcat));

        sip_pixelxy2radec(&sip, W/(2.0*scale), H/(2.0*scale), &rac, &decc);
        sip_pixelxy2radec(&sip, 0.0, 0.0, &ra2, &dec2);
        arcsec = arcsec_between_radecdeg(rac, decc, ra2, dec2);
        // Fudge
        arcsec *= 1.1;
        hdlist = henry_draper_get(hdcat, rac, decc, arcsec);
		logverb("Found %zu HD stars within range (%g arcsec of RA,Dec %g,%g)\n", bl_size(hdlist), arcsec, rac, decc);

        for (i=0; i<bl_size(hdlist); i++) {
            double px, py;
            char* txt;
            hd_entry_t* hd = bl_access(hdlist, i);
            if (!sip_radec2pixelxy(&sip, hd->ra, hd->dec, &px, &py)) {
                continue;
			}
            if (px < 0 || py < 0 || px*scale > W || py*scale > H) {
				logverb("  HD %i at RA,Dec (%g, %g) -> pixel (%.1f, %.1f) is out of bounds\n",
						hd->hd, hd->ra, hd->dec, px, py);
                continue;
			}
            asprintf_safe(&txt, "HD %i", hd->hd);
            if (!justlist) {
                cairo_text_extents_t textents;
                cairo_text_extents(cairo, txt, &textents);
                cairo_arc(cairobg, px, py, crad+1.0, 0.0, 2.0*M_PI);
                cairo_stroke(cairobg);
                cairo_arc(cairoshapes, px, py, crad, 0.0, 2.0*M_PI);
                cairo_stroke(cairoshapes);

                px -= (textents.width * 0.5);
                py -= (crad + 4.0);

                add_text(cairos, txt, px, py, halign, valign);
            }

            if (json)
                sl_appendf(json,
                           "{ \"type\"  : \"hd\","
                           "  \"pixelx\": %g, "
                           "  \"pixely\": %g, "
                           "  \"name\"  : \"HD %i\" }"
                           , px, py, hd->hd);

            printf("%s\n", txt);
            free(txt);
        }
        bl_free(hdlist);
        henry_draper_close(hdcat);
    }

    if (json) {
        FILE* fout = stderr;
        char* annstr = sl_implode(json, ",\n");
        fprintf(fout, "{ \n");
        fprintf(fout, "  \"status\": \"solved\",\n");
        fprintf(fout, "  \"git-revision\": %s,\n", AN_GIT_REVISION);
        fprintf(fout, "  \"git-date\": \"%s\",\n", AN_GIT_DATE);
        fprintf(fout, "  \"annotations\": [\n%s\n]\n", annstr);
        fprintf(fout, "}\n");
        free(annstr);
    }
    sl_free2(json);
    json = NULL;

    if (justlist)
        return 0;

    target = cairo_image_surface_create_for_data(img, CAIRO_FORMAT_ARGB32, W, H, W*4);
    cairot = cairo_create(target);
    cairo_set_source_rgba(cairot, 0, 0, 0, 1);

    // Here's where you set the background surface's properties...
    cairo_set_source_surface(cairot, surfbg, 0, 0);
    cairo_mask_surface(cairot, surfshapesmask, 0, 0);
    cairo_stroke(cairot);

    // Add on the shapes.
    cairo_set_source_surface(cairot, surfshapes, 0, 0);
    //cairo_mask_surface(cairot, surfshapes, 0, 0);
    cairo_mask_surface(cairot, surfshapesmask, 0, 0);
    cairo_stroke(cairot);

    // Add on the foreground.
    cairo_set_source_surface(cairot, surffg, 0, 0);
    cairo_mask_surface(cairot, surffg, 0, 0);
    cairo_stroke(cairot);

    // Convert image for output...
    cairoutils_argb32_to_rgba(img, W, H);

    if (pngformat) {
        if (cairoutils_write_png(outfn, img, W, H)) {
            ERROR("Failed to write PNG");
            exit(-1);
        }
    } else {
        if (cairoutils_write_ppm(outfn, img, W, H)) {
            ERROR("Failed to write PPM");
            exit(-1);
        }
    }

    cairo_surface_destroy(target);
    cairo_surface_destroy(surfshapesmask);
    cairo_surface_destroy(surffg);
    cairo_surface_destroy(surfbg);
    cairo_surface_destroy(surfshapes);
    cairo_destroy(cairo);
    cairo_destroy(cairot);
    cairo_destroy(cairobg);
    cairo_destroy(cairoshapes);
    cairo_destroy(cairoshapesmask);
    free(img);

    return 0;
}
int main (int argc, char *argv[]) {

	krad_v4l2_vpx_display_test_t *display_test;
	krad_flac_t *krad_flac;
	krad_dirac_t *krad_dirac;
	krad_vpx_encoder_t *krad_vpx_encoder;
	//krad_vpx_decoder_t *krad_vpx_decoder;
	kradgui_t *kradgui;
	kradebml_t *ebml;
	cairo_surface_t *cst;
	cairo_t *cr;
	char *filename = "/home/oneman/kode/testmedia/capture/new_testfile4.webm";
	int hud_width, hud_height;
	int hud_stride;
	int hud_byte_size;
	unsigned char *hud_data;
	struct SwsContext *sws_context;

	int fps;

	int videotrack;
	int audiotrack;
	char *device;
	krad_v4l2_t *kradv4l2;
	krad_sdl_opengl_display_t *krad_opengl_display;
	int width;
	int height;
	int count;
	//int first_frame;
	int read_composited;
	
	unsigned char *read_screen_buffer;
	unsigned char *dbuffer;
	unsigned char *dfbuffer;
	krad_audio_t *audio;
	krad_audio_api_t audio_api;
	krad_vorbis_t *krad_vorbis;
	
	hud_width = 320;
	hud_height = 240;

	read_composited = 1;
	//first_frame = 1;
	
	width = 640;
	height = 480;
	fps = 30;
	count = 0;
	int keyframe;
	int bitrate;
	void *frame = NULL;
	void *vpx_packet;
	int packet_size;
	int took;
	int video_codec;
	int audio_codec;
	int framenum;
	int bytes;
	
	bitrate = 1000;
	
	video_codec = 1;
	audio_codec = 1;
		
	if (argc < 2) {
		device = DEFAULT_DEVICE;
		printf("no device provided, using %s , to provide a device, example: krad_v4l2_test /dev/video0\n", device);
	} else {
		device = argv[1];
		printf("Using %s\n", device);
	}

	display_test = calloc(1, sizeof(krad_v4l2_vpx_display_test_t));
	pthread_rwlock_init(&display_test->ebml_write_lock, NULL);
	pthread_rwlock_rdlock(&display_test->ebml_write_lock);
	//display_test->kradtimer = kradtimer_create();
	display_test->input_ringbuffer[0] = krad_ringbuffer_create (RINGBUFFER_SIZE);
	display_test->input_ringbuffer[1] = krad_ringbuffer_create (RINGBUFFER_SIZE);
	display_test->samples[0] = malloc(4 * 8192);
	display_test->samples[1] = malloc(4 * 8192);
	display_test->first_block = 1;
	display_test->audio_codec = audio_codec;
	
	dbuffer = calloc(1, 2000000);
	dfbuffer = calloc(1, 2000000);
	audio_api = JACK;
	//audio = kradaudio_create("krad v4l2 vpx display test", audio_api);
	krad_vorbis = krad_vorbis_encoder_create(2, 44100, 0.7);
	krad_flac = krad_flac_encoder_create(1, 44100, 16);
	
	read_screen_buffer = calloc(1, width * height * 4 * 4 * 4 * 4);
	sws_context = sws_getContext ( width, height, PIX_FMT_RGB32, width, height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
	ebml = kradebml_create();
	//kradebml_open_output_stream(ebml, "192.168.1.2", 9080, "/teststream.webm", "secretkode");
	kradebml_open_output_file(ebml, filename);
	if (video_codec == 1) {
		kradebml_header(ebml, "webm", APPVERSION);
	} else {
		kradebml_header(ebml, "matroska", APPVERSION);
	}
	if (video_codec == 1) {
		videotrack = kradebml_add_video_track(ebml, "V_VP8", 30, width, height);
	}
	if (video_codec == 2) {
		videotrack = kradebml_add_video_track(ebml, "V_DIRAC", 10, width, height);
	}
	if (audio_codec == 1) {
		audiotrack = kradebml_add_audio_track(ebml, "A_VORBIS", 44100, 2, krad_vorbis->header, krad_vorbis->headerpos);
	}
	if (audio_codec == 2) {
		bytes = krad_flac_encoder_read_min_header(krad_flac, dfbuffer);
		audiotrack = kradebml_add_audio_track(ebml, "A_FLAC", 44100, 1, dfbuffer, bytes);
		display_test->krad_flac = krad_flac;
	}	
	kradebml_write(ebml);

	krad_opengl_display = krad_sdl_opengl_display_create(APPVERSION, width, height, width, height);
	//krad_opengl_display = krad_sdl_opengl_display_create(APPVERSION, 1920, 1080, width, height);
	
	krad_vpx_encoder = krad_vpx_encoder_create(width, height, bitrate);
	krad_dirac = krad_dirac_encoder_create(width, height);
	kradgui = kradgui_create(width, height);
	kradgui_add_item(kradgui, REEL_TO_REEL);
	
	hud_stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, hud_width);
	hud_byte_size = hud_stride * hud_height;
	hud_data = calloc (1, hud_byte_size);
	cst = cairo_image_surface_create_for_data (hud_data, CAIRO_FORMAT_ARGB32, hud_width, hud_height, hud_stride);
	
	krad_opengl_display->hud_width = hud_width;
	krad_opengl_display->hud_height = hud_height;
	krad_opengl_display->hud_data = hud_data;
	display_test->audiotrack = audiotrack;
	display_test->ebml = ebml;
	//display_test->audio = audio;
	display_test->krad_vorbis = krad_vorbis;
	display_test->kradgui = kradgui;

	kradv4l2 = kradv4l2_create();

	kradv4l2_open(kradv4l2, device, width, height, fps);
	
	kradv4l2_start_capturing (kradv4l2);
	
	kradgui_reset_elapsed_time(kradgui);
	kradgui->render_timecode = 1;
	
	audio = kradaudio_create("krad v4l2 vpx display test", KINPUT, audio_api);
	display_test->audio = audio;
	pthread_create(&display_test->audio_encoding_thread, NULL, audio_encoding_thread, (void *)display_test);
	
	kradaudio_set_process_callback(audio, krad_v4l2_vpx_display_test_audio_callback, display_test);
	if (audio_api == JACK) {
		krad_jack_t *jack = (krad_jack_t *)audio->api;
		kradjack_connect_port(jack->jack_client, "firewire_pcm:001486af2e61ac6b_Unknown0_in", "krad v4l2 vpx display test:InputLeft");
		kradjack_connect_port(jack->jack_client, "firewire_pcm:001486af2e61ac6b_Unknown0_in", "krad v4l2 vpx display test:InputRight");
	}
	while (count < TEST_COUNT) {
		//kradtimer_start(display_test->kradtimer, "cycle");


		cr = cairo_create(cst);
		kradgui->cr = cr;
		kradgui_render(kradgui);
		cairo_destroy(cr);
		
		frame = kradv4l2_read_frame_wait (kradv4l2);
		
		if (display_test->start_audio == 0) {
			display_test->start_audio = 1;
			usleep(200000);
		}
		
		if (video_codec == 2) {
		//	memcpy(dfbuffer, frame, width * height + (((width * height) / 2) * 2));
		}
		krad_vpx_convert_uyvy2yv12(krad_vpx_encoder->image, frame, width, height);
		///krad_vpx_convert_frame_for_local_gl_display(krad_vpx_encoder);
		kradv4l2_frame_done (kradv4l2);
		
		
		
		krad_sdl_opengl_display_render(krad_opengl_display, krad_vpx_encoder->image->planes[0], krad_vpx_encoder->image->stride[0], krad_vpx_encoder->image->planes[1], krad_vpx_encoder->image->stride[1], krad_vpx_encoder->image->planes[2], krad_vpx_encoder->image->stride[2]);

		krad_sdl_opengl_draw_screen( krad_opengl_display );
		
		if (read_composited) {
			krad_sdl_opengl_read_screen( krad_opengl_display, read_screen_buffer);
			rgb_to_yv12(sws_context, read_screen_buffer, width, height, krad_vpx_encoder->image->planes, krad_vpx_encoder->image->stride);
			vpx_img_flip(krad_vpx_encoder->image);
		}
		
		if (video_codec == 1) {
		
			count++;
		
			packet_size = krad_vpx_encoder_write(krad_vpx_encoder, (unsigned char **)&vpx_packet, &keyframe);

			//printf("packet size was %d\n", packet_size);
			if (read_composited) {
				vpx_img_flip(krad_vpx_encoder->image);
			}
		
			if (packet_size) {
				pthread_rwlock_wrlock(&display_test->ebml_write_lock);
				kradebml_add_video(ebml, videotrack, vpx_packet, packet_size, keyframe);
				//kradebml_write(ebml);
				pthread_rwlock_unlock (&display_test->ebml_write_lock);		
			}


		}
		
		
		if (video_codec == 2) {

//			packet_size = krad_dirac_encode (krad_dirac, dfbuffer, dbuffer, &framenum, &took);
			packet_size = krad_dirac_encode (krad_dirac, krad_vpx_encoder->image->img_data, dbuffer, &framenum, &took);
			if (took == 1) {
				took = 0;
				count++;
			}
	
			if (packet_size > 0) {
				krad_dirac_packet_type(dbuffer[4]);
				//write(fd, buffer, len);
				printf("Encoded size is %d for frame %d\n", packet_size, framenum);
			}
		
			//printf("packet size was %d\n", packet_size);
			if (read_composited) {
				vpx_img_flip(krad_vpx_encoder->image);
			}
		
			keyframe = 0;
		
			if (packet_size) {
				pthread_rwlock_wrlock(&display_test->ebml_write_lock);
				kradebml_add_video(ebml, videotrack, dbuffer, packet_size, keyframe);
				//kradebml_write(ebml);
				pthread_rwlock_unlock (&display_test->ebml_write_lock);		
			}
		
		}
		
	//kradtimer_finish_show(display_test->kradtimer);
	}
	
	display_test->start_audio = 0;
	
	if (video_codec == 2) {
		
		schro_encoder_end_of_stream (krad_dirac->encoder);
//			packet_size = krad_dirac_encode (krad_dirac, dfbuffer, dbuffer, &framenum, &took);

		while ((framenum != count - 1) && (framenum != 0)) {

			packet_size = krad_dirac_encode (krad_dirac, krad_vpx_encoder->image->img_data, dbuffer, &framenum, &took);

			if (packet_size > 0) {
				krad_dirac_packet_type(dbuffer[4]);
				//write(fd, buffer, len);
				printf("Encoded size is %d for frame %d\n", packet_size, framenum);
			} else {
				usleep(50000);
			}
	
			//printf("packet size was %d\n", packet_size);
			if (read_composited) {
				//vpx_img_flip(krad_vpx_encoder->image);
			}
	
			keyframe = 0;
	
			if (packet_size) {
				pthread_rwlock_wrlock(&display_test->ebml_write_lock);
				kradebml_add_video(ebml, videotrack, dbuffer, packet_size, keyframe);
				//kradebml_write(ebml);
				pthread_rwlock_unlock (&display_test->ebml_write_lock);		
			}
	
		}
	
	}
	

	//display_test->start_audio = 0;
	printf("finish audio encoding\n");
	usleep(2000000);
	display_test->stop_audio_encoding = 1;
	
	
	pthread_join(display_test->audio_encoding_thread, NULL);
	
	kradebml_destroy(ebml);

	kradv4l2_stop_capturing (kradv4l2);

	kradv4l2_close(kradv4l2);

	kradv4l2_destroy(kradv4l2);
	krad_dirac_encoder_destroy(krad_dirac);
	krad_vpx_encoder_destroy(krad_vpx_encoder);
	
	// must be before vorbis
	kradaudio_destroy(audio);
	
	krad_vorbis_encoder_destroy(krad_vorbis);
	krad_flac_encoder_destroy(krad_flac);
	free(display_test->samples[0]);
	free(display_test->samples[1]);
	
	krad_sdl_opengl_display_destroy(krad_opengl_display);
	kradgui_destroy(kradgui);
	
	free(read_screen_buffer);
	sws_freeContext (sws_context);
	
	krad_ringbuffer_free ( display_test->input_ringbuffer[0] );
	krad_ringbuffer_free ( display_test->input_ringbuffer[1] );
	pthread_rwlock_destroy(&display_test->ebml_write_lock);
	//kradtimer_destroy(display_test->kradtimer);
	free(display_test);
	free(dbuffer);
	free(dfbuffer);
	return 0;

}