Mostrando entradas con la etiqueta PHP. Mostrar todas las entradas
Mostrando entradas con la etiqueta PHP. Mostrar todas las entradas

AMPortable–Apache+MySQL+PHP Portable


AMPortable[9]

AMPortable v1.2.2 es un software portable que permite ejecutar Apache2, MySQL y PHP5 sin la necesidad de estar instalando nada.

En la captura pueden verlo funcionando en Windows 8 Release Preview, el programa se esconde en la bandeja de sistema. Como pueden apreciar, actualmente se está en la sección de proyectos, en donde se hizo clic derecho en uno de ellos, ahí se desea abrir ese proyecto en Opera u otro navegador que se haya detectado en el sistema.
Bueno, eso es lo que permite actualmente, ya lo estaré publicando en mi sitio web. 

Características:

  • Permite ejecutar Apache2, MySQL5 y PHP5.3 sin necesidad de instalar nada (requiere no tener en ejecución otras instancias de los programas mencionados)
  • Dado que es portable, podemos comprimir toda la carpeta y llevarlo a cualquier lugar y seguir trabajando sin ningún problema.
  • Permite configurar el puerto
  • Permite especificar una carpeta externa para poder enlazarla con un alias
  • Permite visualizar los diferentes proyectos
  • Permite abrir las carpetas de dichos proyectos directamente
  • Permite abrir las carpetas en sublimetext2 directamente
  • Permite abrir los proyectos en los navegadores instalados
  • Permite crear nuevos proyectos (carpetas)
  • Permite visualizar PHPInfo
  • Permite iniciar o detener el servidor http, mysql rápidamente
  • Permite iniciar junto con Windows de manera silenciosa
  • Ofrece un entorno de desarrollo vía web tales como:
    • Codeita
    • IceCoder
    • SQLBuddy
    • SQLDesigner
    • PHPConsole
    • Nitro (TODO list)
    • Enlaces a ayuda online (PHP.net, HTML5 spec, CSS, W3 Schools, jQuery, CSSDeck, Drawter, JSFiddle, JSLint)
  • XDebug habilitado por defecto.
  • Ofrece una extensión para Google Chrome que permite abrir dicho entorno de desarrollo web.

amportable[5]

AMPortable luce así:

  • Ofrece configuración del puerto http a utilizar
  • Una carpeta externa alternativa para no estar copiando nuestros archivos dentro de la carpeta de AMPortable (generalmente se enlazará a localhost/www)
  • También puede buscar el ejecutable de SublimeText2 para luego poder abrir sus proyectos con este increíble editor
  • Los botones Iniciar y Detener nos permiten detener o iniciar tanto el servidor http (Apache aplicando las modificaciones al archivo php.ini de PHP) como el servidor de base de datos (MySQL).
  • El botón phpinfo nos permitirá visualizar los datos de nuestra configuración a PHP
    php5
  • El botón Dev Center nos permitirá abrir en nuestro navegador el entorno web de desarrollo
    amportabledev
  • Si cuenta con el navegador web Google Chrome, podrá instalarlo como una aplicación web
    amportablewebapp
  • Desde Google Chrome podrá acceder al entorno web de desarrollo.
    AMPortablwebapp
  • AMPortable Dev Center contiene las siguientes aplicaciones web

    Codeita: Un editor de código fuente sencillo
    codeita
    SQLBuddy: Un cliente para gestionar la base de datos MySQL
    sqlbuddy
    WWWSQLDesigner
    : Una aplicación web para diseñar visualmente nuestras bases de datos
    sqldesign
    PHP Console: Consola web para probar algunos snippets PHP sin necesidad de estar creando archivos PHP ni mucho menos abriéndolos averiguando su URL.
    phpconsole
    Nitro: Una aplicación web para navegadores webkit, que permite tomar notas rápidas, crear tareas, y además sincronizar con Ubuntu One o DropBox
    nitro
    Referencias online: Permite acceder a diferentes sitios que pueden sernos de mucha ayuda, entre ellos JsFiddle, PHP.net, W3 Schools entre otras.
    jsfiddle
    IceCoder: Otro editor parecido a Codeita, pero más avanzado, aunque ha de notarse su lentitud cuando se tiene muchos archivos en nuestro proyecto.
    icecoder
  • El botón Mostrar proyectos nos permitirá visualizar el listado de proyectos PHP que tengamos en AMPortable, en realidad lista las carpetas dentro de la carpeta content\www\ de AMPortable.
    amportable-proyectos
  • Dentro de esta sección de proyectos podemos interactuar con nuestros proyectos de la siguiente manera:

    amporoycEn el listado sólo tenemos un proyecto, al hacer clic derecho en ese proyecto nos mostrará el menú contextual de la captura.
    Podemos :
    - Abrir en el navegador predeterminado dicho proyecto
    - También podemos abrirlo en los otros navegadores que tengamos instalado, así nos ahorramos estar escribiendo URLs y también evitamos estar ejecutando tales navegadores por separado. Muy necesario el estar verificando cómo se comporta nuestro proyecto en los diferentes navegadores.
    - Además podemos abrir la carpeta de dicho proyecto en el explorador de Windows.
    - Otra opción nos permite abrir la carpeta raíz (la que contiene a todos nuestros proyectos).
    - También podemos crear nuevos proyectos directamente desde ahí
    blogEn este ejemplo vemos cómo creamos un nuevo proyecto (en realidad una nueva carpeta)
    nuevorpyecUna vez creado, podremos abrir la carpeta recién creada en el Explorer

    - Abrir con Sublime Text 2 : nos permitirá abrir dicho proyecto (carpeta) en este genial editor de código fuente.
    sublimetext2

 

Eso es todo por ahora, espero que les sirva así como a mí. Este programa lo pongo a vuestra disposición de manera gratuita, y si desean pueden realizar donaciones aquí http://apps.codigobit.info/p/support.html me servirá de mucho su apoyo, gracias :)

Descargar https://www.box.com/s/a9e3048ccf8383646c43 (20MB)

 

Nuevas características:amportable123

  • Se agregó línea de comandos al menú contextual para gestionar los proyectos por medio de cmd.exe
  • Se corrigió el problema de PATH interno a la carpeta PHP5 y MySQL
    con eso en la línea de comandos se puede utilizar tanto php.exe como mysql.exe
  • Se agregó iconos al menú contextual así como poder utilizar nuestros favicon.ico como icono del proyecto

Cómo subir GIF animados a Twitter


crop avatar twittbio.com

Método obsoleto, ya no funciona.
Otros lo odian, a otros nos gusta, me refiero a los GIF animados como imágenes de perfil para nuestra cuenta de Twitter. “¿Y eso qué? súbanlo y punto”, dirán muchos – es que muchos que queremos tener nuestra imagen de perfil con imágenes animadas GIF en lugar de estáticas no lo tenemos sencillo el poder subirlo, ya que Twitter no permite subir GIF animados a menos que tenga ciertas condiciones que lo han decidido mantener no público.

Antes era posible subir imágenes animadas, pero luego al ver que éstas consumían mucho ancho de banda (por ejemplo 40KB vs 4KB) y con las miles de consultas que recibe el servicio a cada segundo, ya no permitieron eso, pero al ver que muchos usuarios tenían ya sus GIFs animados decidieron mantener las existentes.

Como el sistema que manejan no es perfecto, muchos usuarios podían burlar eso al subir los GIFs con una extensión diferente, optaban por el PNG y Twitter lo aceptaba normalmente. Ya más tarde eso se detectó e hicieron las correcciones y ya no era posible subirlos.

El sistema detectaba que era un GIF animado y no permitía subir.

He aquí como vienen los cambios descubiertos por usuarios en poder subirlos de todas maneras.

El primer método que funcionaba hasta hace poco era la de poder subir GIFs animados alterados, la cual consistía en modificar el archivo binario con un editor hexadecimal, en especial cambiando el último byte que es 0x3B a 0x3C y agregando un byte más 0x2C.

Con eso bastaba, el sistema permitía subirlo sin modificarlo.

Luego de que Twitter se diera cuenta de ello decidió corregirlo, y ahora permite subir GIFs pero NO animados, si resultan ser GIF animados extrae el primer frame resultando una imagen estática.

Y por último, el que todavía funciona (hasta esta fecha),  que es básicamente lo mismo que el anterior, pero con algunos detalles a tomar en cuenta.

MÉTODO MANUAL (más abajo el método sencillo)

PRIMERO:

El archivo animado tiene que ser un GIF animado cuya resolución sea de 48x48 píxeles, es decir cuadrado.

SEGUNDO:

Este archivo no debe sobrepasar los 700KBs que es el límite máximo de tamaño aceptado por Twitter (aunque no lo comprobé).

TERCERO:

Obtener un editor hexadecimal y abrir con ello el archivo GIF, modificar los últimos bytes, es decir cambiarlo de tal forma que tenga lo siguiente: 0x20 0x00 0x3B

twitter gif animado

ESO ES TODO: Ahora sólo quedaría subirlo a nuestra cuenta Twitter y estaremos disfrutando de una imagen de perfil animada.

HERRAMIENTAS RECOMENDADAS:

Para poder crear imágenes GIF recomiendo GIF Movie Gear, aunque es de pago, es un editor que permite recortar y reducir la resolución de la animación:

gif movie gear

Y para modificar los bytes, con WinHEX u otro.

¿AÚN MÁS FÁCIL?

Si no desean realizar todo ese trabajo tedioso y se encuentran con un GIF animado en la web y les gustaría subirlo sin necesidad de realizar todo lo anterior, recomiendo que utilicen mi WebApp que escribí con esos propósitos, lo pueden encontrar en la siguiente dirección http://tweetgif.codigobit.info/ su utilización es muy sencilla.

avatar twittbio.com

Sólo inician sesión utilizando su cuenta Twitter, hace clic en “login with twitter” les mostrará la ventana de confirmación para dar autorización a la aplicación para poder realizar cambios en su cuenta Twitter, aceptan y seguidamente verán sus datos con la posibilidad de elegir el archivo (GIF animado) a subir.

avatar twittbio

Le dan a subir y esperan hasta que el archivo aparezca en un recuadro con el cuadro de selección, para elegir el área que se cortará y reducirá.

crop avatar twittbio.com

Eso es todo, elegida el área a recortar le dan a Crop y el sistema se encargará de realizar el recorte y cambio de resolución a 48x48 además de ello modificará los bytes del formato GIF y lo subirá en vuestra cuenta Twitter.

SUGERENCIA: El hosting que estoy utilizando no me permite realizar procesos que duren más de 15 segundos, así que utilicen GIFs animados no tan complejos y largos.

NOTA: Una de las cosas raras de este “hack” es que la imagen más pequeña, que se muestra en la lista de followers (una de menos resolución 24x24) no se mostrará.

mini avatar

Si tienen sugerencias no duden en dejarlo en los comentarios.

Actualización:
Twitter acepta imágenes GIF animadas de 48x48 píxeles, el hack ya no es necesario, pero aún puede seguir usando este servicio para subir cualquier otro y ahorrarse el estar modificando un GIF de otro tamaño.

PD: Si ya Twitter no permite esto (hablando de un futuro), y descubren otra manera de hacerlo, por favor menciónenlo y así poder actualizar esta aplicación web.

Actualización [20 agosto 2013] Twitter ya no permite subir gif animados para cambiar el perfil :(

Detección de rostros con PHP


La detección de rostros es una tecnología que determina la ubicación y tamaño del rostro humano en cualquier fotografía. Detecta rasgos faciales e ignora cualquier cosa, tales como edificios, árboles y cuerpos.

Buscando información sobre una aplicación que imita a Photobooth de Mac (kPicturebooth), me encontré con una excelente clase PHP que no utiliza ni siquiera la biblioteca opensource OpenCV desarrollada por Intel que también permite detectar rasgos faciales, pero cuyo inconveniente es la de instalarlo en nuestro servidor, un limitante para muchos nosotros.

La detección de rostros en estos días está disponible en distintos dispositivos y/o sitios, por ejemplo en cámaras fotográficas, Google e iPhoto; al parecer una tarea común.

Maurice Svay le dedicó un tiempo a estudiar artículos, papers, etc con la finalidad de crear una alternativa a OpenCV, el sitio web que recomienda es http://www.facedetection.com un sitio web con bastantes recursos sobre ese tema. Sin embargo terminó portando una implementación hecha con canvas+javascript en http://blog.kpicturebooth.com/?p=8 que dicho sea de paso ya no existe tal sitio.

El código que logró realizar gracias al trabajo de Karthik Tharavaad, es el siguiente:

<?php
// 
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.     
// 
// @Author Karthik Tharavaad 
//         karthik_tharavaad@yahoo.com
// @Contributor Maurice Svay
//              maurice@svay.Com

class Face_Detector {
    
    protected $detection_data;
    protected $canvas;
    protected $face;
    private $reduced_canvas;
    
    public function __construct($detection_file = 'detection.dat') {
        if (is_file($detection_file)) {
            $this->detection_data = unserialize(file_get_contents($detection_file));
        } else {
            throw new Exception("Couldn't load detection data");
        }
        //$this->detection_data = json_decode(file_get_contents('data.js'));
    }
    
    public function face_detect($file) {
        if (!is_file($file)) {
            throw new Exception("Can not load $file");
        }
        
        $this->canvas = imagecreatefromjpeg($file);
        $im_width = imagesx($this->canvas);
        $im_height = imagesy($this->canvas);

        //Resample before detection?
        $ratio = 0;
        $diff_width = 320 - $im_width;
        $diff_height = 240 - $im_height;
        if ($diff_width > $diff_height) {
            $ratio = $im_width / 320;
        } else {
            $ratio = $im_height / 240;
        }

        if ($ratio != 0) {
            $this->reduced_canvas = imagecreatetruecolor($im_width / $ratio, $im_height / $ratio);
            imagecopyresampled($this->reduced_canvas, $this->canvas, 0, 0, 0, 0, $im_width / $ratio, $im_height / $ratio, $im_width, $im_height);
            
            $stats = $this->get_img_stats($this->reduced_canvas);
            $this->face = $this->do_detect_greedy_big_to_small($stats['ii'], $stats['ii2'], $stats['width'], $stats['height']);
            $this->face['x'] *= $ratio;
            $this->face['y'] *= $ratio;
            $this->face['w'] *= $ratio;
        } else {
            $stats = $this->get_img_stats($this->canvas);
            $this->face = $this->do_detect_greedy_big_to_small($stats['ii'], $stats['ii2'], $stats['width'], $stats['height']);
        }
        return ($this->face['w'] > 0);
    }
    
    
    public function toJpeg() {
        $color = imagecolorallocate($this->canvas, 255, 0, 0); //red
        imagerectangle($this->canvas, $this->face['x'], $this->face['y'], $this->face['x']+$this->face['w'], $this->face['y']+ $this->face['w'], $color);
        header('Content-type: image/jpeg');
        imagejpeg($this->canvas);
    }
    
    public function toJson() {
        return "{'x':" . $this->face['x'] . ", 'y':" . $this->face['y'] . ", 'w':" . $this->face['w'] . "}";
    }
    
    public function getFace() {
        return $this->face;
    }
    
    protected function get_img_stats($canvas){
        $image_width = imagesx($canvas);
        $image_height = imagesy($canvas);     
        $iis =  $this->compute_ii($canvas, $image_width, $image_height);
        return array(
            'width' => $image_width,
            'height' => $image_height,
            'ii' => $iis['ii'],
            'ii2' => $iis['ii2']
        );         
    }
    
    protected function compute_ii($canvas, $image_width, $image_height ){
        $ii_w = $image_width+1;
        $ii_h = $image_height+1;
        $ii = array();
        $ii2 = array();      
                                
        for($i=0; $i<$ii_w; $i++ ){
            $ii[$i] = 0;
            $ii2[$i] = 0;
        }                        
                                    
        for($i=1; $i<$ii_w; $i++ ){  
            $ii[$i*$ii_w] = 0;       
            $ii2[$i*$ii_w] = 0; 
            $rowsum = 0;
            $rowsum2 = 0;
            for($j=1; $j<$ii_h; $j++ ){
                $rgb = ImageColorAt($canvas, $j, $i);
                $red = ($rgb >> 16) & 0xFF;
                $green = ($rgb >> 8) & 0xFF;
                $blue = $rgb & 0xFF;
                $grey = ( 0.2989*$red + 0.587*$green + 0.114*$blue )>>0;  // this is what matlab uses
                $rowsum += $grey;
                $rowsum2 += $grey*$grey;
                
                $ii_above = ($i-1)*$ii_w + $j;
                $ii_this = $i*$ii_w + $j;
                
                $ii[$ii_this] = $ii[$ii_above] + $rowsum;
                $ii2[$ii_this] = $ii2[$ii_above] + $rowsum2;
            }
        }
        return array('ii'=>$ii, 'ii2' => $ii2);
    }
    
    protected function do_detect_greedy_big_to_small( $ii, $ii2, $width, $height ){
        $s_w = $width/20.0;
        $s_h = $height/20.0;
        $start_scale = $s_h < $s_w ? $s_h : $s_w;
        $scale_update = 1 / 1.2;
        for($scale = $start_scale; $scale > 1; $scale *= $scale_update ){
            $w = (20*$scale) >> 0;
            $endx = $width - $w - 1;
            $endy = $height - $w - 1;
            $step = max( $scale, 2 ) >> 0;
            $inv_area = 1 / ($w*$w);
            for($y = 0; $y < $endy ; $y += $step ){
                for($x = 0; $x < $endx ; $x += $step ){
                    $passed = $this->detect_on_sub_image( $x, $y, $scale, $ii, $ii2, $w, $width+1, $inv_area);
                    if( $passed ) {
                        return array('x'=>$x, 'y'=>$y, 'w'=>$w);
                    }
                } // end x
            } // end y
        }  // end scale
        return null;
    }
    
    protected function detect_on_sub_image( $x, $y, $scale, $ii, $ii2, $w, $iiw, $inv_area){
        $mean = ( $ii[($y+$w)*$iiw + $x + $w] + $ii[$y*$iiw+$x] - $ii[($y+$w)*$iiw+$x] - $ii[$y*$iiw+$x+$w]  )*$inv_area;
        $vnorm =  ( $ii2[($y+$w)*$iiw + $x + $w] + $ii2[$y*$iiw+$x] - $ii2[($y+$w)*$iiw+$x] - $ii2[$y*$iiw+$x+$w]  )*$inv_area - ($mean*$mean);    
        $vnorm = $vnorm > 1 ? sqrt($vnorm) : 1;
        
        $passed = true;
        for($i_stage = 0; $i_stage < count($this->detection_data); $i_stage++ ){
            $stage = $this->detection_data[$i_stage];  
            $trees = $stage[0];  

            $stage_thresh = $stage[1];
            $stage_sum = 0;
                              
            for($i_tree = 0; $i_tree < count($trees); $i_tree++ ){
                $tree = $trees[$i_tree];
                $current_node = $tree[0];    
                $tree_sum = 0;
                while( $current_node != null ){
                    $vals = $current_node[0];
                    $node_thresh = $vals[0];
                    $leftval = $vals[1];
                    $rightval = $vals[2];
                    $leftidx = $vals[3];
                    $rightidx = $vals[4];
                    $rects = $current_node[1];
                    
                    $rect_sum = 0;
                    for( $i_rect = 0; $i_rect < count($rects); $i_rect++ ){
                        $s = $scale;
                        $rect = $rects[$i_rect];
                        $rx = ($rect[0]*$s+$x)>>0;
                        $ry = ($rect[1]*$s+$y)>>0;
                        $rw = ($rect[2]*$s)>>0;  
                        $rh = ($rect[3]*$s)>>0;
                        $wt = $rect[4];
                        
                        $r_sum = ( $ii[($ry+$rh)*$iiw + $rx + $rw] + $ii[$ry*$iiw+$rx] - $ii[($ry+$rh)*$iiw+$rx] - $ii[$ry*$iiw+$rx+$rw] )*$wt;
                        $rect_sum += $r_sum;
                    } 
                     
                    $rect_sum *= $inv_area;
                         
                    $current_node = null;
                    if( $rect_sum >= $node_thresh*$vnorm ){
                        if( $rightidx == -1 ) 
                            $tree_sum = $rightval;
                        else
                            $current_node = $tree[$rightidx];
                    } else {
                        if( $leftidx == -1 )
                            $tree_sum = $leftval;
                        else
                            $current_node = $tree[$leftidx];
                    }
                } 
                $stage_sum += $tree_sum;
            } 
            if( $stage_sum < $stage_thresh ){
                return false;
            }
        } 
        return true;
    }
}

Y para utilizarlo, únicamente lo hacemos de la siguiente manera:

$detector = new Face_Detector('detection.dat');
$detector->face_detect('maurice_svay_150.jpg');
$detector->toJpeg();

El cual nos devolverá el siguiente resultado.

demoFaceRecognition

Requiere de la biblioteca GD y es un poco lento pero debe funcionar en muchos servidores PHP. También es necesario el archivo detection.dat 

NOTA: Claro está que es un inicio funcional con algunas imágenes, con otras demorará más, y no funciona con varios rostros.

 

download

Ejemplo modificado.

Imagen original ~> Resultado  http://svay.com/experiences/face-detection/

Para mayor soporte y dudas, visiten el artículo original.

Face Detection in pure PHP (without OpenCV)