Archivo

Archivo para la categoría ‘linux’

Renderizando PDFs en Python con Poppler II

jueves, 15 de abril de 2010 8 comentarios

Hace unos días me llegó un mail de alguien preguntándome cómo, a partir de la parte I de este artículo, hacer un sencillo visor de PDFs con wxPython. Me encontré con algunas dificultades, principalmente que el ScrolledWindow de wxPython no permite actualizarse dinámicamente, o automáticamente según el contenido (esto sí es bastante sencillo en GTK); con lo cual se complicaba hacer zoom, modificar el tamaño de la ventana y adaptar los scrollbars, etc.

Sin embargo, con alguna vuelta de más pude armar un ejemplo, que paso a dejar acá:

#!/usr/bin/env python
# coding: utf-8
 
""" 
    wxPDFViewer - Simple PDF Viewer using Python-Poppler and wxPython 
    Marcelo Fidel Fernandez - MIT License
    http://www.marcelofernandez.info - marcelo.fidel.fernandez@gmail.com
"""
 
import wx
import wx.lib.wxcairo as wxcairo
import sys
import poppler
 
 
class PDFWindow(wx.ScrolledWindow):
    """ This example class implements a PDF Viewer Window, handling Zoom and Scrolling """
 
    MAX_SCALE = 2
    MIN_SCALE = 1
    SCROLLBAR_UNITS = 20  # pixels per scrollbar unit
 
    def __init__(self, parent):
        wx.ScrolledWindow.__init__(self, parent, wx.ID_ANY)
        # Wrap a panel inside
        self.panel = wx.Panel(self)
        # Initialize variables
        self.n_page = 0
        self.scale = 1
        self.document = None
        self.n_pages = None
        self.current_page = None
        self.width = None
        self.height = None
        # Connect panel events
        self.panel.Bind(wx.EVT_PAINT, self.OnPaint)
        self.panel.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
        self.panel.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
        self.panel.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
 
    def LoadDocument(self, file):
        self.document = poppler.document_new_from_file("file://" + file, None)
        self.n_pages = self.document.get_n_pages()
        self.current_page = self.document.get_page(self.n_page)
        self.width, self.height = self.current_page.get_size() 
        self._UpdateSize()
 
    def OnPaint(self, event):
        dc = wx.PaintDC(self.panel)
        cr = wxcairo.ContextFromDC(dc)
        cr.set_source_rgb(1, 1, 1)  # White background
        if self.scale != 1:
            cr.scale(self.scale, self.scale)
        cr.rectangle(0, 0, self.width, self.height)
        cr.fill()
        self.current_page.render(cr)
 
    def OnLeftDown(self, event):
        self._UpdateScale(self.scale + 0.2)
 
    def OnRightDown(self, event):
        self._UpdateScale(self.scale - 0.2)
 
    def _UpdateScale(self, new_scale):
        if new_scale >= PDFWindow.MIN_SCALE and new_scale <= PDFWindow.MAX_SCALE:
            self.scale = new_scale
            # Obtain the current scroll position
            prev_position = self.GetViewStart() 
            # Scroll to the beginning because I'm going to redraw all the panel
            self.Scroll(0, 0) 
            # Redraw (calls OnPaint and such)
            self.Refresh() 
            # Update panel Size and scrollbar config
            self._UpdateSize()
            # Get to the previous scroll position
            self.Scroll(prev_position[0], prev_position[1]) 
 
    def _UpdateSize(self):
        u = PDFWindow.SCROLLBAR_UNITS
        self.panel.SetSize((self.width*self.scale, self.height*self.scale))
        self.SetScrollbars(u, u, (self.width*self.scale)/u, (self.height*self.scale)/u)
 
    def OnKeyDown(self, event):
        update = True
        # More keycodes in http://docs.wxwidgets.org/stable/wx_keycodes.html#keycodes
        keycode = event.GetKeyCode() 
        if keycode in (wx.WXK_PAGEDOWN, wx.WXK_SPACE):
            next_page = self.n_page + 1
        elif keycode == wx.WXK_PAGEUP:
            next_page = self.n_page - 1
        else:
            update = False
        if update and (next_page >= 0) and (next_page < self.n_pages):
                self.n_page = next_page
                self.current_page = self.document.get_page(next_page)
                self.Refresh()
 
 
class MyFrame(wx.Frame):
 
    def __init__(self):
        wx.Frame.__init__(self, None, -1, "wxPdf Viewer", size=(800,600))
        self.pdfwindow = PDFWindow(self)
        self.pdfwindow.LoadDocument(sys.argv[1])
        self.pdfwindow.SetFocus() # To capture keyboard events
 
 
if __name__=="__main__":
    app = wx.App()
    f = MyFrame()
    f.Show()
    app.MainLoop()

Si bien tengo entendido que el scroll no es «óptimo», ya que en cada OnPaint() se redibuja todo el PDF, anda bastante bien en mi instalación y no parece ser un problema. Lógicamente sí se puede redibujar un área en particular con Cairo (sería la que queda «invalidada» por el scroll), pero wxPython me explotó al intentar algunas cosas por un lado, y me parece que en realidad no sé hacerlo bien por el otro (si alguien puede tirar una soga en esto en particular, bienvenido sea).

Me entretuve mucho haciendo esto, y espero que a alguien le sea de utilidad; y aunque todavía Python-Poppler no está disponible para Windows en forma binaria (pero puede ser compilado, bug acá), sí se puede usar en cualquier Linux, OSX, etc. Y nuevamente, hay una demo para hacer esto mismo con PyGTK, y la demo de Poppler en C es mucho más completa, además de fácil de leer y traducir a Python.

Saludos

Categories: codear, linux, programación, python, ubuntu-ar Tags:

Curso de Asterisk

martes, 30 de marzo de 2010 Sin comentarios

Este es un quick-post como favor a un amigazo que participa de un emprendimiento involucrado en estos cursos de Asterisk

Bitsense empresa dedicada a la implementación de soluciones telefónicas, dará comienzo a su 3er curso de capacitación de Telefonía IP denominado Biac (Bitsense Initial Asterisk Course), el mismo es el primer curso en la Argentina dictado por dos instructores certificados dCAP (Digium-certified Asterisk Professional) junto con el apoyo de certificados Cisco y Juniper.

Para solicitar mas informacion envienos un mail a capacitacion@bitsense.com.ar y un representante se comunicará con usted o llamenos al telefono al 5353.9858 (int 105).

Saludos

Categories: codear, linux, sysadmin Tags:

Cómo remover el módulo USB 2.0 en Ubuntu 9.10+

viernes, 19 de marzo de 2010 1 comentario

Este post va a intentar ser breve y me parece que es bastante técnico, pero puede serle útil a más de uno.

Resulta que yo tengo una Impresora Multifunción Samsung SCX-4200, que tiene unos drivers (cerrados) para Linux [1]. Estos drivers sirven para imprimir y escanear, y si bien hoy en día Ubuntu se las arregla bárbaro para imprimir con los drivers libres de SpliX (¡instalación y configuración automágica!), queda pendiente aún el tema del escaneo.

Por algún motivo al utilizar el scanner (vía USB) la transferencia se caía, y resultó ser que la comunicación Scanner <-> USB 2.0 no funciona, como ya documenté en este mismo blog hace unos años (con la impresión no hay problemas); y no importa la mother, chip o cosa que haya en el medio (lo probé con diferentes equipos). O es esta printer en particular (mucha mala suerte), o es algo del firmware que me tocó en gracia, o… shit happens. 🙁

En fin, en versiones anteriores de Ubuntu anteriores a 9.10, para forzar una comunicación USB 1.1 se solucionaba con un «sudo rmmod ehci_hcd», porque el módulo USB 2.0 (ehci_hcd) era justamente, un módulo que se cargaba dinámicamente. Pero a partir de Ubuntu 9.10 (¿o antes?) este módulo fue incluido en el kernel (estáticamente), con lo cual a priori no tenía manera sencilla de forzar una comunicación USB 1.1 con algún dispositivo (que no sea cambiar el parámetro correspondiente en el BIOS), ya que no es posible descargar un módulo estático del kernel (más info acá).


Me puse a buscar, y encontré una solución. Para simular la «descarga» el módulo es necesario posicionarse en el directorio /sys/bus/pci/drivers/ehci_hcd y pasarle al archivo «unbind» qué hub USB «unbindear» (¿»desrelacionar»?); los hubs USB se pueden ver con un lsusb -v, y los que van a aparecer en el directorio mencionado son los de «Full Speed», o sea, los de USB 2.0 [2] .

Si tu PC soporta USB 2.0 (y por ende tenés este problema, je), al menos uno hay, que corresponde al Hub de la motherboard. En mi caso hay dos, pero para no andar especulando (y porque quiero que el scanner funcione sin averiguar a cuál de los dos hub está conectado en particular), «unbindeo»/»desrelaciono»/»desenlazo» (?) ambos hubs:

marcelo@marcelo-laptop:~$ sudo -i
[sudo] password for marcelo:
root@marcelo-laptop:~# cd /sys/bus/pci/drivers/ehci_hcd/
root@marcelo-laptop:/sys/bus/pci/drivers/ehci_hcd# ls -l
total 0
lrwxrwxrwx 1 root root    0 2010-03-19 14:12 0000:00:1a.7 -> ../../../../devices/pci0000:00/0000:00:1a.7
lrwxrwxrwx 1 root root    0 2010-03-19 14:12 0000:00:1d.7 -> ../../../../devices/pci0000:00/0000:00:1d.7
--w------- 1 root root 4096 2010-03-19 14:12 bind
lrwxrwxrwx 1 root root    0 2010-03-19 14:12 module -> ../../../../module/ehci_hcd
--w------- 1 root root 4096 2010-03-19 14:12 new_id
--w------- 1 root root 4096 2010-03-19 14:12 remove_id
--w------- 1 root root 4096 2010-03-19 14:12 uevent
--w------- 1 root root 4096 2010-03-19 14:12 unbind
root@marcelo-laptop:/sys/bus/pci/drivers/ehci_hcd# echo -n 0000\:00\:1a.7 > unbind
root@marcelo-laptop:/sys/bus/pci/drivers/ehci_hcd# echo -n 0000\:00\:1d.7 > unbind
root@marcelo-laptop:/sys/bus/pci/drivers/ehci_hcd# ls -l
total 0
--w------- 1 root root 4096 2010-03-19 14:12 bind
lrwxrwxrwx 1 root root    0 2010-03-19 14:12 module -> ../../../../module/ehci_hcd
--w------- 1 root root 4096 2010-03-19 14:12 new_id
--w------- 1 root root 4096 2010-03-19 14:12 remove_id
--w------- 1 root root 4096 2010-03-19 14:12 uevent
--w------- 1 root root 4096 2010-03-19 14:21 unbind
root@marcelo-laptop:/sys/bus/pci/drivers/ehci_hcd#
Listo el pollo. Todos los dispositivos USB que estén conectados por medio de estos Hubs van a ser reconocidos y utilizados por el «fallback», USB 1.1; en definitiva, este es manejado por el módulo linux uhci_hcd, como podemos ver con el comando dmesg:
[...]
[64720.180444] ehci_hcd 0000:00:1a.7: remove, state 4
[64720.180464] usb usb1: USB disconnect, address 1
[64720.184731] ehci_hcd 0000:00:1a.7: USB bus 1 deregistered
[64720.184838] ehci_hcd 0000:00:1a.7: PCI INT C disabled
[64730.610396] ehci_hcd 0000:00:1d.7: remove, state 1
[64730.610417] usb usb2: USB disconnect, address 1
[64730.610422] usb 2-4: USB disconnect, address 3
[64730.684860] ehci_hcd 0000:00:1d.7: USB bus 2 deregistered
[64730.684980] ehci_hcd 0000:00:1d.7: PCI INT A disabled
[64731.070210] usb 6-2: new full speed USB device using uhci_hcd and address 5
[64731.254158] usb 6-2: configuration #1 chosen from 1 choice
[64731.259814] uvcvideo: Found UVC 1.00 device FO13FF-50 PC-CAM (05c8:0100)
[64731.273207] input: FO13FF-50 PC-CAM as /devices/pci0000:00/0000:00:1d.1/usb6/6-2/6-2:1.0/input/input11
[...]

En mi caso no tenía conectada la impresora, pero sirve el ejemplo de todas maneras ver cómo la webcam es reconocida por uhci_hcd (USB 1.1). Para volver atrás, supongo que hay que hacer lo mismo pero con bind (no lo probé, sólo me parece lógico…), aunque yo reinicio la máquina para no complicarme. 😛

Esto es fácil de meter en un script, y espero que le sirva a alguien (me llevó un buen rato encontrarlo).

Saludos

Marcelo

[1] Por algún motivo la gente de Samsung sacó los drivers Linux de la página de la printer al momento de escribir esto (?). Ya les envié un mail al respecto, espero que contestesten y/o vuelvan a aparecer (habían sido actualizados hace un par de meses, no parecían estar sin mantener…). Si alguien los necesita, me escribe y los pongo en algún lugar accesible.
Actualización: Me contestaron enseguida, a las 3 horas de haberles escrito que no hay drivers Linux en su página. Según ellos, se disculpan y afirman que puede que el equipo de desarrollo esté actualizando los drivers en este mismo momento… hay que ver en unos días si aparecen.
[2] Acá hay una porción de la salida de un «lsusb -v» donde aparece uno de los 2 Root Hub USB 2.0 que tengo en mi equipo; ver que el archivo relacionado que aparece en el directorio /sys/bus/pci/drivers/ehci_hcd corresponde al descriptor «iSerial» del mismo:
[...]
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            9 Hub
  bDeviceSubClass         0 Unused
  bDeviceProtocol         0 Full speed (or root) hub
  bMaxPacketSize0        64
  idVendor           0x1d6b Linux Foundation
  idProduct          0x0002 2.0 root hub
  bcdDevice            2.06
  iManufacturer           3 Linux 2.6.31-20-generic ehci_hcd
  iProduct                2 EHCI Host Controller
  iSerial                 1 0000:00:1d.7
  bNumConfigurations      1
[...]
Categories: codear, linux, sysadmin, ubuntu-ar Tags:

Virtio – Paravirtualización de I/O

sábado, 27 de febrero de 2010 4 comentarios

Hace un rato que estoy leyendo sobre virtualización, pero no de CPU, sino de I/O (otro más acá)… muy interesante, me aclaró algunas dudas que tenía, dado que últimamente al configurar este tipo de software se me confundían las cosas 🙂

Resulta que a nivel de I/O tenemos algo parecido a la virtualización al nivel de CPU: emulación, paravirtualización y ejecución «directa», por llamarlo de alguna manera. Sugiero leer el artículo para más detalles, pero sólo quiero agregar que recién estamos en la etapa de paravirtualización, y que (en buena hora) Intel y AMD agregaron unidades IOMMU en sus últimos diseños para poder asignar dispositivos directamente a una (o más, según el caso) VM, evitando el Hypervisor y ahorrando ciclos de CPU. Pero esto parece estar verde aún.

Virtio vendría a ser como una serie de drivers de paravirtualización de I/O. Lo bueno es que no sabía que VirtualBox soportaba para las interfaces de red, algo que al parecer (y de esta manera) intenta ser un estándar  (net y block devices por ahora),  ya que tiene una API de comunicación Host <–> Guest abierta, independiente y en paralelo a la propuesta de KVM como hypervisor.

Luego de ver un poco todo esto, me puse  a configurarlo en una VM con WinXP, le instalé estos drivers y ya estoy usando menos CPU para la parte de red en mi guest 🙂

Acá se ve un poco la mejora a nivel de tráfico de red *real* que hay usando I/O paravirtualizado:

http://www.linux-kvm.org/page/Using_VirtIO_NIC

En fin, esperemos que todo esto mejore más aún. KVM ya soporta virtio para dispositivos de almacenamiento, además de los de red (linkeo la instalación de los drivers de Windows porque lógicamente Linux tiene estas baterías ya incluídas, je).

Saludos

Categories: codear, linux, sysadmin, ubuntu-ar Tags:

PostgreSQL 8.5 9.0 – Replicación mejorada

sábado, 6 de febrero de 2010 3 comentarios

Para los que no están enterados, Streaming Replication es la nueva gran característica de PostgreSQL 9.0 (ex-8.5), todavía en desarrollo. Estoy muy contento por la noticia, realmente era algo pendiente ver integrado algo de esto en PostgreSQL mismo (ya que hay productos y/o versiones modificadas para hacer esto, pero no es lo mismo que «el original», claro está 🙂 ) y lo hace cada vez más adecuado para evitar (o al menos dejar a uno la opción de) utilizar motores de bases de datos muy buenas pero caras y propietarias (Oracle) o lamentablemente en problemas políticos/de gestión (MySQL).

Básicamente SR permite que exista un proceso «sender»en el master que envíe a procesos «receiver» en el/los nodos secundarios porciones de WAL (Write-Ahead Log), es decir, de transacciones «comiteadas» recientemente. Antes (PostgreSQL 8.4 y anteriores) los WAL se podían archivar a otro nodo una vez se hayan completado 16 MB de transacciones (por defecto), con lo cual si se tenía una BD que «cambie poco», 16 MB podían representar un lapso de tiempo físico importante. A partir de ahora, el lapso de tiempo se reduce a unos pocos segundos de diferencia en el master y la/las réplicas (dependiendo el enlace, la carga del master, etc.), con lo cual es una mejora substancial en las capacidades y posibilidades de PostgreSQL.

Hay que resaltar que por ahora este proceso es asincrónico, y aunque hay usuarios que pueden necesitar replicación sincrónica, cada esquema tiene sus ventajas y desventajas, y sin lugar a dudas esta primera versión de momento atiende muchísimas necesidades.  Combinado con otra de las novedades de 9.0 que es la posibilidad de usar un nodo secundario (recibiendo WALs mediante SR o el método tradicional) como Sólo Lectura (característica llamada «Hot Standby«), 9.0 da un paso muy adelante con respecto a versiones anteriores. 🙂

Para más adelante (y planificado para hacerse, ojo) quedó la opción de Straming Replication sincrónico y obtener más y mejor info del proceso de replicación (lag, estadísticas, etc.). Otro punto flojo, que espero se resuelva mejor (o con un mecanismo estándar), es que uno tiene que scriptear a mano el Failover, es decir, el proceso de recuperación (heartbeat es una herramienta genérica para este tipo de cosas).

Dejo algunos links relacionados con más info y demostraciones:
http://www.depesz.com/index.php/2010/02/01/waiting-for-9-0-streaming-replication/
http://www.depesz.com/index.php/2010/01/08/waiting-for-8-5-hot-standby/

¡Saludos!
Marcelo

Categories: codear, linux, sysadmin, ubuntu-ar Tags: