Archive

Archive for the ‘Uncategorized’ Category

Things change…

July 29th, 2010 No comments

Again ages since I last wrote on this blog. The reason I'm not writing anymore is on January 2010 I left for a sort of around the world trip.
I'm currently in Bolivia after having been in Brazil, Argentina and Chile.

I'll resume this site the day I'll stop somewhere and start experimenting with technology again, in the meanwhile, if you're interested in my travel stories you can found them at my travel blog

Marco

Categories: Uncategorized Tags:

PyQT playground: image gallery with zoom

January 28th, 2009 2 comments

In this article I'm going to create a small PyQT based application that displays images in a grid and that zoom the image hovered by the mouse.

This is how the final application looks like:

PyQT Image Gallery Screenshot

The first class we need is an ImageGallery, which is a mere QDialog using a QGridLayout.

class ImageGallery(QDialog):
 
    def __init__(self, parent=None):
        super(QDialog, self).__init__(parent)
        self.setWindowTitle("Image Gallery")
        self.setLayout(QGridLayout(self))
 
    def populate(self, pics, size, imagesPerRow=4,
                 flags=Qt.KeepAspectRatioByExpanding):
        row = col = 0
        for pic in pics:
            label = ImageLabel("")
            pixmap = QPixmap(pic)
            pixmap = pixmap.scaled(size, flags)
            label.setPixmap(pixmap)
            self.layout().addWidget(label, row, col)
            col +=1
            if col % imagesPerRow == 0:
                row += 1
                col = 0

The code is very simple, the class has only one public method, populate, which iterates over the images passed in the argument pics, create a QPixmap for each of them, and add them to the layout.

The interesting bit is the line where I create the label:

label = ImageLabel("")

This line creates a new instance of the ImageLabel, which is listed here below:

class ImageLabel(QLabel):
    """ This widget displays an ImagePopup when the mouse enters its region """
    def enterEvent(self, event):
        self.p = ImagePopup(self)
        self.p.show()
        event.accept()

The ImageLabel is a normal QLabel except that I redefined the enterEvent in order to show an ImagePopup when the mouse enters the label.

Finally, the ImagePopup class, responsible for the creation of the zoomed popup image.

class ImagePopup(QLabel):
    """
    The ImagePopup class is a QLabel that displays a popup, zoomed image
    on top of another label.
    """
    def __init__(self, parent):
        super(QLabel, self).__init__(parent)
 
        # set pixmap and size, which is the double of the original pixmap
        thumb = parent.pixmap()
        imageSize = thumb.size()
        imageSize.setWidth(imageSize.width()*2)
        imageSize.setHeight(imageSize.height()*2)
        self.setPixmap(thumb.scaled(imageSize,Qt.KeepAspectRatioByExpanding))
 
        # center the zoomed image on the thumb
        position = self.cursor().pos()
        position.setX(position.x() - thumb.size().width())
        position.setY(position.y() - thumb.size().height())
        self.move(position)
 
        # FramelessWindowHint may not work on some window managers on Linux
        # so I force also the flag X11BypassWindowManagerHint
        self.setWindowFlags(Qt.Popup | Qt.WindowStaysOnTopHint
                            | Qt.FramelessWindowHint
                            | Qt.X11BypassWindowManagerHint)
 
    def leaveEvent(self, event):
        """ When the mouse leave this widget, destroy it. """
        self.destroy()

That's it, it's very simple as you can see. You can download the python code or a zip file containing the code and the images.

Thanks for reading.

Categories: Uncategorized Tags:

Indenting XML documents with gEdit

December 6th, 2008 1 comment

gedit is a pretty cool text editor for the GNOME desktop environment.

The problem is that sometimes I found myself using it to edit XML documents but there is no way to pretty print them.

I found yesterday a quick solution to this problem thanks to the External Tools support in gedit and a small utility called xmlindent.

Once you have installed xmlindent click on Tools->External tools, and on the dialog enter the following informations:

External tools dialog

Of course you can customize the options as you wish, the displayed configuration just indents the whole document and replace the unindented one.

To use it just click External Tools -> xmlindent.

Categories: Uncategorized Tags:

Embedding Mplayer in a PyGTK application

February 16th, 2008 5 comments

Recently I wanted to extract the sound track from a MP4 file.
You actually need a single command-line to do that, either using Mplayer or GStreamer.
It's amazing what you can do with GStreamer pipelines, but unfortunately I ran into several problems trying to play H.264 video files with AAC audio (the files are produced by a Sanyo camera and make Totem crash after about few seconds...) so I gave up and I took a look at MPlayer. After all I really didn't need all the GStreamer functionalities.
A single line actually does the job:

mplayer -ao pcm:file=$OUTPUT_FILE $INPUT_FILE

Couldn't be easier.

Nevertheless, I wanted to command the extraction from a GUI as it makes it more user friendly for people that don't deal with shells everyday. Additionally, I didn't want the MPlayer window to popup, I actually wanted to embed Mplayer inside my application.

Again, it turns out that a single line does the job:

mplayer -ao pcm:file=$OUTPUT_FILE -wid $WINDOW_XID

The -wid option tells Mplayer to connect to the window represented by the ID $WINDOW_XID.
This ID is actually the identifier given by the X Server to the window.
We'll see later how to retrieve it.

With this setup, the video is shown in the application, the problem is that there is no indication about the progress. What I wanted was to periodically ask to MPlayer the status of the playback, and displaying it in a progress bar. Checking the MPlayer's man page I discovered that it can be controlled by putting it into a slave mode and by sending him the commands through a named pipe. Bingo !

To start the mplayer in slave mode, I modified the command line to look like this:

mplayer -ao pcm:file=$OUTPUT_FILE -wid $WINDOW_XID -slave -idle \n
-input file=$FIFO

where FIFO is the absolute path of the named pipe where the commands are sent
(for a complete list of commands, type mplayer -input cmdlist).

On the Python side, you have to embed the video in a GtkDrawingArea.
The documentation for this component just says:
The GtkDrawingArea widget is used for creating custom user interface elements.
It's essentially a blank widget; you can draw on widget->window

It is actually everything I need, as the only thing required to do is to get the X ID of the window and pass it to Mplayer. You do it like this:

xid = canvas.window.xid # where canvas is an instance of GtkDrawingArea

We have almost everything required to start Mplayer, the only missing thing is the FIFO.
In Python, you create a FIFO using

os.mkfifo("path_to_fifo")

The full code to start Mplayer in another process would then be:

command = "mplayer -ao pcm:file=%s -wid %i -slave -idle \n
-input file=%s" % (outputFile,xid,fifo)
command = command.split().append("input_video_file.mp4")
subprocess.Popen(command, stdout=logfile, stderr=logfile)

I added the input file after the call to split because if there are whitespaces in the filename or in a parent directory, then the filename would break down in multiple tokens with the call to split.

Now that MPlayer has started, we have to tell him what to do. To do that, we write to the pipe:

mplayerClient = open(FIFO,"w")
mplayerClient.write("play\n") # commands must ends with a newline

(Actually, I still haven't get MPlayer to not start automatically the playback, even if I'm using the -idle option. Please post a comment if you can shed a light on the subject...)

At this point the application is showing the video, but as we said before, we also want to update a progress bar to show the progress, and to do that we've to repeatedly ask the status to Mplayer.

The easiest way to do that, since I was using Gtk, is to use the gobject.timeout_add call, like this:

# call the myUpdateFunction each UPDATE_INTERVAL milliseconds
gobject.timeout_add(UPDATE_INTERVAL, myUpdateFunction)

and myUpdateFunction is defined as:

def myUpdateFunction():
    keepGoing = True
    mplayerClient.write("get_percent_pos\n")
    mplayerClient.flush() # really important, or commands won't be always sent !
    line = logfile.readline()
    if line and line.startswith("ANS_PERCENT_POSITION"):
    # +1 because progress starts from 0, it would end to 99 otherwise
        progress = int(line[line.index('=')+1:-1]) + 1
        progressBar.set_text("%s %%" % progress)
        progressBar.update(progress/100.0)
    else:
        keepGoing = False
 
return keepGoing

That's it, progressBar is a normal GtkProgressBar object and logfile is where I previously redirected Mplayer stdout and stderr.

The above code won't actually works out of the box as there are some corner cases you have to deal with, for example it can happen that the update function is called before MPlayer starts to play the video (which should actually happen with the -idle option, but I couldn't get it to work). In that case line would be an empty string and the playback will immediately stop as myUpdateFunction will return False.

You can find the complete but fairly hackish code here:
AudioExtractor.zip

AudioExtractor

The program also pops up a dialog asking you if you want to burn the file with Serpentine or save it to a different location. I can't guarantee it will work for you as I've been written it mostly as an educational tool.

Categories: Uncategorized Tags: