Example #1
0
/* ...draw multiline string - hmm; need to put that stuff into display */
static inline void draw_string(cairo_t *cr, const char *fmt, ...)
{
	char                    buffer[4096], *p, *end;
	cairo_text_extents_t    text_extents;
	cairo_font_extents_t    font_extents;
	va_list                 argp;

	cairo_save(cr);
	cairo_select_font_face(cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
	cairo_set_font_size(cr, 40);
	cairo_font_extents(cr, &font_extents);

	va_start(argp, fmt);
	vsnprintf(buffer, sizeof(buffer), fmt, argp);
	va_end(argp);

    for (p = buffer; *p; p = end + 1)
    {
        /* ...output single line */
		((end = strchr(p, '\n')) != NULL ? *end = 0 : 0);
		cairo_show_text(cr, p);
		cairo_text_extents (cr, p, &text_extents);
		cairo_rel_move_to (cr, -text_extents.x_advance, font_extents.height);
        TRACE(0, _b("print text-line: <%f,%f>"), text_extents.x_advance, font_extents.height);

        /* ...stop when last line processes */
        if (!end)   break;
    }

    /* ...restore drawing context */
	cairo_restore(cr);
}
Example #2
0
void shoes_plot_draw_label(cairo_t *cr, shoes_plot *plot,
    int x, int y, char *str, int where)
{
  // TODO: Font was previously set to Helvetica 12 and color was setup
  // keep them for now

  cairo_font_extents_t ft; // TODO: pangocairo way
  cairo_font_extents(cr, &ft);
  int str_h = (int) ceil(ft.height);
  PangoLayout *layout = pango_cairo_create_layout (cr);
  pango_layout_set_font_description (layout , plot->label_pfd);
  pango_layout_set_text (layout, str, -1);
  PangoRectangle ct;
  pango_layout_get_pixel_extents (layout, NULL, &ct);
  int str_w = ct.width;
  int newx = 0;
  int newy = 0;
  if (where == LEFT) { // left side y-axis
    newx = x - (str_w + 3) - 1 ;
    newy = y - (str_h / 2);
  } else if (where == RIGHT) { // right side y-axis
    newx = x;
    newy = y - (str_h / 2);
    //printf("lbl rightx: %i, y: %i, %s\n", (int)newx, (int)newy, str);
  } else if (where == BELOW) { // bottom side x axis
    newx = x - (str_w / 2);
    newy = y + (str_h / 2);
  } else { 
    printf("FAIL: shoes_plot_draw_label 'where ?'\n");
  }
  cairo_move_to(cr, newx, newy);
  pango_cairo_show_layout(cr, layout);
  g_object_unref(layout);
  // printf("TODO: shoes_plot_draw_label called\n");
}
Example #3
0
static void
gst_cairo_time_overlay_update_font_height (GstCairoTimeOverlay * timeoverlay)
{
  gint width, height;
  cairo_surface_t *font_surface;
  cairo_t *font_cairo;
  cairo_font_extents_t font_extents;

  width = timeoverlay->width;
  height = timeoverlay->height;

  font_surface =
      cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
  font_cairo = cairo_create (font_surface);
  cairo_surface_destroy (font_surface);
  font_surface = NULL;

  cairo_select_font_face (font_cairo, "monospace", 0, 0);
  cairo_set_font_size (font_cairo, 20);
  cairo_font_extents (font_cairo, &font_extents);
  timeoverlay->text_height = font_extents.height;
  GST_DEBUG_OBJECT (timeoverlay, "font height is %f", font_extents.height);
  cairo_destroy (font_cairo);
  font_cairo = NULL;
}
Example #4
0
static void
draw (GtkWidget *drawing_area,
      cairo_t *cr,
      FT_Face face)
{
    cairo_font_extents_t font_extents;
    gint *sizes = NULL, n_sizes, alpha_size, pos_y, i;
    const gchar *text;
    cairo_font_face_t *font;

    text = get_sample_string (face);
    sizes = build_sizes_table (face, &n_sizes, &alpha_size);

    font = cairo_ft_font_face_create_for_ft_face (face, 0);
    cairo_set_font_face (cr, font);
    cairo_font_extents (cr, &font_extents);
    cairo_font_face_destroy (font);

    /* draw text */
    pos_y = MAX (font_extents.height, 32) + 4;
    cairo_set_font_size (cr, alpha_size);
    draw_string (cr, lowercase_text, &pos_y);
    draw_string (cr, uppercase_text, &pos_y);
    draw_string (cr, punctuation_text, &pos_y);

    pos_y += 8;
    for (i = 0; i < n_sizes; i++) {
	cairo_set_font_size (cr, sizes[i]);
	draw_string (cr, text, &pos_y);
    }

    g_free (sizes);
}
Example #5
0
static int ui_font_extents(lua_State *L)
{
	struct context *c = lua_touserdata(L, 1);
	const char *str = lua_tostring(L, 2);

	cairo_font_extents_t te;
	cairo_font_extents(c->cr, &te);

	lua_newtable(L);

	lua_pushnumber(L, te.ascent);
	lua_setfield(L, -2, "ascent");

	lua_pushnumber(L, te.descent);
	lua_setfield(L, -2, "descent");

	lua_pushnumber(L, te.height);
	lua_setfield(L, -2, "height");

	lua_pushnumber(L, te.max_x_advance);
	lua_setfield(L, -2, "max_x_advance");

	lua_pushnumber(L, te.max_y_advance);
	lua_setfield(L, -2, "max_y_advance");

	return 1;
}
Example #6
0
static void
draw (cairo_t *cr, struct options *options)
{
    cairo_text_extents_t extents;
    cairo_font_extents_t font_extents;

    cairo_select_font_face (cr,
			    options->family, options->slant, options->weight);
    cairo_set_font_size (cr, options->size);

    cairo_text_extents (cr, options->text, &extents);
    cairo_translate (cr,
		     options->PAD - extents.x_bearing,
		     options->PAD - extents.y_bearing);

    cairo_font_extents (cr, &font_extents);
    cairo_rectangle (cr, 0, -font_extents.ascent,
		      extents.x_advance, font_extents.height);
    cairo_move_to (cr, -options->PAD, 0);
    cairo_line_to (cr, extents.width + options->PAD, 0);
    cairo_set_source_rgba (cr, 1, 0, 0, .7);
    cairo_stroke (cr);

    cairo_rectangle (cr,
		     extents.x_bearing, extents.y_bearing,
		     extents.width, extents.height);
    cairo_set_source_rgba (cr, 0, 1, 0, .7);
    cairo_stroke (cr);

    cairo_move_to (cr, 0, 0);
    cairo_set_source_rgb (cr, 0, 0, 1);
    cairo_show_text (cr, options->text);
    cairo_fill (cr);
}
static VALUE
cr_font_extents (VALUE self)
{
  cairo_font_extents_t extents;
  cairo_font_extents (_SELF, &extents);
  cr_check_status (_SELF);
  return CRFONTEXTENTS2RVAL (&extents);
}
Example #8
0
CAMLprim value
ml_cairo_font_extents (value cr)
{
  cairo_font_extents_t e;
  cairo_font_extents (cairo_t_val (cr), &e);
  check_cairo_status (cr);
  return Val_cairo_font_extents (&e);
}
Example #9
0
static int
cr_font_extents (lua_State *L) {
    cairo_t **obj = luaL_checkudata(L, 1, OOCAIRO_MT_NAME_CONTEXT);
    cairo_font_extents_t extents;
    cairo_font_extents(*obj, &extents);
    create_lua_font_extents(L, &extents);
    return 1;
}
Example #10
0
double gt_graphics_cairo_get_text_height(GtGraphics *gg)
{
  GtGraphicsCairo *g = gt_graphics_cairo_cast(gg);
  cairo_font_extents_t ext;
  gt_assert(g);
  cairo_font_extents(g->cr, &ext);
  return ext.height;
}
Example #11
0
static PyObject *
pycairo_font_extents (PycairoContext *o) {
  cairo_font_extents_t e;

  cairo_font_extents (o->ctx, &e);
  RETURN_NULL_IF_CAIRO_CONTEXT_ERROR(o->ctx);
  return Py_BuildValue("(ddddd)", e.ascent, e.descent, e.height,
		       e.max_x_advance, e.max_y_advance);
}
static PyObject *
pycairo_font_extents (PycairoContext *o)
{
    cairo_font_extents_t e;

    cairo_font_extents (o->ctx, &e);
    if (Pycairo_Check_Status (cairo_status (o->ctx)))
	return NULL;
    return Py_BuildValue("(ddddd)", e.ascent, e.descent, e.height,
			 e.max_x_advance, e.max_y_advance);
}
Example #13
0
File: cawc.c Project: Roger/caw
static PyObject * 
_cairo_font_height(PyObject *self, PyObject *args)
{
    cairo_t *cairo;
    cairo_font_extents_t fe;

    if (!PyArg_ParseTuple(args, "l", &cairo))
        return NULL;

    cairo_font_extents(cairo, &fe);
    return Py_BuildValue("dd", fe.ascent, fe.descent);
    return Py_BuildValue("ii", (int)fe.ascent, (int)fe.descent);
}
Example #14
0
static void
draw_coordinates(cairo_t *cr, double ox, double oy, GLfloat *x, GLfloat *y, int n)
{
	char str[64];
	int i;
	cairo_font_extents_t ext;

	cairo_font_extents(cr, &ext);
	for (i = 0; i < n; i++) {
		snprintf(str, 64, "%d: %14.9f, %14.9f", i, x[i], y[i]);
		cairo_move_to(cr, ox, oy + ext.height * (i + 1));
		cairo_show_text(cr, str);
	}
}
Example #15
0
static int cairo_font_extents_l( lua_State* L )
{
  cairo_font_extents_t extents = {0};
  lua_cairo_t* lc = lua_cairo_check( L, 1 );

  cairo_font_extents( lc->cairo, &extents );

  lua_pushnumber( L, extents.ascent );
  lua_pushnumber( L, extents.descent );
  lua_pushnumber( L, extents.height );
  lua_pushnumber( L, extents.max_x_advance );
  lua_pushnumber( L, extents.max_y_advance );

  return( 5 );
}
Example #16
0
  OBFontMetrics CairoPainter::GetFontMetrics(const std::string &text)
  {
    cairo_font_extents_t fe;
    cairo_font_extents(m_cairo, &fe);
    cairo_text_extents_t te;
    cairo_text_extents(m_cairo, text.c_str(), &te);

    OBFontMetrics metrics;
    metrics.fontSize = m_fontPointSize;
    metrics.ascent = fe.ascent;
    metrics.descent = -fe.descent;
    metrics.width = te.x_advance;//te.width;
    metrics.height = te.height;
    return metrics;
  }
/**
 * Render an CairoFontTexture using this font.
 * 
 **/
void CairoFont::RenderText(string s, IFontTextureResourcePtr texr, int x, int y) {
    CairoFontTexture* tex = dynamic_cast<CairoFontTexture*>(texr.get());
    if (!tex) throw Exception("Font Texture not compatible with SDLFontResource.");
    cairo_t *tcr = tex->cr;
    cairo_text_extents_t te;
    cairo_font_extents_t fe;
    cairo_font_extents (tcr, &fe);
    cairo_set_operator (tcr, CAIRO_OPERATOR_OVER);
    cairo_set_source_rgb (tcr, colr[0], colr[1], colr[2]);
    cairo_select_font_face (tcr, filename.c_str(),
                            slant, weight);
    cairo_set_font_size (tcr, ptsize);
    cairo_text_extents (tcr, s.c_str(), &te);
    cairo_move_to (tcr, x-te.x_bearing, y-te.y_bearing - fe.descent+fe.height/2);
    cairo_show_text (tcr, s.c_str());
    tex->FireChangedEvent(0, 0, tex->width, tex->height);
}
Example #18
0
static cairo_status_t
test_scaled_font_init (cairo_scaled_font_t  *scaled_font,
		       cairo_t              *cr,
		       cairo_font_extents_t *extents)
{
    cairo_set_font_face (cr,
			 cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
							&fallback_font_key));

    cairo_scaled_font_set_user_data (scaled_font,
				     &fallback_font_key,
				     cairo_scaled_font_reference (cairo_get_scaled_font (cr)),
				     (cairo_destroy_func_t) cairo_scaled_font_destroy);

    cairo_font_extents (cr, extents);

    return CAIRO_STATUS_SUCCESS;
}
Example #19
0
static void
draw_string(cairo_t *cr,
	    const char *fmt, ...)
{
	char buffer[4096];
	char *p, *end;
	va_list argp;
	cairo_text_extents_t text_extents;
	cairo_font_extents_t font_extents;

	cairo_save(cr);

	cairo_select_font_face(cr, "sans",
			       CAIRO_FONT_SLANT_NORMAL,
			       CAIRO_FONT_WEIGHT_NORMAL);
	cairo_set_font_size(cr, 14);

	cairo_font_extents (cr, &font_extents);

	va_start(argp, fmt);

	vsnprintf(buffer, sizeof(buffer), fmt, argp);

	p = buffer;
	while (*p) {
		end = strchr(p, '\n');
		if (end)
			*end = 0;

		cairo_show_text(cr, p);
		cairo_text_extents (cr, p, &text_extents);
		cairo_rel_move_to (cr, -text_extents.x_advance, font_extents.height);

		if (end)
			p = end + 1;
		else
			break;
	}

	va_end(argp);

	cairo_restore(cr);

}
Example #20
0
/* adapted from gnome-utils:font-viewer/font-view.c
 *
 * Copyright (C) 2002-2003  James Henstridge <*****@*****.**>
 * Copyright (C) 2010 Cosimo Cecchi <*****@*****.**>
 *
 * License: GPLv2+
 */
static void
draw_string (SushiFontWidget *self,
             cairo_t *cr,
             GtkBorder padding,
	     const gchar *text,
	     gint *pos_y)
{
  cairo_font_extents_t font_extents;
  cairo_text_extents_t extents;
  cairo_glyph_t *glyphs;
  GtkTextDirection text_dir;
  gint pos_x;
  gint num_glyphs;
  gint i;

  text_dir = gtk_widget_get_direction (GTK_WIDGET (self));

  text_to_glyphs (cr, text, &glyphs, &num_glyphs);

  cairo_font_extents (cr, &font_extents);
  cairo_glyph_extents (cr, glyphs, num_glyphs, &extents);

  if (pos_y != NULL)
    *pos_y += font_extents.ascent + font_extents.descent +
      extents.y_advance + LINE_SPACING / 2;
  if (text_dir == GTK_TEXT_DIR_LTR)
    pos_x = padding.left;
  else {
    pos_x = gtk_widget_get_allocated_width (GTK_WIDGET (self)) -
      extents.x_advance - padding.right;
  }

  for (i = 0; i < num_glyphs; i++) {
    glyphs[i].x += pos_x;
    glyphs[i].y += *pos_y;
  }

  cairo_move_to (cr, pos_x, *pos_y);
  cairo_show_glyphs (cr, glyphs, num_glyphs);

  g_free (glyphs);

  *pos_y += LINE_SPACING / 2;
}
Example #21
0
static void *
draw_thread (void *arg)
{
    const char *text = "Hello world. ";
    thread_data_t *thread_data = arg;
    cairo_surface_t *surface;
    cairo_font_extents_t extents;
    cairo_t *cr;
    int i;

    cr = cairo_create (thread_data->target);
    cairo_surface_destroy (thread_data->target);

    cairo_set_source_rgb (cr, 1, 1, 1);
    cairo_paint (cr);
    cairo_set_source_rgb (cr, 0, 0, 0);

    cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Serif",
			    CAIRO_FONT_SLANT_NORMAL,
			    CAIRO_FONT_WEIGHT_NORMAL);
    cairo_set_font_size (cr, NUM_ITERATIONS);
    cairo_font_extents (cr, &extents);

    cairo_move_to (cr, 1, HEIGHT - extents.descent - 1);

    for (i = 0; i < NUM_ITERATIONS; i++) {
	char buf[2];

	cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Serif",
				CAIRO_FONT_SLANT_NORMAL,
				CAIRO_FONT_WEIGHT_NORMAL);
	cairo_set_font_size (cr, i);

	buf[0] = text[i%strlen(text)];
	buf[1] = '\0';
	cairo_show_text (cr, buf);
    }

    surface = cairo_surface_reference (cairo_get_target (cr));
    cairo_destroy (cr);

    return surface;
}
Example #22
0
/* Experimental - Currently messes up the display if larger then 12 point Monospace */
void set_cairo_font_size(cairo_t *cr, font_info *font)
{
	double size;
	cairo_font_extents_t extents;
	cairo_text_extents_t text_extents;
	
	cairo_select_font_face(cr, font->family, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
	size = font->size * (96.0/72.0);
	
	cairo_set_font_size(cr, size);
	
	cairo_font_extents(cr, &extents);
	cairo_text_extents(cr, "@", &text_extents);
	
	font->w = extents.max_x_advance;
	font->h = extents.height;
	font->descent = extents.descent;
	
}
Example #23
0
/**
 * Convert a unit array to a C array of doubles representing NPC values.
 */
static void
unit_array_to_npc(double *result, grid_context_t *gr, char dim, 
                  const unit_array_t *u) 
{
    grid_viewport_node_t *node = gr->current_node;
    double dev_x_per_npc, dev_y_per_npc;
    dev_x_per_npc = dev_y_per_npc = 1.0;
    cairo_matrix_transform_distance(node->npc_to_dev, &dev_x_per_npc, 
                                                      &dev_y_per_npc);

    double x_ntv, y_ntv, w_ntv, h_ntv;
    x_ntv = y_ntv = 0.0;
    w_ntv = h_ntv = 1.0;
    cairo_matrix_transform_point(node->npc_to_ntv, &x_ntv, &y_ntv);
    cairo_matrix_transform_distance(node->npc_to_ntv, &w_ntv, &h_ntv);

    cairo_font_extents_t font_extents;
    cairo_font_extents(gr->cr, &font_extents);

    cairo_text_extents_t em_extents;
    cairo_text_extents(gr->cr, "m", &em_extents);

    double dev_per_npc, o_ntv, size_ntv;
    dev_per_npc = o_ntv = size_ntv = 0.0;

    if (dim == 'x') {
        dev_per_npc = dev_x_per_npc;
        o_ntv = x_ntv;
        size_ntv = w_ntv;
    } else if (dim == 'y') {
        dev_per_npc = dev_y_per_npc;
        o_ntv = y_ntv;
        size_ntv = h_ntv;
    } else {
        fprintf(stderr, "Warning: unknown dimension '%c'\n", dim);
    }

    unit_array_to_npc_helper(result, dev_per_npc, font_extents.height,
                             em_extents.width, o_ntv, size_ntv, 
                             unit_array_size(u), u);
}
Example #24
0
void
StringSizeWithContextReal(cairo_t * c, const char *str, int* w, int* h)
{
    if (!str || str[0] == 0) {
        if (w) *w = 0;
        if (h) *h = 0;
        return;
    }
    if (!fcitx_utf8_check_string(str)) {
        if (w) *w = 0;
        if (h) *h = 0;

        return;
    }
    cairo_text_extents_t extents;
    cairo_font_extents_t fontextents;
    cairo_text_extents(c, str, &extents);
    cairo_font_extents(c, &fontextents);
    if (w)
        *w = extents.x_advance;
    if (h)
        *h = fontextents.height;
}
Example #25
0
static cairo_test_status_t
check_font_extents (const cairo_test_context_t *ctx, cairo_t *cr, const char *comment)
{
    cairo_font_extents_t font_extents, ref_font_extents = {11, 2, 13, 6, 0};
    cairo_status_t status;

    memset (&font_extents, 0xff, sizeof (cairo_font_extents_t));
    cairo_font_extents (cr, &font_extents);

    status = cairo_status (cr);
    if (status)
	return cairo_test_status_from_status (ctx, status);

    if (! font_extents_equal (&font_extents, &ref_font_extents)) {
	cairo_test_log (ctx, "Error: %s: cairo_font_extents(); extents (%g, %g, %g, %g, %g)\n",
			comment,
		        font_extents.ascent, font_extents.descent,
			font_extents.height,
			font_extents.max_x_advance, font_extents.max_y_advance);
	return CAIRO_TEST_FAILURE;
    }

    return CAIRO_TEST_SUCCESS;
}
Example #26
0
int tasklist_paint_task(wtk_widget_t *w, cairo_t *context, clara_wndlist_e_t *wnd, int x)
{
	cairo_font_face_t *face = wtk_get_normal_font();
	cairo_font_extents_t fe;
	cairo_text_extents_t te;
	int t_x, t_y, t_h, t_w;

	t_w = w->rect.w;
	t_h = w->rect.h;
	
	cairo_set_font_face(context, face);
	cairo_set_font_size(context, 16);

	cairo_font_extents (context, &fe);
	cairo_text_extents (context, wnd->title, &te);

	t_x = x + 5;
	t_y = (t_h / 2) - (te.height / 2);

	if (wnd->focused) {
		cairo_rectangle(context, x, 2, te.width + 10, t_h - 4);	
		cairo_set_source_rgb(context, 0.3, 0.3, 1);
		cairo_fill(context);
	}

	cairo_move_to (context, te.x_bearing + t_x + 1,  t_y - te.y_bearing + 1);

	cairo_set_source_rgb (context, 0, 0, 0);
	cairo_show_text (context, wnd->title);

	cairo_move_to (context, te.x_bearing + t_x,  t_y - te.y_bearing);

	cairo_set_source_rgb (context, 1, 1, 1);
	cairo_show_text (context, wnd->title);
	return te.width + 10;
}
Example #27
0
/* Set 'width' and 'height' (either can be NULL), and set values for other constants */
static void timing_dia_get_size(struct vgpu_compute_unit_t *compute_unit, int *width, int *height)
{
	GdkWindow *window;
	cairo_t *cr;

	int widget_width;
	int widget_height;

	widget_width = gtk_widget_get_allocated_width(compute_unit->timing_dia_area);
	widget_height = gtk_widget_get_allocated_height(compute_unit->timing_dia_area);

	window = gtk_widget_get_window(compute_unit->timing_dia_area);
	cr = gdk_cairo_create(window);
	cairo_font_extents(cr, &timing_dia_font_extents);
	timing_dia_col_width = timing_dia_font_extents.max_x_advance * 4;
	timing_dia_row_height = timing_dia_font_extents.ascent + timing_dia_font_extents.descent;

	if (height)
		*height = widget_height / timing_dia_row_height + 2;
	if (width)
		*width = widget_width / timing_dia_col_width + 2;

	cairo_destroy(cr);
}
Example #28
0
static cairo_test_status_t
draw (cairo_t *cr, int width, int height)
{
    const cairo_test_context_t *ctx = cairo_test_get_context (cr);
    FcPattern *pattern;
    cairo_font_face_t *font_face;
    cairo_font_extents_t font_extents;
    cairo_font_options_t *font_options;
    cairo_status_t status;
    char *filename;
    int face_count;
    struct stat stat_buf;

    xasprintf (&filename, "%s/%s", ctx->srcdir, FONT);

    if (stat (filename, &stat_buf) || ! S_ISREG (stat_buf.st_mode)) {
	cairo_test_log (ctx, "Error finding font: %s: file not found?\n", filename);
	return CAIRO_TEST_FAILURE;
    }

    pattern = FcFreeTypeQuery ((unsigned char *)filename, 0, NULL, &face_count);
    free (filename);
    if (! pattern) {
	cairo_test_log (ctx, "FcFreeTypeQuery failed.\n");
	return cairo_test_status_from_status (ctx, CAIRO_STATUS_NO_MEMORY);
    }

    font_face = cairo_ft_font_face_create_for_pattern (pattern);
    FcPatternDestroy (pattern);

    status = cairo_font_face_status (font_face);
    if (status) {
	cairo_test_log (ctx, "Error creating font face for %s: %s\n",
			filename,
			cairo_status_to_string (status));
	return cairo_test_status_from_status (ctx, status);
    }

    if (cairo_font_face_get_type (font_face) != CAIRO_FONT_TYPE_FT) {
	cairo_test_log (ctx, "Unexpected value from cairo_font_face_get_type: %d (expected %d)\n",
			cairo_font_face_get_type (font_face), CAIRO_FONT_TYPE_FT);
	cairo_font_face_destroy (font_face);
	return CAIRO_TEST_FAILURE;
    }

    cairo_set_font_face (cr, font_face);
    cairo_font_face_destroy (font_face);

    font_options = cairo_font_options_create ();

#define CHECK_FONT_EXTENTS(comment) do {\
    cairo_test_status_t test_status; \
    test_status = check_font_extents (ctx, cr, (comment)); \
    if (test_status != CAIRO_TEST_SUCCESS) { \
	cairo_font_options_destroy (font_options); \
	return test_status; \
    } \
} while (0)

    cairo_font_extents (cr, &font_extents);
    CHECK_FONT_EXTENTS ("default");

    cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_ON);
    cairo_set_font_options (cr, font_options);

    CHECK_FONT_EXTENTS ("HINT_METRICS_ON");

    cairo_move_to (cr, 1, font_extents.ascent - 1);
    cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); /* blue */

    cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
    cairo_set_font_options (cr, font_options);
    CHECK_FONT_EXTENTS ("HINT_METRICS_ON HINT_STYLE_NONE");
    cairo_show_text (cr, "the ");

    cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_SLIGHT);
    cairo_set_font_options (cr, font_options);
    CHECK_FONT_EXTENTS ("HINT_METRICS_ON HINT_STYLE_SLIGHT");
    cairo_show_text (cr, "quick ");

    cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_MEDIUM);
    cairo_set_font_options (cr, font_options);
    CHECK_FONT_EXTENTS ("HINT_METRICS_ON HINT_STYLE_MEDIUM");
    cairo_show_text (cr, "brown");

    cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_FULL);
    cairo_set_font_options (cr, font_options);
    CHECK_FONT_EXTENTS ("HINT_METRICS_ON HINT_STYLE_FULL");
    cairo_show_text (cr, " fox");

    /* Switch from show_text to text_path/fill to exercise bug #7889 */
    cairo_text_path (cr, " jumps over a lazy dog");
    cairo_fill (cr);

    /* And test it rotated as well for the sake of bug #7888 */

    cairo_translate (cr, width, height);
    cairo_rotate (cr, M_PI);

    cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_DEFAULT);
    cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_OFF);
    cairo_set_font_options (cr, font_options);
    CHECK_FONT_EXTENTS ("HINT_METRICS_OFF");

    cairo_move_to (cr, 1, font_extents.height - font_extents.descent - 1);

    cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
    cairo_set_font_options (cr, font_options);
    CHECK_FONT_EXTENTS ("HINT_METRICS_OFF HINT_STYLE_NONE");
    cairo_show_text (cr, "the ");

    cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_SLIGHT);
    cairo_set_font_options (cr, font_options);
    CHECK_FONT_EXTENTS ("HINT_METRICS_OFF HINT_STYLE_SLIGHT");
    cairo_show_text (cr, "quick");

    cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_MEDIUM);
    cairo_set_font_options (cr, font_options);
    CHECK_FONT_EXTENTS ("HINT_METRICS_OFF HINT_STYLE_MEDIUM");
    cairo_show_text (cr, " brown");

    cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_FULL);
    cairo_set_font_options (cr, font_options);
    CHECK_FONT_EXTENTS ("HINT_METRICS_OFF HINT_STYLE_FULL");
    cairo_show_text (cr, " fox");

    cairo_text_path (cr, " jumps over");
    cairo_text_path (cr, " a lazy dog");
    cairo_fill (cr);

    cairo_font_options_destroy (font_options);

    return CAIRO_TEST_SUCCESS;
}
Example #29
0
/*==================================================================================
	pstext - subroutine to output text strings.

		x, y - coordinates of the label's reference point, in real coordinates (but see valign and halign, below)
		text - character string to be output
		jchar - length of meaningful character string, 0 if unknown.
		textlen - automatic argument supplied by fortran, gives allocated length of string
		valign: integer alignment code for vertical (from possibly rotated character standpoint) alignment.
			0 = top-aligned
			1 = middle-aligned
			2 = bottom-aligned
			10-12 = y should be considered a number of lines from top margin of page, then alignment=valign-10
			100-902 = valign is given by the final digit.  The y-coordinate should be calculated
				based upon the given y, but then add a number of lines to move down the page from there
				given by this code/100 (e.g., 1-9 lines)
			1000-9002 = valign is given by the final digit.  The y-coordinate should be calculated
			based upon the given y, but then add a number of lines to move up the page from there
			given by this code/1000 (e.g., 1-9 lines)
			(e.g., 202 would mean that the text should be bottom-aligned to the reference point, and 
				the y coordinate is two lines below the supplied y coordinate
		halign: integer alignment code for horizontal (from possibly rotated character standpoint) alignment.
			0 = left-aligned
			1 = center-aligned
			2 = right-aligned
			10-12 = x should be considered a number of lines from left margin of page, then alignment=halign-10
			100-9002 = halign is given by the final digit.  The x coordinate should be calculated based upon
			    the given x, but add a number of points given by this code / 100 (e.g., 1-90).
			REFERENCE_TO_TRACKED_MIN_X - REFERENCE_TO_TRACKED_MIN_X+2 = halign is given by the final digit. The
				x coordinate to be used is the tracked minimum x.
 
==================================================================================*/
void pstext_ (double *x, double *y, char *text, int *jchar, int *valign, int *halign, int textlen) {
	cairo_text_extents_t te;
	cairo_font_extents_t fe;
	cairo_matrix_t curMatrix;
	
	double userX, userY;
	double tempX, tempY;
	int valignCode, halignCode;
	int linesToMove = 0;
	double pointsToMove = 0;
	double xOffset = 0;
	double yOffset = 0;
	char *temptext=malloc(255 * sizeof(char));
	char *mytext;
	
	strncpy(temptext, text, 254);	/* copy only as many characters as will fit in value */

	if (*jchar == 0) {
		temptext[textlen]='\0';
	} else {
		temptext[*jchar]='\0';
	}
	
	mytext = trim(temptext);
	compressSpaces(mytext);
	completeRelativeOperation();

	DEBUGPRINT(("In pstext.  Pt=(%f, %f), DevPoint=(%f, %f), Text=%s, jchar=%i, textlen=%i, valign=%i, halign=%i.\n", *x, *y, deviceX(*x), deviceY(*y), mytext, *jchar, textlen, *valign, *halign));
	cairo_text_extents(dmh_cr,mytext,&te);
	cairo_font_extents (dmh_cr, &fe);
	cairo_set_source_rgb (dmh_cr, 0, 0, 0);	/* black */

	userX = deviceX(*x);	/* change coordinates from real to device */
	userY = deviceY(*y);

	if (dmh_debug) {
		tempX = userX;
		tempY = userY;
		cairo_device_to_user(dmh_cr, &tempX, &tempY);	/* need this to deal with possibly rotated transform */
		cairo_rectangle(dmh_cr, tempX-4, tempY-4, 8, 8);
		cairo_set_source_rgb (dmh_cr, 1, 0.5, 0);
		cairo_fill(dmh_cr);
		cairo_set_source_rgb (dmh_cr, 0, 0, 0);
		cairo_move_to(dmh_cr, tempX, tempY);
	}
	
	DEBUGPRINT(("In pstext.  UserPt=(%f, %f) tempPt=(%f, %f).\n", userX, userY, tempX, tempY));
	if (*valign > 9 && *valign < 100) {
		/* y should be considered a number of lines from top of page.  Note that cairo thinks the origin is at top-left */
		userY = TOPMARGIN + ((int)*y * fe.height);
	} else if (*valign > 99 && *valign < 1000) {
		linesToMove = *valign / 100;
	} else if (*valign > 990 && *valign < 10000) {
		linesToMove = -(*valign / 1000);
	}
	DEBUGPRINT(("In pstext.  LinesToMove=%i.\n", linesToMove));
	if (*halign > 9 && *halign < 100) {
		/* x should be considered a number of lines from top of page.  Note that cairo thinks the origin is at top-left */
		userX = LEFTMARGIN + ((int)*x * fe.height);
	} else if (*halign > 99 && *halign < 10000) {
		pointsToMove = (*halign)/100;
	} else if (*halign >= REFERENCE_TO_TRACKED_MIN_X && *halign <= REFERENCE_TO_TRACKED_MIN_X+2) {
		userX = dmh_min_tracked_x;
		dmh_min_tracked_x = DBL_MAX;	/* Now turn off tracking */
		dmh_track_min_x = 0;
	}

	DEBUGPRINT(("In pstext.  UserPt=(%f, %f).\n", userX, userY));
	cairo_device_to_user(dmh_cr, &userX, &userY);	/* need this to deal with possibly rotated transform */
	cairo_move_to(dmh_cr, userX, userY);
	if (linesToMove != 0) {
		cairo_rel_move_to(dmh_cr, 0, linesToMove * fe.height);
	}
	
	if (pointsToMove != 0) {
		cairo_rel_move_to(dmh_cr, pointsToMove, 0);
	}
	
	if (dmh_debug) {
		cairo_get_current_point(dmh_cr, &tempX, &tempY);
		cairo_rectangle(dmh_cr, tempX-2, tempY-2, 4, 4);
		cairo_set_source_rgb (dmh_cr, 0, 0.5, 1);
		cairo_fill(dmh_cr);
		cairo_set_source_rgb (dmh_cr, 0, 0, 0);
		cairo_move_to(dmh_cr, tempX, tempY);
	}

	valignCode = *valign % 10;
	halignCode = *halign % 10;
	switch (valignCode) {
		case 0:	/* Top-aligned */
			yOffset = te.height + EXTRASPACEPTS;
			break;
		case 1:	/* Middle-aligned */
			yOffset = te.height * 0.5;
			break;
		case 2:	/* Bottom-aligned */
			yOffset = -EXTRASPACEPTS;
			break;
	}

	switch (halignCode) {
		case 0:	/* Left-aligned */
			xOffset = EXTRASPACEPTS;
			break;
		case 1:	/* Center-aligned */
			xOffset = -te.width * 0.5;
			break;
		case 2:	/* Right-aligned */
			xOffset = -te.width - EXTRASPACEPTS;
			break;
	}
	DEBUGPRINT(("In pstext.  Offset=(%f, %f).\n", xOffset, yOffset));
	cairo_rel_move_to(dmh_cr, xOffset, yOffset);

	if (dmh_debug) {
		cairo_get_current_point(dmh_cr, &tempX, &tempY);
		cairo_rectangle(dmh_cr, tempX-2, tempY-2, 4, 4);
		cairo_set_source_rgb (dmh_cr, 1, 0, 0.5);
		cairo_fill(dmh_cr);
		cairo_set_source_rgb (dmh_cr, 0, 0, 0);
		cairo_move_to(dmh_cr, tempX, tempY);
	}

	cairo_get_matrix(dmh_cr, &curMatrix);
	DEBUGPRINT(("Current matrix: %f, %f, %f, %f, %f, %f.\n", curMatrix.xx, curMatrix.yx, curMatrix.xy, curMatrix.yy, curMatrix.x0, curMatrix.y0));

	if (dmh_track_min_x) {
		cairo_get_current_point(dmh_cr, &tempX, &tempY);
		if (tempX < dmh_min_tracked_x) {
			dmh_min_tracked_x = tempX;
		}
	}
	cairo_show_text (dmh_cr, mytext);

	DEBUGPRINT(("Status:%s\n",cairo_status_to_string(cairo_status(dmh_cr))));

	free(temptext);
}
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;
}