ia: Benvenite! In mi blog io scribe in interlingua, italiano e anglese.

it: Benvenuti! Nel mio blog scrivo in interlingua, italiano e inglese.

en: Welcome! In my blog I write in Interlingua, Italian and English.

Need a fast way to tag faces in many images? Try Imaginario!

Today I've released Imaginario 0.9. The big feature coming with this new release is a face tagging flow which I believe will be the fastest and simplest you've ever used, despite it being all manual. I even sat down and spent some quality time with Blender to prepare a video to show it off:

While some people might actually think that I spent more time for making the video than for implementing the face tagging feature itself, this couldn't be farther from the truth: the face tagging branch has been being worked on for at least three months (of course, that's my spare time — so it's actually less than one hour per day) and consisted of more than 40 commits (after squashing all the fixups), whereas for the video I spent no more than a couple of hours.

I would appreciate if the curious could go and try it out, and let me know about any issues you should find: there are built packages for Linux (AppImage), macOS and Windows. I do also have an Ubuntu PPA where nightly images are built, but I'm not sure if I can recommend that one, since I've not been using it myself and have no idea whether those packages actually even start. But you are welcome to try :-)

Your feedback will help me do better, so please don't be shy!

A simple cross-compiler for the Raspberry Pi

I've recently found some use for a first-generation Raspberry Pi (Pi 1 model B) which had been lying in a drawer since many years. A few days ago I've installed the Raspbian distribution in it, and was about to install motion on it, but I stopped as soon as I noticed that apt was suggesting to bring in 1 GB worth of dependencies. Adding --no-install-recommends reduced the proposal a bit, but it was still around 700 MB -- a bit too much for my taste. I figured out that the motion package for Debian (and Raspbian) depends on MySQL, PostgreSQL, FFmpeg and what not; so, I decided that I could probably just recompile it and disable all the stuff I didn't need at configure time.

But I didn't want to install all the build dependencies and the cross-compiler in my machine; containers exist for a reason, after all. So I had a look at the crossbuilder tool that we use in UBports: this is a nice little shell program that uses an Ubuntu-based LXD image to cross-compile a package after automatically fetching all its dependencies, and installs it into an UBports device. It does some magic with adb and stuff, but I thought that the basic functionality should work with minor modifications on any Debian-based distribution.

And indeed, some hours later, I got a branch where I can use crossbuilder to build packages for the Raspberry Pi. Assuming that you have LXD properly setup, the command

crossbuilder --raspbian source motion

will cause crossbuilder to create a container and download the Debian source package for motion; at this point you can modify the source code as you see fit, and rebuild it. I only changed the debian/rules file to add a few flags such as --without-mysql, --without-ffmpeg, etc. And

crossbuilder --raspbian

is the command to run in order to perform the build. This will first download all the dependencies (according to the debian/control file), build the package, and create a tar archive containing all the generated .deb files. This archive can then be copied into the target device and unpacked there.

Now, there's a small problem in that Raspbian claims to be armhf, while in fact its floating-point processor is somehow not compliant with the armhf architecture. So, you generally cannot use an armhf package from Debian or Ubuntu on the Raspberry Pi. Given that I didn't have the time to prepare a proper Raspbian image for LXD, I used the Debian distribution as a base instead, and I chose to target the armel architecture: this might impose some penalties on the performance (at least for floating-point code), but it seems to work fine on the Raspberry Pi. Unfortunately, this means that you cannot just install the generated packages o the Pi, as dpkg will complain about the architecture mismatch (your package is armel, while the distro claims to be armhf). But unpacking the debian package with

dpkg -x motion_<...>.deb tmp

will indeed give you package that you can use.

I will eventually get back to this and make the script work better with Raspbian, but this is a quick start.

Using the latest QBS on older distributions

A short announcement, probably meaningless to most people, but who knows: I've created an Ubuntu PPA with the latest QBS. The reason why this might make some sense is that this PPA targets the older Ubuntu distributions. It's currently built for 14.04 (Trusty, which is no longer supported by Canonical), and I'll eventually upload the QBS package for 16.04, too.

This package can be useful to people distributing applications in the AppImage format, where one usually builds the application in one older distribution in order to increase the chances of it being runnable in as many Linux distributions as possible. A simpler way to obtain QBS on Trusty is to install QtCreator, but that's not trivial to install in an automated way and might not come with the latest QBS. Especially when building on Ubuntu, a package from a PPA is much easier to install.

This QBS is built statically, and won't install any Qt libraries on your system; this is good, because it allows you to use whatever Qt version you like without any risk of conflicts.

Implementing "Open with…" on MacOS with Qt

I just released PhotoTeleport 0.12, which includes the feature mentioned in the title of this blog post. Given that it took me some time to understand how this could work with Qt, I think it might be worth spending a couple of lines about how to implement it.

In the target application

The first step (and the easiest one) is about adding the proper information to your .plist file: this is needed to tell MacOS what file types are supported by your application. The official documentation is here, but given that an example is better than a thousand words, here's what I had to add to PhotoTeleport.plist in order to have it registered as a handler for TIFF files:

  <key>CFBundleDocumentTypes</key>
  <array>
    <dict>
      <key>CFBundleTypeExtensions</key>
      <array>
        <string>tiff</string>
        <string>TIFF</string>
        <string>tif</string>
        <string>TIF</string>
      </array>
      <key>CFBundleTypeMIMETypes</key>
      <array>
        <string>image/tiff</string>
      </array>
      <key>CFBundleTypeName</key>
      <string>NSTIFFPboardType</string>
      <key>CFBundleTypeOSTypes</key>
      <array>
        <string>TIFF</string>
        <string>****</string>
      </array>
      <key>CFBundleTypeRole</key>
      <string>Viewer</string>
      <key>LSHandlerRank</key>
      <string>Default</string>
      <key>LSItemContentTypes</key>
      <array>
        <string>public.tiff</string>
      </array>
      <key>NSDocumentClass</key>
      <string>PVDocument</string>
    </dict>
    …more dict entries for other supported file formats…
  </array>

This is enough to have your application appear in Finder's "Open with…" menu and be started when the user selects it from the context menu, but it's only half of the story: to my big surprise, the selected files are not passed to your application as command line parameters, but via some MacOS-specific event which needs to be handled.

By grepping into the Qt source code, I've found out that Qt already handles the event, which is then transformed into a QFileOpenEvent. The documentation here is quite helpful, so I won't waste your time to repeat it here; what has hard for me was to actually find that this functionality exists and is supported by Qt.

In the source application

The above is only half of the story: what if you are writing an application which wants to send some files to some other application? Because of the sandboxing, you cannot just start the desired application in a QProcess and pass the files as parameters: again, we need to use the Apple Launch Services so that the target application would receive the files through the mechanism described above.

Unfortunately, as far as I could find this is not something that Qt supports; sure, with QDesktopServices::openUrlExternally() you can start the default handler for the given url, but what if you need to open more than one file at once? And what if you want to open the files in a specific application, and not just in the default one? Well, you need to get your hands dirty and use some MacOS APIs:

#import <CoreFoundation/CoreFoundation.h>
#import <ApplicationServices/ApplicationServices.h>

void MacOS::runApp(const QString &app, const QList<QUrl> &files)
{
    CFURLRef appUrl = QUrl::fromLocalFile(app).toCFURL();

    CFMutableArrayRef cfaFiles =
        CFArrayCreateMutable(kCFAllocatorDefault,
                             files.count(),
                             &kCFTypeArrayCallBacks);
    for (const QUrl &url: files) {
        CFURLRef u = url.toCFURL();
        CFArrayAppendValue(cfaFiles, u);
        CFRelease(u);
    }

    LSLaunchURLSpec inspec;
    inspec.appURL = appUrl;
    inspec.itemURLs = cfaFiles;
    inspec.asyncRefCon = NULL;
    inspec.launchFlags = kLSLaunchDefaults + kLSLaunchAndDisplayErrors;
    inspec.passThruParams = NULL;

    OSStatus ret;
    ret = LSOpenFromURLSpec(&inspec, NULL);
    CFRelease(appUrl);
}

In Imaginario I've saved this into a macos.mm file, added it to the source files, and also added the native MacOS libraries to the build (qmake):

LIBS += -framework CoreServices

You can see the commit implementing all this, it really doesn't get more complex than this. The first parameter to the MacOS::runApp() function is the name of the application; I've verified that the form /Applications/YourAppName.app works, but it may be that more human-friendly variants work as well.

Bussator: implementing webmentions as comments

Recently I've grown an interest to the indieweb: as big corporations are trying to dictate the way we live our digital life, I'm feeling the need to take a break from at least some of them and getting somehow more control over the technologies I use.

Some projects have been born which are very helpful with that (one above all: NextCloud), but there are also many older technologies which enable us to live the internet as a free distributed network with no owners: I'm referring here to protocols such as HTTP, IMAP, RSS, which I perceive to be under threat of being pushed aside in favor of newer, more convenient, but also more oppressive solutions.

Anyway. The indieweb community is promoting the empowerment of users, by teaching them how to regain control of their online presence: this pivots arund having one's own domain and use self-hosted or federated solutions as much as possible.

One of the lesser known technologies (yet widely used in the indieweb community) is webmentions: in simple terms, it's a way to reply to other people's blog posts by writing a reply in your own blog, and have it shown also on the original article you are replying to. The protocol behind this feature is an recommendation approved by the W3C, and it's actually one of the simplest protocol to implement. So, why not give it a try?

I already added support for comments in my blog (statically generated with Nikola) by deploying Isso, a self-hosted commenting system which can even run as a FastCGI application (hence, it can be deployed in a shared hosting with no support for long-running processes) — so I was looking for a solution to somehow convert webmentions into comments, in order hot to have to deal with two different commenting systems.

As expected, there was no ready solution for this; so I sat down and hacked up Bussator, a WSGI application which implements a webmention receiver and publishes the reply posts as Isso comments. The project is extensible, and Isso is only one of the possible commenting systems; sure, at the moment it's indeed the only one available, but there's no reason why a plugin for Static Man, Commento, Remark or others couldn't be written. I'll happily accept merge requests, don't be shy — or I can write it myself, if you convince me to (a nice Lego box would make me do anything 😉).

The first user of Bussator is this blog, and while the project code is well covered by unit tests, we all know that real life is all another matter; so please bear with me, if not everything works as it should. And that's why I'll be thrilled to see your webmentions replies here.

Ah, and webmentions will allow me to get your Twitter likes and replies published as comments, too — this thanks to Brid.gy!