Comic Book Reader

Projet C++ avec Qt

Bruno PETIT - Antonin RAFFIN

ENSTA ParisTech 2016

Plan

I. Cahier des charges

 

2. Architecture

 

3. Résultat

 

4. Annexe

Note: voir README.md/.pdf pour la compilation

Cahier des charges

Réaliser un lecteur permettant de prendre en charge les différents formats utilisés
pour les bandes dessinés

Intuitif

Interface agréable

Rapide

Orienté vers l'utilisateur:

Démarche (1)

1. ANalyse du problème

  • Définition des objectifs
  • Réflexion sur les points importants
  • Réflexion sur les différentes étapes pour avoir une structure évolutive

2. Choix de l'architecture

  • Combien de classes ? Quel héritage ?
  • Quelles fonctions doivent-être implémentées ?

Démarche (2)

3. Répartition des tâches

  • Travail en parallèle
  • Partie GUI quasi-indépendante de l'extraction

4. Choix des Technologies et conventions

  • Quel langage ? Quelle bibliothèque ?
  • Quel framework pour le GUI ?
  • Conventions de programmation ?
  • Versioning avec GIT

Démarche (3)

5. Réalisation

  • Tests unitaires
  • Création d'une première version stable

6. Améliorations

  • Ajout de fonctionnalités
  • Amélioration de l'interface et de la robustesse du système

Fonctionnalités

Archives Supportées

  • cbz (zip)
  • cbr (rar)
  • tar
  • gz

Formats Supportés

  • jpeg
  • png
  • gif
  • bmp
  • tiff

Fonctionnalités

Système

Utilisateur

  • Lazy loading (on n'extrait que ce dont on a besoin)
  • Robuste: supporte presque tous les types d'organisation et de nommage
  • N'extrait que les images de l'archive
  • Affichage multiple (une ou deux images)
  • Redimensionnement automatique avec filtre
  • Zoom et grab avec la souris
  • Réinitialisation du zoom (avec adaptation à la fenêtre)

Les différentes classes

Extraction

GUI

Note: Les différentes classes sont détaillées par la suite

  • Archive
  • Book
  • Async
  • MainWindow
  • ImageGraphicView

Book

Archive

MainWindow

Extraction

Gestion du livre

Affichage et interaction avec l'utilisateur

Async

Lazy Loading

Les différentes classes

Affichage de l'image

ImageGraphicView

Classe Archive

class Archive
{
private:
    std::string name;
    std::string currentEntryName;
    unsigned int nbEntries;
    unsigned int counter;
    void* currentArchive;
    void* currentEntry;
public:
    Archive(){}
    virtual ~Archive(){}
    virtual void open(){}
    virtual void close(){}
    virtual bool hasNext(){}
    virtual void next(){}
    virtual std::string getEntryName(){}
    virtual int getCurrentEntryNb(){}
    virtual int getNbOfEntries(){}
    virtual void writeTempEntry(std::string tempFolder){}
}

Classe abstraite pour représenter et extraire une archive

Classe Archive

Contient les informations essentielles:

  • Récupérer les différentes informations
  • Parcourir l'archive
  • Extraire une entité

Fonctions pour l'Extraction

  • Nom de l'archive
  • Nombre de pages
  • Informations sur l'entité en cours d'extraction

Classe Archive

Résultat: Une extraction facile

  archive = new LibArchive(archiveName); //Classe héritant de la classe Archive

  while (archive->hasNext())
  {
    archive->next();
    archive->writeTempEntry(tempFolder);//Extraction de l'entité courante
  }

  archive->close();

Exemple: extraire toute une archive

Archive

LibArchive

LibZippp

Chaque classe qui utilise une certaine bibliothèque pour extraire les archives hérite de la classe Archive

Bibliothèque:

Classe Book

class Book
{
public:
  Book(){}
  Book(std::string archiveName);
  Book(std::string archiveName, std::string tempFolderName);
  ~Book();
  void extractOneImage();
  void extractAll();
  void createImagesList();
  unsigned int getNbPages();
  int getCurrentPageNumber();
  QImage getCurrentImage();
  QImage getNextImage();
  void setPage(unsigned int pageNumber);
  bool hasPrev();
  bool hasNext();
  void prev();
  void next();

private:
  void init(std::string archiveName);
  void createTempFolder();
  std::string tempFolder;
  LibArchive* bookArchive;
  QStringList images;
  unsigned int currentPage;//Warning: page numbers go from 0 to nbPages-1
  unsigned int nbPages;
};

Classe pour représenter et manipuler un livre

Classe Book

Surcouche pour faire le lien entre l'extracteur (de type Archive) et l'interface graphique (MainWindow)

Permet de parcourir le dossier temporaire dans lequel ont été extraites les images

Book

Archive

MainWindow

Extraction

Gestion du livre

Affichage et interaction avec l'utilisateur

Classe ASYNC

class Async : public QObject
{
    Q_OBJECT

public:
    Async();
    Async(Book* comicBook);
    ~Async();
    void beginExtraction();
    void continueExtraction();
    void setCurrentBook(Book* comicBook);
    int getNbPagesLoaded();

signals:
    void imageReady(int pageNumber);

private:
  int nbPagesLoaded;// number of pages extracted
  int nbPages;// Total number of pages (of the book)
  int nextStop;// Used in the async extraction for stopping the loop
  int nbPagesToExtractBeforeDipslay;// Nb of pages to be load before showing
  Book* currentBook;// The current comic book we are extracting
};

Classe pour extraire l'archive de manière asynchrone

Classe Async

Se place entre la classe Book et l'interface graphique (MainWindow)

Book

Archive

MainWindow

Extraction

Gestion du livre

Affichage et interaction avec l'utilisateur

Lazy loading: extrait une image que lorsqu'elle doit être affichée

=> Le dossier temporaire a une taille minimale

Async

Permet un affichage rapide (émet un signal dès que les deux premières images sont prêtes)

Lazy Loading

Classe ImageGraphicView

class ImageGraphicView : public QGraphicsView
{
    Q_OBJECT
public:
  ImageGraphicView(QWidget * parent=0);
  ~ ImageGraphicView();
  void setImage(const QImage & image);

public slots:
  void fitImage();

protected:
  virtual void resizeEvent(QResizeEvent *event);
  virtual void wheelEvent(QWheelEvent *event);
  virtual void mousePressEvent(QMouseEvent *event);
  virtual void mouseReleaseEvent(QMouseEvent *event);
  void setZoomFactor(const double factor) { zoomFactor=factor; }
  void setZoomCtrlFactor(const double factor) {zoomCtrlFactor=factor; }
  double zoomFactor;
  double zoomCtrlFactor;

private:
    // Scene where the image is drawn
    QGraphicsScene* scene;
    // Pixmap item containing the image
    QGraphicsPixmapItem* pixmapItem;
    // Size of the current image
    QSize imageSize;
    // Current pixmap
    QPixmap currentPixmap;
};

Classe pour afficher et manipuler une image

Classe ImageGraphicView

Gère les différents événements:

MainWindow

Affichage et interaction avec l'utilisateur

ImageGraphicView

Affichage de l'image

  • Zoom (avec la souris)
  • Drag (avec la souris)
  • Redimensionnement de la fenêtre

S'occupe du bon affichage de l'image:

  • Ajustement de la taille de l'image aux dimensions de la fenêtre
  • Application d'un filtre pour atténuer les effets du redimensionnement

Classe MainWindow

Classe principale pour l'affichage et l'interaction avec l'utilisateur

Interaction

  • Création des menus
  • Création de la barre d'outil
  • Création des événements associés
  • Gestion des raccourcis clavier

Affichage

  • Nombre de pages et page courante
  • Gestion des différents modes de vue
  • Gestion de l'ouverture d'une archive

Résultat

Résultat

Ouvrir un fichier

Navigation

Mode d'affichage

(une ou deux pages)

Réinitialiser le zoom

Icônes => plus universel et intuitif

Crédits: flaticon.com

Un raccourci clavier est associé à chaque icône

Annexe

Les instructions pour la compilation et les informations sur le logiciel sont dans le README.md

Comic Book Reader

By Antonin Raffin

Comic Book Reader

  • 1,044