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

Main Window Operation In Matplotlib

Matplotlib is a MATLAB-like library that allows Python programmers to create images and animations. For example, you can easily draw a graphic representation of functions with Y (and maybe Z) values generated by numpy and scipy functions.
Matplotlib can also be interactive and handle events. The command mpl_connect is used for connecting an event with a callback function.

The Backend Layer

Someone on the IRC has challenged me with questions on how to perform some operations when the window is closed. In addition, I want the window title to be other than the default, “Figure 1”.
enter image description here

Well, the layer that handles the main window is the backend layer,
To find what backend Matplotlib uses, you can add the line
print type(fig.canvas)
The result may be something like:
<class 'matplotlib.backends.backend_gtkagg.FigureCanvasGTKAgg'>
This means that the backend used is ‘GtkAgg’.
With the function ‘dir’, I’ve found that the canvass has a function named get_toplevel, and the returned value of fig.canvass.get_toplevel() is an object of type gtk.Window.
This object has the methods of a GTK window. So you can change its title with the ‘set_titlemethod. For example:
fig.canvas.get_toplevel().set_title(‘Rubic Cube’)
You can tell your application what to do when the user closes the window, by calling its 'connect' method, with 'destroy' for first arguments.
For example:
fig.canvas.get_toplevel().connect(‘destroy’, destroyFunc, ‘Goodbye, cruel world!’)
destroyFunc` is a function that accept 2 arguments (3 if a class member): the widget where the event has occurred and additional user defined data.
More about Python FTK can be found at http://www.pygtk.org/pygtk2tutorial/index.html

Last but not least, you can specify the backend Matplotlib will use, by calling the ‘use’ method of matplotlib.
For example:
matplotlib.use('GTKAgg')

Note: This method should be called before importing ‘pyplot’.

Written with StackEdit.

Bézier Curves

The Bézier curve is a popular way to draw curves in graphic editors such as GIMP and Inkscape. A curve of degree n is defined using n+1 points, where the first and last are the start and end points of the curve, respectively, and the rest are control points.
For example:
fff
The curve in the image above is a cubic Bézier curve. It has start and end points (filled with blue) and two control points (with no fill).
Each control point is attached by a straight line to a start or an end point, for a reason:

  • The control points allows the user to control the curve intuitively.
  • The straight line between the start(or end) point and its control point is tangent to the curve at the start(or end) point.

The Definition

A Bézier curve is defined as the collection of points that are the result of the function
B(t) for every t in [0,1].
A linear Bézier is simply a straight line between to points P0 and P1. The function is:
(1 – t)BP0 + tBP1

For n>1, Be P0, P1 … Pn the list of the curve’s points. Then the curve’s function is defined as
BP0P1…Pn(t) = (t – 1)BP0P1…Pn-1(t) + tBP1P2…Pn(t)

Or, in its explicit form:

(Not a very precise definition because 00 is not a number, so use the value 1 instead.)

This equation can be proved easily using the Pascal triangle.
From the explicit definition, you can see that the translation is done by adding the same coordinates to which of the curves start, end and control points.
because:
Rotations and translations are done by a transform matrix. So, if T is a transform matrix:
TBP1,P2,…Pn = BTP1,TP2,…TPn

About Tangents

Now, in a Bézier curve, BP0P1…Pn(t), The line P0 – P1 is tangent to the curve at point P0, and Pn – Pn-1 is tangent to the curve at point Pn

To prove this we’ll have to show that the derivative of a Bézier curve of degree n at the start and end points is a non-zero scalar multiplied by the difference between P1 and P0, and between Pn and Pn-1.
That scalar is n.

For n=1;
BP0,P1 = (1 – t)P0 + tP1
Let’s derive:
B’P0,P1 = -P0 + P1

Good!

Let’s assume it’s correct for n, and prove for n+1
BP0,P1…,Pn+1(t) = (1 – t)BP0,P1…,Pn(t) + tBP1,P2…,Pn+1(t)
Let’s derive:
B’P0,P1…,Pn+1(t) = -BP0,P1…,Pn(t) + (1-t)B’P0,P1…,Pn(t) + BP1,P2…,Pn+1(t) + tB’P1,P2…,Pn+1(t)

Now, to get the tangent to the curve at p0, let;s assign t=0:
B’P0,P1…,Pn+1(0) = -BP0,P1…,Pn(0) + B’P0,P1…,Pn(0) + BP1,P2…,Pn+1(0) =
= – P0 + n(P1 – P0) + P1 = (n+1)(P1 – P0)

Good!
Now, to get the tangent to the curve at p0, let;s assign t=1:
B’P0,P1…,Pn+1(1) = -BP0,P1…,Pn(1) + BP1,P2…,Pn+1(1) + B’P1,P2…,Pn+1(1) =
= – Pn + Pn+1 + n(Pn+1 – Pn) + P1 = (n+1)(Pn+1 – Pn)

QED

SVG supports Bézier curves of up to the third degree. A path consisting of such curves are good approximations of shapes provided that you have enough points.

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

Drawing The Koch Snowflake Fractal With GIMP

I once found myself discussing in some forums about conversion of many pictures from one format to another. I knew that many image processors can work in batch mode. The first image processor I thought of was GIMP. As expected, you can get help on this tool when run from the command-line with the option ‘–help’. In linux you can use ‘man gimp” to get more details about the tool. I found that ‘-b’ is the option to use to run GIMP in batch mode, and that the default scripting language is Script-Fu. Now, what is Script-Fu?  From the menu bar: “Help -> GIMP-Online -> User Manual Web Site” leads to the following page:

http://docs.gimp.org/

Now, choose your language and version, and go to the chapter about scripting. Choose section ‘Using Script-Fu Scripts’. This language is based on Scheme, a language very similar to list. To work with Script Fu, choose ‘from the menu bar “Filters->Script-Fu”.

To load an image, use the function ‘gimp-file-load’.

Ti save a file, use the function ‘gimp-file-save’

.Well, this is not the tool I would use to convert image files.

I decided to challenge myself in drawing the Koch-Snowflake  in Script-Fu. The following picture is what the fractal looks like:

Koch

Now, how to draw this fractal? Simply draw an equilateral triangle, and follow the following steps until you no longer have a polygon:

  1.  Split each side of the polygon into three sections equal in length.
  2. Replace the middle section by two sides of an equilateral triangle, pointing outwards.

Now, how to do it with Script-Fu?

Copy the draw-line function from here.

define a function to draw the fractal, with an inner function to draw a side (origianlly, a side of a triangle).

This is the code:

(define (sqr x) (* x x))

(define (draw-line layer x-from y-from x-to y-to) 
  (let* (
          (points (cons-array 4 'double))
        )

        (aset points 0 x-from)
        (aset points 1 y-from)
        (aset points 2 x-to  )
        (aset points 3 y-to  )

        (gimp-pencil layer 4 points)
  )
)

(define (draw-koch-snowflake layer height width)
  (let* (
      ; sin60, cos60 will be used for rotating lines 60 degrees
      (sin60 (/ (sqrt 3) 2)) ; sqrt(3)/2 - No operator precedence in LISP/Scheme
      (cos60 0.5)

      (min-size (min height width))
      (side-length (* sin60 min-size))
    )

    (define (draw-side layer from-x from-y to-x to-y)
      (let* (
           (diff-x (- to-x from-x))
           (diff-y (- to-y from-y))
           (third-diff-x (/ diff-x 3))
           (third-diff-y (/ diff-y 3))
           (squared-length (+ (sqr diff-x) (sqr diff-y)))
         )
       (if (<= squared-length 1)                    ;; The (squared) distance is less than or equal to 1 pixel?
          (draw-line layer from-x from-y to-x to-y) ;; Yes, just draw the line
          (begin                                    ;; No, recursively split the side and draw it.
            ;; recursively draw the 1st section
             (define end-section-1-x (+ from-x third-diff-x))
             (define end-section-1-y (+ from-y third-diff-y))
             (draw-side layer from-x from-y end-section-1-x end-section-1-y)

             ;; create a new vertex, the 2nd section is replaced by 2 sides
             ;; of an equilateral triangle
             ;; This is how you rotate a vector 60 degrees counterclockwise. 
             (define new-vertex-x
               (+ end-section-1-x (* cos60 third-diff-x) (* sin60 third-diff-y))
             ); define new-vertex-y
             (define new-vertex-y
               (+ end-section-1-y (* (- sin60) third-diff-x) (* cos60 third-diff-y))
             ); define new-vertex-y
             (draw-side layer end-section-1-x end-section-1-y new-vertex-x new-vertex-y)

             ;; recursively draw the last section
             ;; and the section from the new vertex to the beginning of
             ;; the last section.
             (define start-section-3x (- to-x third-diff-x))
             (define start-section-3y (- to-y third-diff-y))
             (draw-side layer new-vertex-x new-vertex-y start-section-3x start-section-3y)
             (draw-side layer start-section-3x start-section-3y to-x to-y)
          ) ; End of command block
       );if
      );let* in draw-side
    ); define draw-side
    (define first-vertex-x (/ (- width side-length) 2))
    (define first-vertex-y (- (- height (* side-length sin60)) 
                              (/ (- height min-size) 2)))
    (define start-x first-vertex-x)
    (define start-y first-vertex-y)
    (define end-x (+ start-x side-length))
    (define end-y start-y)
    (draw-side layer start-x start-y end-x end-y)

    (set! start-x end-x)
    (set! start-y end-y)
    (set! end-x (- end-x (* cos60 side-length)))
    (set! end-y (+ end-y (* sin60 side-length)))
    (draw-side layer start-x start-y end-x end-y)

    (set! start-x end-x)
    (set! start-y end-y)
    (set! end-x first-vertex-x)
    (set! end-y first-vertex-y)
    (draw-side layer start-x start-y end-x end-y)

  );  let* in draw-koch-snowflake
)

; The caller function:

(define (koch-caller)
 (let* 
   (
     (my-image (car (gimp-image-new 600 600 RGB)))
     (my-layer (car (gimp-layer-new my-image 600 600 RGB-IMAGE "my layer" 100 NORMAL))) 
     ;; You add a layer because you cannot draw directly on the image object.
   )
   (gimp-image-add-layer my-image my-layer -1)    ; Add the layer to the image
   (gimp-context-set-background '(255 255 255))   ; White background
   (gimp-context-set-foreground '(000 000 000))   ; Black foreground
   (gimp-context-set-opacity 100)                 ; So you can see the picture
   (gimp-drawable-fill my-layer BACKGROUND-FILL)  ; First, fill the layer with background color.
   (gimp-brushes-set-brush "Circle (01)")         ; The thinnest line.
   (draw-koch-snowflake my-layer 600 600)         ; Draw a 600 X 600 snowflake
   (gimp-display-new my-image)                    ; Physically display the result
 )
)

Now, to better understand how to rotate a vector, refer to this Wikipedia entry.