10

HI All,

I am trying to zip up an Epub file i have made using c#

Things I have tried

  • Dot Net Zip http://dotnetzip.codeplex.com/
  • - DotNetZip works but epubcheck fails the resulting file (**see edit below)
  • ZipStorer zipstorer.codeplex.com
  • - creates an epub file that passes validation but the file won't open in Adobe Digital Editions
  • 7 zip
  • - I have not tried this using c# but when i zip the file using there interface it tells me that the mimetype file name has a length of 9 and it should be 8

In all cases the mimetype file is the first file added to the archive and is not compressed

The Epub validator that I'am using is epubcheck http://code.google.com/p/epubcheck/

if anyone has succesfully zipped an epub file with one of these libraries please let me know how or if anyone has zipped an epub file successfully with any other open source zipping api that would also work.


EDIT

DotNetZip works, see accepted answer below.

3 Answers3

13

If you need to control the order of the entries in the ZIP file, you can use DotNetZip and the ZipOutputStream.

You said you tried DotNetZip and it (the epub validator) gave you an error complaining about the mime type thing. This is probably because you used the ZipFile type within DotNetZip. If you use ZipOutputStream, you can control the ordering of the zip entries, which is apparently important for epub (I don't know the format, just surmising).


EDIT

I just checked, and the epub page on Wikipedia describes how you need to format the .epub file. It says that the mimetype file must contain specific text, must be uncompressed and unencrypted, and must appear as the first file in the ZIP archive.

Using ZipOutputStream, you would do this by setting CompressionLevel = None on that particular ZipEntry - that value is not the default.

Here's some sample code:

private void Zipup()
{
    string _outputFileName = "Fargle.epub";
    using (FileStream fs = File.Open(_outputFileName, FileMode.Create, FileAccess.ReadWrite ))
    {
        using (var output= new ZipOutputStream(fs))
        {
            var e = output.PutNextEntry("mimetype");
            e.CompressionLevel = CompressionLevel.None;

            byte[] buffer= System.Text.Encoding.ASCII.GetBytes("application/epub+zip");
            output.Write(buffer,0,buffer.Length);

            output.PutNextEntry("META-INF/container.xml");
            WriteExistingFile(output, "META-INF/container.xml");
            output.PutNextEntry("OPS/");  // another directory
            output.PutNextEntry("OPS/whatever.xhtml");
            WriteExistingFile(output, "OPS/whatever.xhtml");
            // ...
        }
    }
}

private void WriteExistingFile(Stream output, string filename)
{
    using (FileStream fs = File.Open(fileName, FileMode.Read))
    {
        int n = -1;
        byte[] buffer = new byte[2048];
        while ((n = fs.Read(buffer,0,buffer.Length)) > 0)
        {
            output.Write(buffer,0,n);
        }
    }
}

See the documentation for ZipOutputStream here.

Cheeso
  • 180,104
  • 92
  • 446
  • 681
  • thank you so much for your quick well explained response just 2 quick things i had to change: output.PutNextEntry("META-INF/"); is not needed and just makes an empty META-INF file in the zip folder, and down in the WriteExistingFile I changed _outputFileName to filename just figured it may help anyone else looking at your answer thanks again – claybo.the.invincible May 05 '11 at 15:06
  • Hey claybo, thanks. I modified the sample code to fix those two things. I wasn't sure about the need for OPS/ (content directory) and META-INF/ (directory for meta content) within the epub file. – Cheeso May 05 '11 at 18:07
7

Why not make life easier?

private void IonicZip()
{
    string sourcePath = "C:\\pulications\\";
    string fileName = "filename.epub";

    // Creating ZIP file and writing mimetype
    using (ZipOutputStream zs = new ZipOutputStream(sourcePath + fileName))
    {
        var o = zs.PutNextEntry("mimetype");
        o.CompressionLevel = CompressionLevel.None;

        byte[] mimetype = System.Text.Encoding.ASCII.GetBytes("application/epub+zip");
        zs.Write(mimetype, 0, mimetype.Length);
    }

    // Adding META-INF and OEPBS folders including files     
    using (ZipFile zip = new ZipFile(sourcePath + fileName))
    {
        zip.AddDirectory(sourcePath  + "META-INF", "META-INF");
        zip.AddDirectory(sourcePath  + "OEBPS", "OEBPS");
        zip.Save();
    }
}
Dominic
  • 71
  • 1
  • 1
  • Thanks. This helped me write an ePub builder as 7zip was failing me. 7zip didn't seem to be able to work the mimetype right. I also have it doing multiple builds (B&N, Kindle, iBooks, Short Sample) by passing in a list of the files to compress for each eBook type. – Rhyous Feb 18 '14 at 09:05
1

For anyone like me who's searching for other ways to do this, I would like to add that the ZipStorer class from Jaime Olivares is a great alternative. You can copy the code right into your project, and it's very easy to choose between 'deflate' and 'store'.

https://github.com/jaime-olivares/zipstorer

Here's my code for creating an EPUB:

Dictionary<string, string> FilesToZip = new Dictionary<string, string>()
{
    { ConfigPath + @"mimetype",                 @"mimetype"},
    { ConfigPath + @"container.xml",            @"META-INF/container.xml" },
    { OutputFolder + Name.Output_OPF_Name,      @"OEBPS/" + Name.Output_OPF_Name},
    { OutputFolder + Name.Output_XHTML_Name,    @"OEBPS/" + Name.Output_XHTML_Name},
    { ConfigPath + @"style.css",                @"OEBPS/style.css"},
    { OutputFolder + Name.Output_NCX_Name,      @"OEBPS/" + Name.Output_NCX_Name}
};

using (ZipStorer EPUB = ZipStorer.Create(OutputFolder + "book.epub", ""))
{
    bool First = true;
    foreach (KeyValuePair<string, string> File in FilesToZip)
    {
        if (First) { EPUB.AddFile(ZipStorer.Compression.Store, File.Key, File.Value, ""); First = false; }
        else EPUB.AddFile(ZipStorer.Compression.Deflate, File.Key, File.Value, "");
    }
}

This code creates a perfectly valid EPUB file. However, if you don't need to worry about validation, it seems most eReaders will accept an EPUB with a 'deflate' mimetype. So my previous code using .NET's ZipArchive produced EPUBs that worked in Adobe Digital Editions and a PocketBook.

Xero
  • 41
  • 2