Elemento canvas de HTML

Hoy le daré algo de publicidad al elemento canvas de la especificación HTML versión 5. Esta especificación aún está en estado de borrador pero ha incluido este elemento que ya estaba presente en navegadores como Safari y navegadores basados en Gecko 1.8 como Firefox 1.5 y posteriores. También Opera desde la versión 9 y Chrome soportan canvas. Internet Explorer no lo soporta, aunque algunas personas han querido arreglar esto. A lo largo de este artículo incluyo varios canvas y podréis comprobar si vuestro navegador los soporta simplemente viendo si aparece la imagen del canvas en vuestro navegador.

Canvas es un elemento que permite representar gráficos empleando javascript. Veamos paso por paso como podemos utilizar canvas. Primero creamos el elemento canvas en nuestro html. Este es un ejemplo


<canvas id="micanvas" width="200" height="150">Lo siento, tu navegador no soporta <strong>canvas</strong></canvas>

Sencillo ¿no?. Aquí hemos creado un canvas de 200 pixeles de ancho por 150 de alto y le hemos asignado un identificador para poder referirnos a él posteriormente. Siguiendo la especificación de w3c el valor por defecto del ancho del canvas es 300 pixeles y el del alto es 150 pixeles. Estos valores pueden ser modificados a posteriori empleando hojas de estilo CSS. Si tu navegador no soporta canvas se mostrará el contenido entre las etiquetas canvas permitiendo así mostrar contenido alternativo. Este es el efecto de este código canvas en tu navegador:

Lo siento, tu navegador no soporta canvas

Veamos ahora como a través de javascript podemos pintar algo sobre canvas. Este es el código inicial al que hemos añadido un cuadrado rojo:

var micanvas = document.getElementById(‘micanvas’);
if (micanvas.getContext)
{
var context = micanvas.getContext(‘2d’);
context.fillStyle = “rgb(255,0,0)”;
context.fillRect(20,20,100,120);
}
else
{
//canvas no soportado
}

Veamos el resultado

Lo siento, tu navegador no soporta canvas

Atención, si se modifica el ancho o el alto del objeto canvas la imagen se borra volviendo al estado inicial. Esto se puede lograr como habíamos comentado antes a través de hojas de estilo o en javascript mediante:

micanvas.setAttribute(‘width’,250)

ó

micanvas.width = 250;

También

micanvas.width = micanvas.with

ó

micanvas.height = micanvas.height

Borra el canvas actual pero mantiene su tamaño.

El único contexto válido actualmente es el 2d que tiene una API 2D especifica. Es posible que en el futuro surjan otros contextos, por ejemplo 3d que empleen la API de OPENGL para representar contenido tridimensional con aceleración por hardware (estaremos atentos a esto)

Algunos de los métodos empleados por la API 2d y que podéis utilizar son:

save()
restore()
scale(x, y)
rotate(angle)
translate(x, y)
transform(m11, m12, m21, m22, dx, dy)
setTransform(m11, m12, m21, m22, dx, dy)
globalAlpha [ = value ]
globalCompositeOperation [ = value ]
strokeStyle [ = value ]
fillStyle [ = value ]
clearRect(x, y, w, h)
fillRect(x, y, w, h)
strokeRect(x, y, w, h)
arc(x, y, radius, startAngle, endAngle, anticlockwise)

La lista de métodos es muy extensa aunque no todos están soportados por todos los navegadores.

Por cierto el origen de coordenadas para este contexto esta el borde superior izquierdo.

Bueno para que no os quedéis con las ganas de ver lo que se puede hacer con este elemento os paso unos ejemplos:

canvex, racing, benjoffe

Extendiendo PHP (II)

Puedes encontrar la primera parte del artículo aquí: Extendiendo PHP (I)

En esta segunda parte incluiremos el código necesario para que nuestra función haga su trabajo. Invertir una cadena o devolverla tal y como le ha llegado.

Una implementación en C para invertir una cadena podría ser esta (el código se presenta así con el proposito de ser claro, no óptimo)


#include
#include

char* reverseString(const char* str)
{
char* buffer;
int i=0;
buffer = (char*)malloc(strlen(str)*sizeof(char));
while(str[i]) buffer[strlen(str)-i++-1] = str[i];
return buffer;
}

int main(int argc,char** argv)
{
char* rstr;
rstr = (char*)reverseString("Hola mundo");
printf("%s\n",rstr);
free(rstr);
return(0);
}

Pues bien, habíamos dejado nuestra extensión en el directorio ext/dummy/ en donde podemos encontrar varios ficheros

config.m4 – reglas de configuración para \*nix
config.w32 – reglas de configuración para Güindow$
CREDITS – para meter el nombre de la extensión y tu nombre
EXPERIMENTAL – indica que la extensión es experimental
dummy.c – el código fuente de tu extensión
dummy.php – código de pruebas para tu extensión
Makefile.in – plantilla para el makefile
php_dummy.h – Cabecera para tu extensión
test/ – Directorio con las pruebas de regresión

Pasemos a editar dummy.c. Aunque esté lleno de código y marcaciones que pueden resultar extraños sólo debemos fijarnos en la estructura zend_module_entry llamada dummy_module_entry. Debemos sustituir PHP_RINIT(dummy) y PHP_RSHUTDOWN(dummy) por NULL pues no son necesarias para nuestra extensión. Se trata de código para inicializar o finalizar peticiones a la extensión. El código de la estructura se debe parecer a:


zend_module_entry dummy_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
"dummy",
dummy_functions,
PHP_MINIT(dummy),
PHP_MSHUTDOWN(dummy),
NULL, /* Replace with NULL if there's nothing to do at request start */
NULL, /* Replace with NULL if there's nothing to do at request end */
PHP_MINFO(dummy),
#if ZEND_MODULE_API_NO >= 20010901
"0.1", /* Replace with version number for your extension */
#endif
STANDARD_MODULE_PROPERTIES
};

A continuación aparece comentado código para emplear valores propios de la extensión en las entradas de php.ini. Lo dejaremos como está, comentado, pues no las necesitaremos. Más abajo aparecen las implementaciones de MINIT(), MSHUTDOWN(), RINIT(), RSHUTDOWN() y MINFO(). Para MINIT() y MSHUTDOWN() sólo añadimos el código return SUCCESS; pues no queremos que hagan nada más. RINIT() y RSHUTDOWN() pueden ser borradas pero recuerda borrarlas también en el archivo de cabecera php_dummy.h

La función MINFO() se llama en la llamada a phpinfo() y en ella puedes añadir cualquier información que consideres relevante para la extensión.

Finalmente tenemos la función principal PHP_FUNCTION(dummy) donde agregaremos nuestro código adaptado:


/* {{{ proto string dummy(string msg, bool inv)
Devuelve la misma cadena enviada en orden normal o invertido */
PHP_FUNCTION(dummy)
{
char *msg = NULL;
int argc = ZEND_NUM_ARGS();
int msg_len;
zend_bool inv;
char *buffer = NULL;
int i=0;

if (zend_parse_parameters(argc TSRMLS_CC, "sb", &msg, &msg_len, &inv) == FAILURE)
return;

if(!inv) RETURN_STRINGL(msg, msg_len, 1);
buffer = (char*)malloc(strlen(msg)*sizeof(char));
while(msg[i]) buffer[strlen(msg)-i++-1] = msg[i];
RETURN_STRINGL(buffer, strlen(buffer), 1);
// php_error(E_WARNING, "dummy: not yet implemented");
}
/* }}} */

Antes de construir nuestra extensión debemos editar config.m4 para indicar como el usuario especificará que el módulo debe ser compilado en PHP. Estas líneas, comentadas por defecto, hacen justamente esto:

PHP_ARG_ENABLE(dummy, whether to enable dummy support,
[ --enable-dummy Enable dummy support])

Ahora existen 2 opciones a la hora de construir la extensión puedes hacerlo completamente independiente (standalone) y tu extensión será un módulo compartido cuya compilación será más rápida pero que necesitará ser habilitad desde php.ini para su carga o compilarla directamente en PHP que lleva más tiempo.

Para el modo independiente (standalone) debes ejecutar en el directorio de tu extensión el script phpsize que generará unos ficheros para configurar y construir tu extensión independientemente de PHP.

Luego sólo debes ejecutar:

$ ./configure
$ make
# make install

La extensión generada debería llamarse dummy.so y deberías copiarla al directorio donde php busca sus extensiones externas. Ahora debes precargar tu extensión desde php.ini mediante


extension=dummy.so

O desde el código de php directamente como:


dl('dummy.so');

Para la compilación dentro de PHP debes ejecutar en la raiz del código de PHP5

$ ./buildconf

Esto añadirá la opción –enable-dummy al script ./configure. Para probarlo ejecuta

$ ./configure –help

Ahora puedes construir PHP con:

$ ./configure –enable-dummy –enable-mysql=/usr/ …

También puedes usar –enable-dummy=shared para forzar la compilación como librería compartida

¡Ya puedes probar tu extensión en tus scripts php!

<?php
var_dump(dummy(‘hola mundo’,true));
?>

Una última consideración sobre memoria

La asignación de memoria dinámica es la causa principal de las perdidas de memoria (memory leaks). PHP dispone de funciones propias para la gestión de memoria dinámica. Estas funciones son:

emalloc()
efree()
estrdup()
estrndup()
ecalloc()
erealloc()

Que funcionan exactamente igual que sus contrapartidas en C. Estas funciones son seguras para evitar perdidas de memoria. Así que nuestra extensión tiene que sustituir la llama a malloc por emalloc. También debe ejecutar un efree por cada zona de memoria asignada con emalloc.

Listado páginas acortadoras de urls (tipo tinyurl)

Bueno para los que le interese el tema y quieran probar por ellos mismos cual es el que mejor servicio le ofrece como acortadoras de url hay va una lista.¿Alguién conoce algunas más?:

bit.ly
cli.gs
digg.com
is.gd
kl.am
tinyurl.com
307.to
adjix.com
b23.ru
bacn.me
bloat.me
budurl.com
clipurl.us
cort.as
dwarfurl.com
ff.im
fff.to
href.in
idek.net
korta.nu
lin.cr
ln-s.net
loopt.us
memurl.com
merky.de
moourl.com
nanourl.se
ow.ly
peaurl.com
ping.fm
piurl.com
plurl.me
pnt.me
poprl.com
rde.me
reallytinyurl.com
redir.ec
rubyurl.com
http://short.ie/
short.to
http://smallr.com/
http://sn.vc/
http://snipr.com/
http://snipurl.com/
http://snurl.com/
http://tiny.cc/
http://togoto.us/
tr.im
tra.kz
twurl.cc
twurl.nl
u.mavrev.com
u.nu
ur1.ca
url.az
url.ie
urlx.ie
w34.us
xrl.us
yep.it
zi.ma
zurl.ws
chilp.it
notlong.com
qlnk.net

Increibles casualidades

En Las aventuras de Arthur Gordon Pym, escrito por Edgar Allan Poe en 1850, se cuenta la historia de un naufragio cerca de las islas Malvinas del cual quedan cuatro supervivientes en una balsa. Acuciados por el hambre, sortean entre ellos a quién van a matar para comérselo y pierde un grumete llamado Richard Parker. En 1884, una goleta británica naufragó cerca de las islas Sandwich. Quedaron cuatro supervivientes y echaron a suertes a quién debían matar para comérselo y sobrevivir. La suerte decidió que el desafortunado fuera un grumete llamado Richard Parker.