[cairo-commit] [cairo-www] src/emboss.mdwn
Carl Worth
cworth at freedesktop.org
Tue Oct 26 07:40:43 PDT 2010
src/emboss.mdwn | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 159 insertions(+)
New commits:
commit 448a904b0ab70cd2c7afcbc4d6a3bd959ea061c6
Author: ranma42 <ranma42 at web>
Date: Tue Oct 26 07:40:42 2010 -0700
Add emboss filter example
diff --git a/src/emboss.mdwn b/src/emboss.mdwn
new file mode 100644
index 0000000..7236ea9
--- /dev/null
+++ b/src/emboss.mdwn
@@ -0,0 +1,159 @@
+##Emboss a cairo surface
+
+This sample shows how to apply an emboss effect to a cairo A8 image surface.
+
+ /*
+ Adapted from "Fast Embossing Effects on Raster Image Data"
+
+ Original code by: John Schlag, <jfs at kerner.com>
+ Adapted code by: Jeremy Moles, <cubicool at gmail.com>
+
+ Found in the publication "Graphics Gems IV", Academic Press, 1994
+ */
+
+ #include <cairo.h>
+ #include <math.h>
+ #include <stdio.h>
+ #include <string.h>
+ #include <stdlib.h>
+
+ #define PIXEL_SCALE 255
+ #define WIDTH_45 1
+
+ /* This function will use an exisiting surface's data and create and NEW surface copy
+ // of that data which has the emboss lighting algorightm applied to it. */
+ static cairo_surface_t* _create_embossed_surface_from_surface(
+ cairo_surface_t* surface,
+ double azimuth,
+ double elevation
+ ) {
+ unsigned char* src = cairo_image_surface_get_data(surface);
+ unsigned int width = cairo_image_surface_get_width(surface);
+ unsigned int stride = cairo_image_surface_get_stride(surface);
+ unsigned int height = cairo_image_surface_get_height(surface);
+
+ cairo_surface_t* dstSurface = cairo_image_surface_create(CAIRO_FORMAT_A8, width, height);
+
+ unsigned char* dst = cairo_image_surface_get_data(dstSurface);
+
+ /* Compute the light vector from the input parameters.
+ // Normalize the length to PIXEL_SCALE for fast shading calculation. */
+ long Lx = cos(azimuth) * cos(elevation) * PIXEL_SCALE;
+ long Ly = sin(azimuth) * cos(elevation) * PIXEL_SCALE;
+ long Lz = sin(elevation) * PIXEL_SCALE;
+ long Nz = (6 * 255) / WIDTH_45;
+ long Nz2 = Nz * Nz;
+ long NzLz = Nz * Lz;
+
+ unsigned int y = 1;
+ unsigned int x = 1;
+
+ /* TODO: Would it be better to fill DST with SRC instead of the Lz value?
+ // memcpy(dst, src, stride * height); */
+ memset(dst, Lz, stride * height);
+
+ for(y = 1; y < height - 2; y++) {
+ for(x = 1; x < stride - 1; x++) {
+ unsigned int offset = (y * stride) + x;
+ unsigned char* s1 = src + offset;
+ unsigned char* s2 = s1 + stride;
+ unsigned char* s3 = s2 + stride;
+ unsigned char shade = 0;
+
+ /* Compute the normal from the source. The type of the expression
+ // before the cast is compiler dependent. In some cases the sum is
+ // unsigned, in others it is signed. Ergo, cast to signed. */
+ long Nx = (long)(s1[-1] + s2[-1] + s3[-1] - s1[1] - s2[1] - s3[1]);
+ long Ny = (long)(s3[-1] + s3[0] + s3[1] - s1[-1] - s1[0] - s1[1]);
+
+ long NdotL = Nx * Lx + Ny * Ly + NzLz;
+
+ /* Shade with distant light source. */
+ if(!Nx && !Ny) shade = Lz;
+
+ else if(NdotL < 0) shade = 0;
+
+ else shade = NdotL / sqrt(Nx * Nx + Ny * Ny + Nz2);
+
+ *(dst + offset) = shade;
+ }
+ }
+
+ return dstSurface;
+ }
+
+ /* This function only supports A8 surfaces at the moment, and delegates work to the
+ // similarly named function above. */
+ static cairo_surface_t* create_embossed_surface_from_surface(
+ cairo_surface_t* surface,
+ double azimuth,
+ double elevation
+ ) {
+ if(cairo_image_surface_get_format(surface) != CAIRO_FORMAT_A8) {
+ printf("This example only supports embossing A8 surfaces.\n");
+ printf("It shouldn't be too wildy hard to add other format types.\n");
+
+ return 0;
+ }
+
+ else return _create_embossed_surface_from_surface(surface, azimuth, elevation);
+ }
+
+ int main(int argc, char** argv) {
+ unsigned int w = 400;
+ unsigned int h = 50;
+ unsigned int textSize = 35;
+ const char* text = "Cairo Emboss!!!";
+
+ cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_A8, w, h);
+ cairo_t* cr = cairo_create(surface);
+
+ cairo_text_extents_t extents;
+
+ if(argc != 3) {
+ printf(
+ "usage: %s <int> <int>\nThe two integral arguments passed in are "
+ "the light azimuth and elevation values, in angles.\n",
+ argv[0]
+ );
+
+ goto cleanup;
+ }
+
+ cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
+ cairo_set_font_size(cr, textSize);
+ cairo_text_extents(cr, text, &extents);
+
+ cairo_move_to(
+ cr,
+ ((double)(w - extents.width) / 2.0f) - extents.x_bearing,
+ (double)(h - extents.y_bearing) / 2.0f
+ );
+
+ cairo_show_text(cr, text);
+
+ cairo_surface_t* emboss = create_embossed_surface_from_surface(
+ surface,
+ atoi(argv[1]) * (M_PI / 180.0f),
+ atoi(argv[2]) * (M_PI / 180.0f)
+ );
+
+ if(!emboss) {
+ printf("Calling the emboss function failed; cleaning up and leaving.\n");
+
+ goto cleanup;
+ }
+
+ cairo_surface_write_to_png(surface, "cairo_emboss_normal.png");
+ cairo_surface_write_to_png(emboss, "cairo_emboss_embossed.png");
+
+ printf("Wrote cairo_emboss_{normal,embossed}.png to your local directory.\n");
+
+ cairo_surface_destroy(emboss);
+
+ cleanup:
+ cairo_surface_destroy(surface);
+ cairo_destroy(cr);
+
+ return 0;
+ }
More information about the cairo-commit
mailing list