Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / Win32

CBR/CBZ Comics in C#

4.56/5 (13 votes)
31 Jul 2008CPOL7 min read 1   1.7K  
Interaction with CBZ/CBR comic books in C#.

CBR-Index

Introduction

While comic books can be easily dismissed by some as a juvenile distraction, I see them as I did when I was a child. To me, these are tales of excitement, morality, and adolescent empowerment that can insight interest in art, narrative, and human nature. Most of the 20th century comic books were represented in physical (book) format, and part of the enjoyment derived from the book was from the physical entity itself. However, as technology advances, all forms of media are re-inventing themselves in digital format.

The comic book medium is no different in its shift towards digital creation and distribution. As with any exciting new digital medium, programmers seek to interact, manipulate, and automate the standards that define the medium. While no authoritative consortium has emerged to define regulations and protocols, several products are available (for free) in the comics space by way of sequential image viewers.

This article will demonstrate simple methods one can use to interact with today's comics applications, and more importantly, to transform your printed comic books into a digital library that can be stored on Compact Discs (CD) or Digital Versatile Discs (DVD) in an orderly manner. Additionally, I'll explain how to augment my rudimentary demonstration application to add the features important to you.

Background

Almost two years ago, while I was moving into my new house, I had the (dis)pleasure of going through childhood artifacts and unused possessions in order to identify what to throw away and what to keep. During this endeavor, I stumbled on my childhood comic book collection. Rummaging through the boxes of Spiderman, X-Men, The Maxx, Spawn, etc., I began to remember the impact these stories had on my life when I was a child. There was just no way I could justify throwing these books in the garbage. However, if I left them to rot in boxes in the garage, they would certainly get destroyed but the humidity and varying degrees of heat and cold.

At this time, I decided to make it a priority to digitize and organize these precious pieces of American literature.

Scanning your Books

The bulk of this effort comes in the scanning of the books. I think Marvel, DC, and others offer their books in some kind of digital format already, but I wasn't concerned with new comics. My priority was to preserve the books I already own, and I was not willing to re-purchase anything.

Tediously, one by one, I scanned each book in my Hewlett Packard OfficeJet L7650 at 300 DPI. As each page finished, I cropped the pages appropriately to ensure the page was as clean as possible. After each scan, I loaded the image into Adobe Photoshop CS3, and added overlay if the page was too light to brighten the image, and then shrunk it down to between 100-200 DPI, which resulted in a brilliant image.

I created a separate folder for each comic I was going to scan, and I named each scanned image in a sequential manner. The cover would have a file name that was sure to always be at the beginning, such as 01a.jpg, and the next page would be 01.jpg, 02.jpg, 03.jpg, etc. This is very important so the software demonstrated later works correctly. After each comic book was completed, I used WinZip to zip all the files into an archive. The final step was to create an NFO file and rename the archive to *.cbz.

The CBZ and CBR Formats

When I began this project long ago, I assumed that writing the software would be the easy part. I was certain that the industry had a standard that I could reference in IEEE documentation and an API. Unfortunately, that turned out to not be the case at all. From what I can gather, there are two competing formats, and neither of those are specific to comics at all!

The two standard formats at this time are Zip Archived Comic Book (CBZ) and Comic Book Reader (CBR). So far as I can tell, no specific format provides more benefit than the other, and only serves to confuse consumers. The CBZ format is just a renamed ZIP archive, and the CBR format is a renamed RAR archive. Personally, I prefer CBZ since everyone has a zip archiver they can use to deflate the archive, whereas some individuals may not have a RAR application like WinRaR, but this is a matter of preference.

When creating CBZ/CBR archives, it's critical that all the files contained within are named sequentially, with the cover being the first file in the archive. Most archivers also include an NFO file, which is a plain text file with details regarding the book. Typically, all the data shown in the front cover such as penciler, inker, writer, editor, etc., is included in the NFO. Your comic book reader application will display this NFO each time a book is opened.

Image 2

Comic Reader Applications

The goal of this project is not to replace the existing comic book readers (though you could easily do so if inclined) but rather to provide a cleaner UI for launching them or interacting with them. There are a lot of sequential image viewers out there, but my personal favorites for windows are CDisplay, ComicRack, and ComicReader X. For the Unix/Linux Operating System there's Comix which is a fantastic GTK comic reader.

All of these readers are full featured, though readers such as ComicRack are packed with extras like sorting and grouping books and genres. Any of the readers mentioned will suit our needs for this project. Be sure that you have the CBR and CBZ extensions registered to one of these readers prior to playing with the demo application, as we'll be launching the comic files from within our application.

The Goal of our Project

My ultimate goal for the project is quite simple, I want a way to archive my comic books on CD or DVD, and I want a simple way of looking into each comic and seeing the rudimentary details like the cover, the size of the book, and the amount of pages within. Without an interface of some kind, you must open each comic one by one to find the one you want to look at.

This launcher application needs to run easily from the autorun.inf settings in a CD/DVD.

The Code

To do what we need, we basically only need a way to extract RAR and ZIP files. The ZIP part is simple using SharpLibZip, but the RAR portion is more challenging. I tried various methods here such as UnRaRDLL and unrar.exe, but the libraries and utilities I tried just didn't work out for me in the way I wanted, so I went with ChilkatDotNet2.dll (these RAR utilities are freeware).

Once the libraries had been worked out, I put together a very simple object model for this little utility.

Image 3

The form being used for this doesn't do much beyond fetching the files that match the CBR/CBZ file mask and constructing the backend entities based on that.

C#
private string GetZeroImageFromArchive()
{
    string selected = lbFiles.SelectedItem.ToString().ToLower();
    if (selected.IndexOf(".cbr") > -1)
    {
        myComic = new CbrComic(string.Format("{0}\\{1}",
        scanPath, lbFiles.SelectedItem.ToString()));
    }

    if (selected.IndexOf(".cbz") > -1)
    {
        myComic = new CbzComic(string.Format("{0}\\{1}",
        scanPath, lbFiles.SelectedItem.ToString()));
    }
    
    textBox1.Text = string.Format("{0}\r\nSize: {1}MB\r\nPages: {2}", 
        myComic.FileName, myComic.FileSize, myComic.PageCount);

    if (myComic.ErrorMessage != string.Empty)
    {
        MessageBox.Show(myComic.ErrorMessage);
    }
     
    return myComic.CoverPath;
}

Getting the Cover for the CBZ Files

C#
private void GenerateCover()
{
    this.ErrorMessage = string.Empty;
    
    using (ZipFile zFile = new ZipFile(File.OpenRead(FilePath)))
    {
        PageCount = (int)zFile.Count;
    }

    using (ZipInputStream s = new ZipInputStream(File.OpenRead(FilePath)))
    {
        ZipEntry theEntry;
        while ((theEntry = s.GetNextEntry()) != null)
        {
            
            string directoryName = Path.GetDirectoryName(theEntry.Name);
            string fileName = Path.GetFileName(theEntry.Name);

            // create directory if the archive has a folder at root
            if (directoryName.Length > 0)
            {
                string fDirectory = Path.GetTempPath() + directoryName;
                
                //We need to delete the directory is it's already 
                //there so we get the first entry
                if (Directory.Exists(fDirectory))
                {
                    Directory.Delete(fDirectory, true);
                }
                Directory.CreateDirectory(fDirectory);
            }

            string fullPath = Path.GetTempPath() + theEntry.Name;

            if (fileName != String.Empty && !File.Exists(fullPath))
            {
                using (FileStream streamWriter = File.Create(fullPath))
                {
                    int size = 2048;
                    byte[] data = new byte[2048];
                    while (true)
                    {
                        size = s.Read(data, 0, data.Length);
                        if (size > 0)
                        {
                            streamWriter.Write(data, 0, size);
                        }
                        else
                        {
                            break;
                        }
                    }
                    CoverPath = fullPath;
                    return; //Just return the 1st entry in the archive
                }
            }
        }
    }
}

Getting the Cover for the CBR Files

C#
private void GenerateCover()
{
    this.ErrorMessage = string.Empty;
    string path = string.Empty;
    Chilkat.Rar rar = new Chilkat.Rar();
    bool success = rar.Open(FilePath);
    PageCount = (int)rar.NumEntries;

    path = Path.GetTempPath();

    if (success)
    {
        Chilkat.RarEntry entry = rar.GetEntryByIndex(0);
        if (entry.IsDirectory)
        {
            entry = rar.GetEntryByIndex(1);
            entry.Unrar(path);
        }
        else
        {
            entry.Unrar(path);
        }

        FileInfo FI = new FileInfo(string.Format("{0}\\{1}", 
                          path, entry.Filename));
        CoverPath = FI.FullName;
    }
    else
    {
        this.ErrorMessage = "There was an Error: " + rar.LastErrorText;
    }
}

Running the Demo

In order to run the demo, you need to set some variables in the CBR-Index.exe.config file.

  • banner - The title text.
  • scan - The path with the CBR/CBZ files. Empty string notates the working directory.

You can see in the screen capture at the top of the article that I have set the banner value to the McFarlane Spiderman Series Complete, and the scan directory is empty as this application is running from a CDROM.

Compiling Collections on the Disc Media

To get the most benefit from the utility, I recommend creating CDs or DVDs where the root of the disc is filled with specific runs such as Ghost Rider, Silver Surfer, or whatever, and the application is set to auto-run. This way, whenever you put a comic CD into the tray, the application will load, and you will have a clean interface for navigating the contents of the disc.

I'm terribly pressed for time, so I haven't worked out a system for managing entire collections of discs, but I plan to do so at my earliest convenience. I also plan on adding a tab in the application where there will be a listview which displays all the covers in the scanned directory so you don't have to select individual files to see the covers.

History

  • 07- 28- 08 - Submitted article.
  • 07- 30- 08 - Added mentions for ComicReader X & ComicRack

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)