Neige !

Bon, après tous ces posts de geek, un peu de photo pour changer ! La semaine dernière, c’était le bordel monumental suite aux chutes de neige assez ouf qu’on a eu. Certain aiment, d’autres pas. Perso j’étais bien au chaud sous ma couette, mais je plein tous ceux qui ont galéré à rentrer chez eux. Toujours est-il que le lendemain a donné lieu à une super balade et quelques photos sympas.

Toute la galerie est visible ici : http://gallery.pcitron.fr/2010.12.10.Neige/ et ci-dessous quelques exemples :

Play an animated GIF with an IKImageView

Hi, this is a small note for people wondering (like I was, a few days ago) how the hell can I animate my GIFs in an IKImageView !? Well, unlike the NSImageView, where you only have to set a property to YES to animate you GIFs, with the IKImageView, it’s a bit more complicated. You have to subclass your IKImageView, and set an overlay layer on the image, setting it yourself. In my image viewer application, the name of my subclass of IKImageView is ImageView (original isn’t it ? :p) So here is the code of ImageView handling the animation of GIFs, with comments :

#import "ImageView.h"

@implementation ImageView

-(void)awakeFromNib
{
    // create an overlay for the image (which is used to play animated gifs)
    // EDIT: well, don't do that here, due to some initialization orders
    //       problem, it might gives an error and not create the overlay
    //       I leave that line here for the records ^^
    //[self setOverlay:[CALayer layer] forType:IKOverlayTypeImage];

    // NOTE: calling this before anything else seems to fix a lot of
    //       problems ... maybe it's initializing a few things internally
    //       on the first call ...
    [super setImageWithURL:nil];
}

-(BOOL)isGIF:(NSString *)path
{
    // checks if the path points to a GIF image
    NSString * pathExtension = [[path pathExtension] lowercaseString];
    return [pathExtension isEqualToString:@"gif"];
}

-(void)setImageWithURL:(NSURL *)url
{
    // EDIT: this is where we create the overlay now, but only if it doesn't
    //       already exists.
    // checks if a layer is already set
    if ([self overlayForType:IKOverlayTypeImage] == nil)
        [self setOverlay:[CALayer layer] forType:IKOverlayTypeImage];

    // remove the overlay animation
    [[self overlayForType:IKOverlayTypeImage] removeAllAnimations];

    // check if it's a gif
    if ([self isGIF:[url path]] == YES)
    {
        // loads the image
        NSImage * image = [[NSImage alloc] initWithContentsOfFile:[url path]];

        // get the image representations, and iterate through them
        NSArray * reps = [image representations];
        for (NSImageRep * rep in reps)
        {
            // find the bitmap representation
            if ([rep isKindOfClass:[NSBitmapImageRep class]] == YES)
            {
                // get the bitmap representation
                NSBitmapImageRep * bitmapRep = (NSBitmapImageRep *)rep;

                // get the number of frames. If it's 0, it's not an animated gif, do nothing
                int numFrame = [[bitmapRep valueForProperty:NSImageFrameCount] intValue];
                if (numFrame == 0)
                    break;

                // create a value array which will contains the frames of the animation
                NSMutableArray * values = [NSMutableArray array];

                // loop through the frames (animationDuration is the duration of the whole animation)
                float animationDuration = 0.0f;
                for (int i = 0; i < numFrame; ++i)
                {
                    // set the current frame
                    [bitmapRep setProperty:NSImageCurrentFrame withValue:[NSNumber numberWithInt:i]];

                    // this part is optional. For some reasons, the NSImage class often loads a GIF with
                    // frame times of 0, so the GIF plays extremely fast. So, we check the frame duration, and if it's
                    // less than a threshold value, we set it to a default value of 1/20 second.
                    if ([[bitmapRep valueForProperty:NSImageCurrentFrameDuration] floatValue] < 0.000001f)
                        [bitmapRep setProperty:NSImageCurrentFrameDuration withValue:[NSNumber numberWithFloat:1.0f / 20.0f]];

                    // add the CGImageRef to this frame to the value array
                    [values addObject:(id)[bitmapRep CGImage]];

                    // update the duration of the animation
                    animationDuration += [[bitmapRep valueForProperty:NSImageCurrentFrameDuration] floatValue];
                }

                // create and setup the animation (this is pretty straightforward)
                CAKeyframeAnimation * animation = [CAKeyframeAnimation animationWithKeyPath:@"contents"];
                [animation setValues:values];
                [animation setCalculationMode:@"discrete"];
                [animation setDuration:animationDuration];
                [animation setRepeatCount:HUGE_VAL];

                // add the animation to the layer
                [[self overlayForType:IKOverlayTypeImage] addAnimation:animation forKey:@"contents"];

                // stops at the first valid representation
                break;
            }
        }

        // release the image
        [image release];
    }

    // calls the super setImageWithURL method to handle standard images
    [super setImageWithURL:url];
}

@end

So, what I do here is that I create an overlay layer to display the image, and when I find an animated GIF, I load it using the NSImage class, and then I scan it to extract all the frames and setup the layer animation. So to display an animated GIF, you now only have to use the setImageWithURL method of your ImageView class. The advantage of using IKImageView over NSImageView, is that it can be resized while still playing your animation smoothly, and it benefit of all the features of the IKImageView class.

Image Viewer v0.3 pour Mac OS X

Edit: Petite mise à jour pour prévenir que l’image viewer a maintenant sa propre page : http://blog.pcitron.fr/tools/macosx-imageviewer/ On peut y trouver toutes les versions du viewer, et à partir de la 0.5, il y a le binaire de l’application : y’a plus qu’à dropper dans le répertoire Application et hop !

Enfin ! J’ai réussit à lire les GIF animés avec un IKImageView !! C’était le dernier point qui me restait à régler sur mon petit programme, et c’est maintenant chose faite. On a donc maintenant un petit soft permettant de visualiser à peu près tous les types d’image standard (GIF animés compris) de copier / couper / coller / supprimer des images. Quand j’aurais le temps, il faudra que je rajoute le drag & drop et la création de nouveau répertoire, et j’aurais un petit soft de visualisation avec le minimum syndical pour organiser ses galeries.

Comme d’hab’, le code source : ImageViewer.v0.3 (la partie permettant l’animation des GIF dans un IKImageView se trouve dans le fichier ImageView.m)

Image Viewer v0.2 pour Mac OS X

Edit: Petite mise à jour pour prévenir que l’image viewer a maintenant sa propre page : http://blog.pcitron.fr/tools/macosx-imageviewer/ On peut y trouver toutes les versions du viewer, et à partir de la 0.5, il y a le binaire de l’application : y’a plus qu’à dropper dans le répertoire Application et hop !

Bon, ce coup-ci en français, je sais pas ce qui m’a pris dans les posts précédent, trop de doc en anglais, du coup j’ai écris en anglais :p Donc je récapitule : J’ai commencé la programmation sous Mac, et après avoir suivit pas mal de tutos, j’ai décidé de faire un petit projet un peu plus complet pour me former. J’ai décidé de créer un petit logiciel de visualisation d’images. C’est graphique, joli, ça couvre pas mal de points de la programmation sous Mac, parfait !

Donc, là c’est la version 0.2, en gros la même que la précédente, mais avec quelques petites améliorations (niveau raccourcis clavier) et dans le fonctionnement du mode plein écran (quand on passait en plein écran, l’image de la preview était redimensionnée, ce qui fait qu’elle était toute crénelée. Il fallait avancer d’une image et revenir en arrière pour l’avoir en bonne qualité : c’est corrigé)

On a maintenant le nombre d’image d’un répertoire affiché en face de celui-ci. Lorsque l’on se déplace au clavier dans l’arborescence des répertoire, la flèche de droite sert normalement à développer l’arborescence, mais dans le cas où il n’y a pas de sous-répertoire, ça bascule maintenant vers la partie qui affiche les onglets des images, et ça sélectionne la première. Bon, je raconte un peu ma life, mais en gros, c’est rapide et pratique (à mon gout) pour se déplacer sur son disque dur et visualiser rapidement des images.

Comme d’habitude, les sources sont dispo ici : ImageViewer.v0.2 (mieux nettoyées et commentées par rapport à la précédente, mais toujours en anglais)

Et un screenshot :

Simple image viewer on Mac OS X

Edit: The image view now has a dedicated page, and also is available in binary format (you can just drop in your Application’s folder, no need to recompile ^^) The page is : http://blog.pcitron.fr/tools/macosx-imageviewer/

I’ve been learning Objective-C and Cocoa development since a few months now, and after I had followed a few tutorials, I decided to start a little image viewer project : it’s fun to do, and cover a lot of interesting areas of Cocoa programming.

Now I think I’ve reached the first usable version of the software, and I thought I might release it. It’s really really simple. It allows you to browse through your computer, the images contained in a browser are shown as thumbnails, and when clicking on them, you have a bigger preview. If you double click a thumbnail (or press Enter when one is selected) you enter a fullscreen mode. That’s all (the menu options are not implemented yet)

But the source code might interest a few beginners since it covers a few points I found hard to learn :

  • custom cells in the NSOutlineView (it allows to display the folder icons next to the name)
  • use of the user defaults to remember the size and position of the window between each run, and save other stuff
  • programmatically bind the background color of an IKImageBrowserView to the user defaults
  • how to use the fullscreen mode of an NSView

Bellow is a screenshot of the application, and here is the link to the XCode sources : ImageViewer v0.1

Binding the background color of an IKImageBrowserView

A little post-it, because I spent a lot of time figuring this out (I’m new to Cocoa, it doesn’t help :p) I have a preference panel, and I’m using the shared user defaults controller to store my application preferences. In this application, I have an IKImageView and an IKImageBrowserView (I’m trying to create a small image viewer application)

Via the interface builder tool, you can easily bind the background color of the IKImageView (it appears on the bindings tab) but for a reason, Apple decided that the background color of the IKImageBrowserView shouldn’t appear on this tab … I think it’s stupid but anyway. Here is the way to programmatically bind the background color of the IKImageBrowserView to a value stored in the user defaults :

// create the options : continuous update and keyed unarchive
// (the color must be archived and unarchived because it's an
// object and can't be store as an int or stuff like that)
NSMutableDictionary * options = [[NSMutableDictionary alloc] init];
[options setObject:[NSNumber numberWithBool:YES]
         forKey:NSContinuouslyUpdatesValueBindingOption];
[options setObject:NSKeyedUnarchiveFromDataTransformerName
         forKey:NSValueTransformerNameBindingOption];

// mImageBrowser is the IKImageBrowserView, and backgroundColor
// is the key used in the shared user defaults controller to store the color
[mImageBrowser bind:IKImageBrowserBackgroundColorKey
               toObject:[NSUserDefaultsController sharedUserDefaultsController]
               withKeyPath:@"values.backgroundColor"
               options:options];
[options release];

It’s quite simple, but it took some time for me to figure out how to retrieve the shared user defaults key and bind it to the background of my IKImageBrowserView

2 vidéos de Parkour !

Et ouais, passque c’est la fête ! Et passque j’aime bien le style (et surtout passque c’est une vidéo en 2 parties :p) Pas mal de free run, mais de beaux mouv’ de Parkour aussi :) En particulier le tic-tac / saut de bras sur la deuxième vidéo qui déchire bien :)

[youtube]http://www.youtube.com/watch?v=z8Xx-VvT8RE[/youtube]

[youtube]http://www.youtube.com/watch?v=oNN7jTZEqfQ[/youtube]

Way back …

Et ouais, liberté de mouvement, c’est beau, toussa toussa, mais faut aussi pouvoir revenir :D (c.f. la toute fin de la vidéo ci-dessous :p)

Ceci-dit, du grand Parkour cette petite vidéo, pi j’me fais pas trop de soucis pour Mister Phil ! Un peu courte, dommage, y’a un p’tit gout de r’viens-y mais bon …

[youtube]http://www.youtube.com/watch?v=voB6WiP83NU[/youtube]

Parkour, définition

Y’a quelques temps, je suis tombé sur cette vidéo, d’un marseillais avec qui j’ai eu l’honneur de m’entrainer un soir en gymnase (si j’avais su, je l’aurais pas lâché de la soirée pour apprendre !!) Bon, pas celui qui trace, mais celui qui filme j’imagine. Bref, en tout cas, une très belle définition en vidéo de ce qu’est le Parkour à mes yeux.

[youtube]http://www.youtube.com/watch?v=SMppD-bUNWo[/youtube]