Blame tools/djvuextract.cpp

Packit df99a1
//C-  -*- C++ -*-
Packit df99a1
//C- -------------------------------------------------------------------
Packit df99a1
//C- DjVuLibre-3.5
Packit df99a1
//C- Copyright (c) 2002  Leon Bottou and Yann Le Cun.
Packit df99a1
//C- Copyright (c) 2001  AT&T
Packit df99a1
//C-
Packit df99a1
//C- This software is subject to, and may be distributed under, the
Packit df99a1
//C- GNU General Public License, either Version 2 of the license,
Packit df99a1
//C- or (at your option) any later version. The license should have
Packit df99a1
//C- accompanied the software or you may obtain a copy of the license
Packit df99a1
//C- from the Free Software Foundation at http://www.fsf.org .
Packit df99a1
//C-
Packit df99a1
//C- This program is distributed in the hope that it will be useful,
Packit df99a1
//C- but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit df99a1
//C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit df99a1
//C- GNU General Public License for more details.
Packit df99a1
//C- 
Packit df99a1
//C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library from
Packit df99a1
//C- Lizardtech Software.  Lizardtech Software has authorized us to
Packit df99a1
//C- replace the original DjVu(r) Reference Library notice by the following
Packit df99a1
//C- text (see doc/lizard2002.djvu and doc/lizardtech2007.djvu):
Packit df99a1
//C-
Packit df99a1
//C-  ------------------------------------------------------------------
Packit df99a1
//C- | DjVu (r) Reference Library (v. 3.5)
Packit df99a1
//C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved.
Packit df99a1
//C- | The DjVu Reference Library is protected by U.S. Pat. No.
Packit df99a1
//C- | 6,058,214 and patents pending.
Packit df99a1
//C- |
Packit df99a1
//C- | This software is subject to, and may be distributed under, the
Packit df99a1
//C- | GNU General Public License, either Version 2 of the license,
Packit df99a1
//C- | or (at your option) any later version. The license should have
Packit df99a1
//C- | accompanied the software or you may obtain a copy of the license
Packit df99a1
//C- | from the Free Software Foundation at http://www.fsf.org .
Packit df99a1
//C- |
Packit df99a1
//C- | The computer code originally released by LizardTech under this
Packit df99a1
//C- | license and unmodified by other parties is deemed "the LIZARDTECH
Packit df99a1
//C- | ORIGINAL CODE."  Subject to any third party intellectual property
Packit df99a1
//C- | claims, LizardTech grants recipient a worldwide, royalty-free, 
Packit df99a1
//C- | non-exclusive license to make, use, sell, or otherwise dispose of 
Packit df99a1
//C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the 
Packit df99a1
//C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU 
Packit df99a1
//C- | General Public License.   This grant only confers the right to 
Packit df99a1
//C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to 
Packit df99a1
//C- | the extent such infringement is reasonably necessary to enable 
Packit df99a1
//C- | recipient to make, have made, practice, sell, or otherwise dispose 
Packit df99a1
//C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to 
Packit df99a1
//C- | any greater extent that may be necessary to utilize further 
Packit df99a1
//C- | modifications or combinations.
Packit df99a1
//C- |
Packit df99a1
//C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY
Packit df99a1
//C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
Packit df99a1
//C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF
Packit df99a1
//C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
Packit df99a1
//C- +------------------------------------------------------------------
Packit df99a1
Packit df99a1
#ifdef HAVE_CONFIG_H
Packit df99a1
# include "config.h"
Packit df99a1
#endif
Packit df99a1
#if NEED_GNUG_PRAGMAS
Packit df99a1
# pragma implementation
Packit df99a1
#endif
Packit df99a1
Packit df99a1
/** @name djvuextract
Packit df99a1
Packit df99a1
    {\bf Synopsis}
Packit df99a1
    \begin{verbatim}
Packit df99a1
    djvuextract <djvufile> [-page=<page>] [Sjbz=<maskout>] [FG44=<fgout>] [BG44=<bgout>]
Packit df99a1
    \end{verbatim}
Packit df99a1
    
Packit df99a1
    {\bf Description}\\
Packit df99a1
    Program #djvuextract# analyzes the DjVu file
Packit df99a1
    #<djvufile># and saves the various layers into the specified files.
Packit df99a1
    The reverse operation can be achieved using program \Ref{djvumake}.
Packit df99a1
    \begin{itemize}
Packit df99a1
    \item When option #Sjbz=<maskout># is specified, the foreground mask is
Packit df99a1
      saved into file #<maskout># as JB2 data. This data file can be read
Packit df99a1
      using function \Ref{JB2Image::decode} in class \Ref{JB2Image}.
Packit df99a1
    \item When option #FG44=<fgout># is specified, the foreground color image
Packit df99a1
      is saved into file #<fgout># as IW44 data.  This data file can be processed
Packit df99a1
      using programs \Ref{d44}.
Packit df99a1
    \item When option #BG44=<bgout># is specified, the background color image
Packit df99a1
      is saved into file #<bgout># as IW44 data.  This data file can be processed
Packit df99a1
      using programs \Ref{d44}.
Packit df99a1
    \item Optionally one can provide a #-page# option to select a given
Packit df99a1
      page from the document, if it's a multipage document. The page numbers
Packit df99a1
      start from #1#.
Packit df99a1
    \end{itemize}
Packit df99a1
    This commands also supports #"Smmr"# chunks for G4/MMR encoded masks,
Packit df99a1
    #"FGjp"# and #"BGjp"# for JPEG encoded color layers, and finally #"FG2k"#
Packit df99a1
    and #"BG2k"# for JPEG-2000 encoded color layers.
Packit df99a1
Packit df99a1
    @memo
Packit df99a1
    Extract components from DjVu files.
Packit df99a1
    @author
Packit df99a1
    L\'eon Bottou <leonb@research.att.com> - Initial implementation\\
Packit df99a1
    Andrei Erofeev <eaf@geocities.com> - Multipage support */
Packit df99a1
//@{
Packit df99a1
//@}
Packit df99a1
Packit df99a1
#include "GException.h"
Packit df99a1
#include "ByteStream.h"
Packit df99a1
#include "IFFByteStream.h"
Packit df99a1
#include "DjVuDocument.h"
Packit df99a1
#include "DjVuFile.h"
Packit df99a1
#include "GOS.h"
Packit df99a1
#include "DjVuMessage.h"
Packit df99a1
#include "common.h"
Packit df99a1
Packit df99a1
struct DejaVuInfo
Packit df99a1
{
Packit df99a1
  unsigned char width_hi, width_lo;
Packit df99a1
  unsigned char height_hi, height_lo;
Packit df99a1
  char version;
Packit df99a1
} djvuinfo;
Packit df99a1
Packit df99a1
struct PrimaryHeader {
Packit df99a1
  unsigned char serial;
Packit df99a1
  unsigned char slices;
Packit df99a1
} primary;
Packit df99a1
Packit df99a1
struct SecondaryHeader {
Packit df99a1
  unsigned char major;
Packit df99a1
  unsigned char minor;
Packit df99a1
  unsigned char xhi, xlo;
Packit df99a1
  unsigned char yhi, ylo;
Packit df99a1
} secondary;
Packit df99a1
Packit df99a1
Packit df99a1
static void
Packit df99a1
extract_chunk(GP<ByteStream> ibs, const GUTF8String &id, GP<ByteStream> out)
Packit df99a1
{
Packit df99a1
  ibs->seek(0);
Packit df99a1
  GP<IFFByteStream> giff=IFFByteStream::create(ibs);
Packit df99a1
  IFFByteStream &iff=*giff;
Packit df99a1
  GUTF8String chkid;
Packit df99a1
  if (! iff.get_chunk(chkid))
Packit df99a1
    G_THROW("Malformed DJVU file");
Packit df99a1
  if (chkid != "FORM:DJVU" && chkid != "FORM:DJVI" )
Packit df99a1
    G_THROW("This is not a layered DJVU file");
Packit df99a1
  
Packit df99a1
Packit df99a1
  // Special case for FG44 and BG44
Packit df99a1
  if (id == "BG44" || id == "FG44")
Packit df99a1
    {
Packit df99a1
      // Rebuild IW44 file
Packit df99a1
      GP<IFFByteStream> giffout=IFFByteStream::create(out);
Packit df99a1
      IFFByteStream &iffout=*giffout;
Packit df99a1
      int color_bg = -1;
Packit df99a1
      while (iff.get_chunk(chkid))
Packit df99a1
        {
Packit df99a1
          if (chkid == id)
Packit df99a1
            {
Packit df99a1
              GP<ByteStream> gtemp=ByteStream::create();
Packit df99a1
              ByteStream &temp=*gtemp;
Packit df99a1
              temp.copy(*iff.get_bytestream());
Packit df99a1
              temp.seek(0);
Packit df99a1
              if (temp.readall((void*)&primary, sizeof(primary))
Packit df99a1
                G_THROW("Cannot read primary header in BG44 chunk");
Packit df99a1
              if (primary.serial == 0)
Packit df99a1
                {
Packit df99a1
                  if (temp.readall((void*)&secondary, sizeof(secondary))
Packit df99a1
                    G_THROW("Cannot read secondary header in BG44 chunk");
Packit df99a1
                  color_bg = ! (secondary.major & 0x80);
Packit df99a1
                  iffout.put_chunk(color_bg ? "FORM:PM44" : "FORM:BM44");
Packit df99a1
                }
Packit df99a1
              if (color_bg < 0)
Packit df99a1
                G_THROW("IW44 chunks are not in proper order");
Packit df99a1
              temp.seek(0);
Packit df99a1
              iffout.put_chunk(color_bg ? "PM44" : "BM44");
Packit df99a1
              iffout.copy(temp);
Packit df99a1
              iffout.close_chunk();
Packit df99a1
            }
Packit df99a1
          iff.close_chunk();
Packit df99a1
        }
Packit df99a1
    }
Packit df99a1
  else
Packit df99a1
    {
Packit df99a1
      // Just concatenates all matching chunks
Packit df99a1
      while (iff.get_chunk(chkid))
Packit df99a1
        {
Packit df99a1
          if (chkid == id)
Packit df99a1
            out->copy(*iff.get_bytestream());
Packit df99a1
          iff.close_chunk();
Packit df99a1
        }
Packit df99a1
    }
Packit df99a1
}
Packit df99a1
Packit df99a1
Packit df99a1
void 
Packit df99a1
usage()
Packit df99a1
{
Packit df99a1
  DjVuPrintErrorUTF8("%s",
Packit df99a1
#ifdef DJVULIBRE_VERSION
Packit df99a1
          "DJVUEXTRACT --- DjVuLibre-" DJVULIBRE_VERSION "\n"
Packit df99a1
#endif
Packit df99a1
          "Extracts components of a DjVu file\n"
Packit df99a1
          "\n"
Packit df99a1
          "Usage:\n"
Packit df99a1
	  "   djvuextract <djvufile> [-page=<num>] {...<chunkid>=<file>...} \n");
Packit df99a1
  exit(1);
Packit df99a1
}
Packit df99a1
Packit df99a1
Packit df99a1
int
Packit df99a1
main(int argc, char **argv)
Packit df99a1
{
Packit df99a1
  DJVU_LOCALE;
Packit df99a1
  GArray<GUTF8String> dargv(0,argc-1);
Packit df99a1
  for(int i=0;i
Packit df99a1
    dargv[i]=GNativeString(argv[i]);
Packit df99a1
  G_TRY
Packit df99a1
    {
Packit df99a1
      int i;
Packit df99a1
Packit df99a1
      // Process page number
Packit df99a1
      int page_num=0;
Packit df99a1
      for(i=1;i
Packit df99a1
	 if (!dargv[i].cmp("-page=", 6))
Packit df99a1
           {
Packit df99a1
              page_num = dargv[i].substr(6,dargv[i].length()).toInt() - 1; // atoi(6+(const char *)dargv[i]) - 1;
Packit df99a1
             for(int j=i;j
Packit df99a1
               dargv[j]=dargv[j+1];
Packit df99a1
             argc--;
Packit df99a1
             break;
Packit df99a1
           } 
Packit df99a1
      if (page_num<0)
Packit df99a1
        {
Packit df99a1
          DjVuPrintErrorUTF8("%s", "Invalid page number\n");
Packit df99a1
          usage();
Packit df99a1
        }
Packit df99a1
      
Packit df99a1
      // Check that chunk names are legal
Packit df99a1
      if (argc<=2)
Packit df99a1
        usage();
Packit df99a1
      for (i=2; i
Packit df99a1
        if (IFFByteStream::check_id(dargv[i]) || dargv[i][4]!='=' || dargv[i][5]==0)
Packit df99a1
          usage();
Packit df99a1
Packit df99a1
      // Decode
Packit df99a1
      const GURL::Filename::UTF8 url1(dargv[1]);
Packit df99a1
      GP<DjVuDocument> doc=DjVuDocument::create_wait(url1);
Packit df99a1
      if (! doc->wait_for_complete_init() || ! doc->is_init_ok())
Packit df99a1
        G_THROW("Decoding failed. Nothing can be done.");        
Packit df99a1
      GP<DjVuFile> file=doc->get_djvu_file(page_num);
Packit df99a1
      GP<ByteStream> pibs = file->get_djvu_bytestream(false, false);
Packit df99a1
      // Extract required chunks
Packit df99a1
      for (i=2; i
Packit df99a1
        {
Packit df99a1
          GP<ByteStream> gmbs=ByteStream::create();
Packit df99a1
          const GUTF8String chunkid=dargv[i].substr(0,4);
Packit df99a1
          extract_chunk(pibs, chunkid, gmbs);
Packit df99a1
          ByteStream &mbs=*gmbs;
Packit df99a1
          if (mbs.size() == 0)
Packit df99a1
            {
Packit df99a1
              DjVuPrintErrorUTF8("  %s --> not found!\n", (const char *)dargv[i]);
Packit df99a1
            }
Packit df99a1
          else
Packit df99a1
            {
Packit df99a1
              const GURL::Filename::UTF8 url((const char *)dargv[i].substr(5,-1));
Packit df99a1
              GP<ByteStream> obs=ByteStream::create(url,"wb");
Packit df99a1
              mbs.seek(0);
Packit df99a1
              obs->copy(mbs);
Packit df99a1
              DjVuPrintErrorUTF8("  %s --> \"%s\" (%d bytes)\n", 
Packit df99a1
                      (const char *)dargv[i], (const char *)dargv[i]+5, mbs.size());
Packit df99a1
            }
Packit df99a1
        }
Packit df99a1
    }
Packit df99a1
  G_CATCH(ex)
Packit df99a1
    {
Packit df99a1
      ex.perror();
Packit df99a1
      exit(1);
Packit df99a1
    }
Packit df99a1
  G_ENDCATCH;
Packit df99a1
  return 0;
Packit df99a1
}