PDF.js librería Javascript para leer PDF en Canvas

Interesante librería Javascript que nos permite mostrar en Canvas (HTML5) el contenido de un PDF. Puede venir muy bien para aplicaciones móviles, ya que en navegación en escritorio normalmente la gente tiene instalado un visor de PDFs.

<html>
<head>
  <title>Simple pdf.js page viewer</title>
  <script type="text/javascript"
          src="pdf.js"></script>
  <style type"text/css">
body {
  margin: 6px;
  padding: 0px;
  background-color: #c0bdb7;
}
#controls {
  border-bottom: 1px solid black;
  position:fixed;
  left: 0px; top: 0px;
  width: 100%;
  padding: 7px;
  background-color: rgb(242, 240, 238);
}
span#info {
  float: right;
  font: 14px sans-serif;
  margin-right: 10px;
}
#viewer {
  margin: auto;
  border: 1px solid black;
  width: 8.5in;
  height: 11in;
}
#pageNumber {
  text-align: right;
}
  </style>
 
<script type="text/javascript">
function queryParams() {
    var qs = window.location.search.substring(1);
    var kvs = qs.split("&");
    var params = { };
    for (var i = 0; i < kvs.length; ++i) {
        var kv = kvs[i].split("=");
        params[unescape(kv[0])] = unescape(kv[1]);
    }
    return params;
}
 
var canvas, numPages, pageDisplay, pageNum;
function load() {
    canvas = document.getElementById("canvas");
    canvas.mozOpaque = true;
    pageDisplay = document.getElementById("pageNumber");
    infoDisplay = document.getElementById("info");
    pageNum = parseInt(queryParams().page) || 1;
    fileName = queryParams().file || "compressed.tracemonkey-pldi-09.pdf";
    open(fileName);
}
 
function open(url) {
    document.title = url;
    req = new XMLHttpRequest();
    req.open("GET", url);
    req.mozResponseType = req.responseType = "arraybuffer";
    req.expected = (document.URL.indexOf("file:") == 0) ? 0 : 200;
    req.onreadystatechange = xhrstate;
    req.send(null);
}
 
function xhrstate() {
    if (req.readyState == 4 && req.status == req.expected) {
        var data = req.mozResponseArrayBuffer ||
                   req.mozResponse ||
                   req.responseArrayBuffer ||
                   req.response;
        pdf = new PDFDoc(new Stream(data));
        numPages = pdf.numPages;
        document.getElementById("numPages").innerHTML = numPages.toString();
        gotoPage(pageNum);
    }
}
 
function displayPage(num) {
    pageDisplay.value = num;
 
    var t0 = Date.now();
 
    var page = pdf.getPage(pageNum = num);
 
    var t1 = Date.now();
 
    var ctx = canvas.getContext("2d");
    ctx.save();
    ctx.fillStyle = "rgb(255, 255, 255)";
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.restore();
 
    var gfx = new CanvasGraphics(ctx);
 
    // page.compile will collect all fonts for us, once we have loaded them
    // we can trigger the actual page rendering with page.display
    var fonts = [];
    page.compile(gfx, fonts);
 
    var t2 = Date.now();
 
    // This should be called when font loading is complete
    page.display(gfx);
 
    var t3 = Date.now();
 
    infoDisplay.innerHTML = "Time to load/compile/render: "+ (t1 - t0) + "/" + (t2 - t1) + "/" + (t3 - t2) + " ms";
}
 
function nextPage() {
    if (pageNum < numPages)
        ++pageNum;
    displayPage(pageNum);
}
 
function prevPage() {
    if (pageNum > 1)
        --pageNum;
    displayPage(pageNum);
}
function gotoPage(num) {
    if (0 <= num && num <= numPages)
        pageNum = num;
    displayPage(pageNum);
}
  </script>
</head>
 
<body onload="load();">
  <div id="controls">
    <button onclick="prevPage();">Previous</button>
    <button onclick="nextPage();">Next</button>
    <input type="text" id="pageNumber" onchange="gotoPage(this.value);"
           value="1" size="4"></input>
    / <span id="numPages">--</span>
    <span id="info"></span>
  </div>
  <div id="viewer">
    <!-- Canvas dimensions must be specified in CSS pixels.  CSS pixels
      -- are always 96 dpi.  These dimensions are 8.5x11in at 96dpi. -->
    <canvas id="canvas" width="816" height="1056"></canvas>
  </div>
</body>
 
</html>

PDF.js

Vía / @badass_js

Share Button

Popcorn.js librería Javascript que permite sincronizar vídeo y contenido en HTML5

Popcorn.js es una librería que permite sincronizar la etiqueta <video> de HTML5 con contenido que deseemos mostrar. Para ello utiliza las propiedades, métodos y eventos nativos de HTMLMediaElement. Además ofrece un sistema de plugins desarrollados por la comunidad:

document.addEventListener("DOMContentLoaded", function () {
      // Create a popcporn instance by calling Popcorn("#id-of-my-video")
      var pop = Popcorn("#video");
      // play the video right away
      pop.play()
      // add a footnote at 2 seconds
        .footnote({
          start: 2,
          end: 6,
          text: "This footnote is the stepping stone of progress!",
          target: "footnotediv"
        });
    }, false);

Podéis ver algunos ejemplos bastante interesantes. Una librería muy útil para presentaciones y vídeos corporativos.

Popcorn.js

Share Button

Conocer los +1 de Google de tus posts de WordPress

Ahora que Google ha sacado el botón +1, puede ser interesante saber que puntuación llevan nuestros posts en Google. Una forma rápida (y un tanto cutre) sería crear un fichero (por ejemplo en la raíz del blog que tenga el siguiente código:

<?php 
define('DOING_CRON', true);
define('DOING_AJAX', true);
require_once('../wp-load.php');
global $wpdb;
$result = $wpdb->get_results("SELECT * from $wpdb->posts where post_status = 'publish' order by ID desc limit 20");
?>
<html>
  <head>
    <title>+1 de Google de mis posts</title>
    <script type="text/javascript" src="https://apis.google.com/js/plusone.js">
      {"parsetags": "explicit"}
    </script>
  </head>
  <body>
<?php foreach($result as $i=>$p) { $url = get_permalink($p->ID); ?>
  <p><?php echo $url; ?><script type="text/javascript">
      gapi.plusone.render("content<?php echo $i; ?>", {"href":"<?php echo $url; ?>"});
    </script>
    <span id="content<?php echo $i; ?>">
      <g:plusone></g:plusone>
    </span>
  </p>
<?php } ?>
  </body>
</html>

Espero que os sea de ayuda

Share Button

Librería PHP para TwitPic

TwitPic es un servicio que se utiliza para subir fotos que luego publicas en Twitter. Si estás realizando una aplicación que tira de Twitter y quieres dar la oportunidad al usuario de subir sus fotos puedes hacer uso de esta aplicación y su API (es necesario darse de alta):

$twitpic = new TwitPic($api_key, $consumer_key, $consumer_secret, $oauth_token, $oauth_secret);
try {
  /*
  * Retrieves all images where the user is facetagged
  */
  $user = $twitpic->faces->show(array('user'=>'meltingice'));
  print_r($user->images);
 
  $media = $twitpic->media->show(array('id'=>1234));
  echo $media->message;
 
  $user = $twitpic->users->show(array('username'=>'meltingice'), array('process'=>false, 'format'=>'xml'));
  echo $user; // raw XML response data
 
  /*
  * Uploads an image to TwitPic
  */
  $resp = $twitpic->upload(array('media'=>'path/to/file.jpg', 'message'=>'This is an example'));
  print_r($resp);
 
  /*
  * Uploads an image to TwitPic AND posts a tweet
  * to Twitter.
  *
  * NOTE: this still uses v2 of the TwitPic API. This means that the code makes 2 separate
  * requests: one to TwitPic for the image, and one to Twitter for the tweet. Because of this,
  * understand this call may take a bit longer than simply uploading the image.
  */
  $resp = $twitpic->uploadAndPost(array('media'=>'path/to/file.jpg', 'message'=>'Another example'));
  print_r($resp);
  
} catch (TwitPicAPIException $e) {
  echo $e->getMessage();
}

TwitPic API for PHP

Share Button

Utilizar websockets con Apache

Creo que los websockets tienen futuro, aunque aún está un poco complicado el meterle mano a la hora de desarrollar. Para quienes quieran usarlo en sus proyectos junto a Apache tan solo tendrán que permitir ejecutar Python en Apache e instalar pywebshocket.

Primero es necesario indicar que Apache reconozca Python en nuestro virtual host:

Options Indexes FollowSymLinks MultiViews
AllowOverride None
Order allow,deny
allow from all
AddHandler mod_python .py
PythonHandler mod_python.publisher
PythonDebug On

Despues instalar pywebshocket:

sudo python setup.py build
sudo python setup.py install

Y por último indicar en el httpd.conf añadirlo al Apache:

PythonPath "sys.path+['/usr/local/lib/python2.6/dist-packages/mod_pywebsocket']"
PythonOption mod_pywebsocket.handler_root /home/travis/Desktop/websock_handlers
PythonHeaderParserHandler mod_pywebsocket.headerparserhandler

How to set up apache to serve html5 websocket applications with pywebsocket

Share Button

MathJax: librería javascript para mostrar fórmulas matemáticas

MathJax es una librería javascript que permite mostrar fórmulas LaTeX y MathML en nuestras páginas. Es compatible con casi todos los navegadores (menos IE5.5 lógicamente), permite copiar el código TeX y MathML de la página, utiliza fuentes CSS y no imágenes o Flash y muchas cosas más.

<!DOCTYPE html>
<html>
<head>
<title>MathJax TeX Test Page</title>
<script type="text/x-mathjax-config">
  MathJax.Hub.Config({tex2jax: {inlineMath: [['$','$'], ['\(','\)']]}});
</script>
<script type="text/javascript"
  src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>
</head>
<body>
When $a \ne 0$, there are two solutions to \(ax^2 + bx + c = 0\) and they are
$$x = {-b \pm \sqrt{b^2-4ac} \over 2a}.$$
</body>
</html>

MathJax

Share Button

jQuery Graceful Websocket: plugin jQuery para websockets

jQuery Graceful Websocket es un plugin jQuery que nos permite comunicarnos con el servidor usando websockets de HTML5. El problema es que tan solo Chrome permite los websokets (creo que Firefox los tiene desactivados por defecto por temas de seguridad), además se necesita que el servidor los pueda tratar, por lo que este plugin permite una alternativa mediante Ajax transparente al desarrollador.

// Si el servidor no admite websockets sustituye el ws:// por http://
var ws = $.gracefulWebSocket("ws://127.0.0.1:8080/");
// Envía datos al servidor. 
// Si el servidor no admite websockets lo envía mediante POST
ws.send("message to server");
// Recibe datos del servidor
// Si el servidor no admite websockets hace un polling mediante GET
ws.onmessage = function (event) {
   var messageFromServer = event.data;   
};

WebSocket plugin for jQuery with graceful degradation

Share Button

phpcassa: librería PHP para Cassandra

Aunque (afortunadamente) Cassandra ya no está tan de moda y en boca de todos, sigue siendo una herramienta a tener en cuenta a la hora de desarrollar un proyecto en el que se calcule un elevado nivel de datos. Para los que usamos PHP nos vendrá muy bien esta librería que nos facilitará el trabajo y que además es compatible con TimeUUID y SuperColumnFamily:

<?php
// Copiar todos los ficheros en el directorio
define('THRIFT_ROOT', dirname(__FILE__) . '/include/thrift/');
require_once THRIFT_ROOT.'/packages/cassandra/Cassandra.php';
require_once THRIFT_ROOT.'/transport/TSocket.php';
require_once THRIFT_ROOT.'/protocol/TBinaryProtocol.php';
require_once THRIFT_ROOT.'/transport/TFramedTransport.php';
require_once THRIFT_ROOT.'/transport/TBufferedTransport.php';
include_once(dirname(__FILE__) . '/include/phpcassa.php');
include_once(dirname(__FILE__) . '/include/uuid.php');
// Setting up nodes:
CassandraConn::add_node('192.168.1.1', 9160);
CassandraConn::add_node('192.168.1.2', 5000);
// Create a column family object
$users = new CassandraCF('Keyspace1', 'Users'); // ColumnFamily
$super = new CassandraCF('Keyspace1', 'SuperColumn', true); // SuperColumnFamily
// Inserting:
$users->insert('1', array('email' => 'email@correo.com', 'password' => 'test'));
// Querying:
$users->get('1'); // array('email' => 'email@correo.com', 'password' => 'test')
$users->multiget(array('1', '2')); // array('1' => array('email' => 'email@correo.com', 'password' => 'test'))
// Removing:
$users->remove('1'); // removes whole object
$users->remove('1', 'password'); // removes 'password' field
// Other:
$users->get_count('1'); // counts the number of columns in user 1 (in this case 2)
$users->get_range('1', '10'); // gets all users between '1' and '10'
?>

phpcassa

Share Button

Hacer un split en MySQL

Normalmente no se suelen necesitar hacer splits en MySQL, porque un buen diseño de la BD debería almacenar los campos en distintas columnas, y si no se puede realizar así, se suele guardar la información serializada en PHP o en formato JSON o XML. Pero no siempre son las cosas como queremos y alguna vez nos podemos encontrar con la necesidad de hacer un split de un campo en MySQL (como me ha pasado a mi ahora).

Hacerlo es fácil, solo es necesario hacer dos substrings, por cada campo:

SELECT `ip` ,
SUBSTRING_INDEX( `ip` , '.', 1 ) AS a,
SUBSTRING_INDEX(SUBSTRING_INDEX( `ip` , '.', 2 ),'.',-1) AS b,
SUBSTRING_INDEX(SUBSTRING_INDEX( `ip` , '.', -2 ),'.',1) AS c,
SUBSTRING_INDEX( `ip` , '.', -1 ) AS d
FROM log_table

MySQL String Functions

Share Button

Crear thumbs con WordPress

Si antes hablaba de una librería que crea thumbs con PHP, ahora comento cómo hacerlo con WordPress, ya que a veces es necesario subir ficheros cuando WP se utiliza para algo más que un simple blog:

// uploadfile tiene el path del fichero subido
// el cuarto parámetro es para que haga crop
$thumb = image_resize($uploadfile, $width, $height, true); 
$upload = wp_upload_dir();
$thumburl = str_replace($upload['path'], $upload['url'],  $thumb );
Share Button