The Requested Gradient Cannot Be Found: Use the HTML5 Canvas

enter image description here

Some days ago I found that someone was looking for a D3.js expert. To prove one is an expert one has to pass a test, and one of the tasks on this test is to create a 3D color picker with RGB for axes.

The cube faces cannot be filled with a bi-dimensional linear gradients because such gradients are not supported. So, you have to explicitly write a loop to add the pixels.
Using SVG to add the pixels is a bad idea: SVG is an XML language, and uses a DOM tree. Using SVG will use a lot of memory and will slow down your computer. Use a canvas instead. Drawing on a canvas is done by simple Javascript commands, that add lines and shapes.
Following is a little code snippet that fills a cube face:

    for (i=x1; i<=x2;i++){
      for (j=y1; j<=y2; j++){
        rgb_arr[d.rgb_variable[0]]=i;
        rgb_arr[d.rgb_variable[1]]=j;
        ctx.fillStyle=d3.rgb(rgb_arr[0],rgb_arr[1],rgb_arr[2]);
        ctx.fillRect(i,j,1,1);
      }
    }

Now, to get the color where the mouse points, first get the position using the mouse event’s offsetX and offsetY. These properties will hold the correct value even if the canvas is rotated.
Then you can get the RGBA values of the pixel using method getImageData of the canvas’ context. The method returns the data of a rectangle defined by 4 arguments: x,t,width and height.
Following is an example:


<pre class="wp-block-syntaxhighlighter-code">   canvas.on('click', function(evt){
     var ctx=d3.event.target.getContext('2d');
     var pixelData = ctx.getImageData(d3.event.offsetX,d3.event.offsetY,1,1).data;
     alert(pixelData);
  });
</pre>
Advertisement

Overcoming PDF Problems With Firefox

enter image description here

The other day I downloaded “Fahrenheit 451” by Ray Bradbury as a free eBook, and tried to read it. I found that I cannot read much more than the titles of each chapter.

enter image description here
enter image description here

I tried double-clicking and dragging, and saw that something appears on the screen, organized in paragraphs.

Right Click->Inspect Element

enter image description here
enter image description here
enter image description here

Now, a sub-window is opened at the bottom of the screen:

You can see in that sub-window that some text in English appears in a ‘div’ element just under another ‘div’ element of class ‘textLayer’. To the right of the ‘Inspect Element’ sub-window you can see the CSS rules:

As you can see, the value of property ‘color’ is ‘transparent’, You can edit that property using the color selector or by overriding the text value.
Let’s set it to ‘black’.

Now, you can see the paragraphs.
You can change the opacity property of ‘div.textLayer’ from 0.2 to a higher value (up to 1) in order to read the text better.
Firefox is a great PDF viewer, but my browser couldn’t save the document with the changes: the result was a corrupt file that cannot be opened. I’d written about it to the newsgroup ‘mozilla.wishlist’ found on server ‘news.mozilla.org’. and they opened a ticket.

Creating Custom Cursors With GDK-Pixbuf-2 And Cairo

Wait! Why use GDK-2 when there ate later stable versions you can download for free? Sometimes you use a tool – such as OpenCV – that integrates with GTK-2, and GDK-2.

Your operating system may allow you to create custom cursor, or mouse pointers, of your own with colors and an alpha channel (opacity). GDK allows you to create a cursor from a pixel buffer (pixbuf), using the function ‘gdk_cursor_new_from_pixbuf‘.  OK, but first let’s make a pixel buffer. In the documentation of GDK 3, I found 2 functions to create a pixbuf: gdk_pixbuf_get_from_window and gdk_pixbuf_get_from_surface. The latter does not exist in GDK-2. However, there is one method, I haven’t found documented` It’s called gdk_pixbuf_new_from_data.  You can get the data from Cairo after you’ve drawn your image using Cairo.

Using Cairo might be a bit confusing because::

  • Cairo uses two data types for color channels: double-precision floating-point numbers and unsigned 8-bit integers.
  • The color of the cursor is not as intended when calling ‘cairo_set_source_rgba’.

The following function in C will demonstrate what I mean:

Here, when the cursor is created its color is yellow, but if you save your created image to a file it will be cyan.

Yellow cursor over the red square.
Yellow cursor over the red square.
The image when saved to a PNG file

The image when saved to a PNG file

void createCursor(){
    double arcEnd=2*M_PI;
    GdkPixbuf *pixbuf;
    int stride=cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, 10); // Will be used later, when we'll create the pixbuf.
    cairo_surface_t *surf=cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 10, 10); // A canvas of width 10 and height 10.
    cairo_t *cairo_ctx = cairo_create(surf);
    cairo_set_source_rgba(cairo_ctx, 0., 1., 1., 1.); // Double precision values for Red, Green, Blue and Alpha channels between 0 and 1.

    cairo_arc(cairo_ctx,5,5,4,0,arcEnd); // Draw a circle or an arc of a circle whose center is at (5,5) and whose radius is 4
                                         // The arc begins at angle 0 and ends in angle 2Π
    cairo_fill(cairo_ctx); // Fill the circle with cyan, though we've intended to create a yellow one.

    // Create an example image for the blog
    cairo_surface_write_to_png(surf, "/tmp/fortheblog.png");

    guchar *data = cairo_image_surface_get_data(surf); // The data is in BGR, reverse order of RGB !!!

    pixbuf = gdk_pixbuf_new_from_data(data, GDK_COLORSPACE_RGB, true, 8, 10, 10, stride, NULL, NULL); // Stride is the difference in bytes between two
                                                                                                      // consecutive rows.
    cursor=gdk_cursor_new_from_pixbuf(gdk_display_get_default(), pixbuf, 5, 5);

}

“cursor” in this function is a global variable of type “GdkCursor *”.Now, to add the cursor to a window, use gdk_window_set_cursor.

The “gtk_pixbuf_new_from_data” Function.

This function uses the data returned from the function “cairo_image_surface_get_data”. The data is a pointer to a character. The function receiving the data doesn’t know how many characters are referred to, and how to split it into rows and columns. Following is its prototype:

GdkPixbuf *gdk_pixbuf_new_from_data (const guchar *data,
                     GdkColorspace colorspace,
                     gboolean has_alpha,
                     int bits_per_sample,
                     int width, int height,
                     int rowstride,
                     GdkPixbufDestroyNotify destroy_fn,
                     gpointer destroy_fn_data);