|
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 djvumake
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
{\bf Synopsis}
|
|
Packit |
df99a1 |
\begin{verbatim}
|
|
Packit |
df99a1 |
% djvumake <djvufile> [...<arguments>...]
|
|
Packit |
df99a1 |
\end{verbatim}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
{\bf Description}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
This command assembles a single-page DjVu file by copying or creating
|
|
Packit |
df99a1 |
chunks according to the provided <arguments>. Supported syntaxes for
|
|
Packit |
df99a1 |
<arguments> are as follows:
|
|
Packit |
df99a1 |
\begin{tabular}{ll}
|
|
Packit |
df99a1 |
{#INFO=<w>,<h>,<dpi>#} &
|
|
Packit |
df99a1 |
Creates the initial ``INFO'' chunk. Arguments #w#, #h# and #dpi#
|
|
Packit |
df99a1 |
describe the width, height and resolution of the image. All arguments
|
|
Packit |
df99a1 |
may be omitted. The default resolution is 300 dpi. The default width
|
|
Packit |
df99a1 |
and height will be retrieved from the first mask chunk specified in the
|
|
Packit |
df99a1 |
command line options.\\
|
|
Packit |
df99a1 |
{#Sjbz=<jb2file>#} &
|
|
Packit |
df99a1 |
Creates a JB2 mask chunk. File #jb2file# may
|
|
Packit |
df99a1 |
contain raw JB2 data or be a DjVu file containing JB2 data, such as the
|
|
Packit |
df99a1 |
files produced by \Ref{cjb2}.\\
|
|
Packit |
df99a1 |
{#Smmr=<mmrfile>] #} &
|
|
Packit |
df99a1 |
Creates a mask chunk containing MMR/G4 data. File #mmrfile#
|
|
Packit |
df99a1 |
may contain raw MMR data or be a DjVu file containing MMR data.\\
|
|
Packit |
df99a1 |
{#BG44=<iw44file>:<n>#} &
|
|
Packit |
df99a1 |
Creates one or more IW44 background chunks. File #iw44file# must be an
|
|
Packit |
df99a1 |
IW44 file such as the files created by \Ref{c44}. The optional argument
|
|
Packit |
df99a1 |
#n# indicates the number of chunks to copy from the IW44 file.\\
|
|
Packit |
df99a1 |
{#BGjp=<jpegfile>#} &
|
|
Packit |
df99a1 |
Creates a JPEG background chunk.\\
|
|
Packit |
df99a1 |
{#BG2k=<jpegfile>#} &
|
|
Packit |
df99a1 |
Creates a JPEG-2000 background chunk.\\
|
|
Packit |
df99a1 |
{#FG44=<iw44file>#} &
|
|
Packit |
df99a1 |
Creates one IW44 foreround chunks. File #iw44file# must be an
|
|
Packit |
df99a1 |
IW44 file such as the files created by \Ref{c44}. Only the first
|
|
Packit |
df99a1 |
chunk will be copied.\\
|
|
Packit |
df99a1 |
{FGbz=(bzzfile|\{#color1[:x,y,w,h]\})}
|
|
Packit |
df99a1 |
Creates a chunk containing colors for each JB2 encoded object.
|
|
Packit |
df99a1 |
Such chunks are created using class \Ref{DjVuPalette}.
|
|
Packit |
df99a1 |
See program \Ref{cpaldjvu} for an example.\\
|
|
Packit |
df99a1 |
{#FGjp=<jpegfile>#} &
|
|
Packit |
df99a1 |
Creates a JPEG foreground chunk.\\
|
|
Packit |
df99a1 |
{#FG2k=<jpegfile>#} &
|
|
Packit |
df99a1 |
Creates a JPEG-2000 foreground chunk.\\
|
|
Packit |
df99a1 |
{#INCL=<fileid>#} &
|
|
Packit |
df99a1 |
Creates an include chunk pointing to <fileid>.
|
|
Packit |
df99a1 |
The resulting file should then be included into a
|
|
Packit |
df99a1 |
multipage document.\\
|
|
Packit |
df99a1 |
{#PPM=<ppmfile>#} (psuedo-chunk) &
|
|
Packit |
df99a1 |
Create IW44 foreground and background chunks
|
|
Packit |
df99a1 |
by masking and subsampling PPM file #ppmfile#.
|
|
Packit |
df99a1 |
This is used by program \Ref{cdjvu}.\\
|
|
Packit |
df99a1 |
{#chunk=<rawdatafile>#} &
|
|
Packit |
df99a1 |
Creates the specified chunk with the specified raw data.
|
|
Packit |
df99a1 |
\end{tabular}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
Let us assume now that you have a PPM image #"myimage.ppm"# and a PBM
|
|
Packit |
df99a1 |
bitonal image #"mymask.pbm"# whose black pixels indicate which pixels
|
|
Packit |
df99a1 |
belong to the foreground. Such a bitonal file may be obtained by
|
|
Packit |
df99a1 |
thresholding, although more sophisticated techniques can give better
|
|
Packit |
df99a1 |
results. You can then generate a Compound DjVu File by typing:
|
|
Packit |
df99a1 |
\begin{verbatim}
|
|
Packit |
df99a1 |
% cjb2 mymask.pbm mymask.djvu
|
|
Packit |
df99a1 |
% djvumake mycompound.djvu Sjbz=mymask.djvu PPM=myimage.ppm
|
|
Packit |
df99a1 |
\end{verbatim}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
@memo
|
|
Packit |
df99a1 |
Assemble DjVu files.
|
|
Packit |
df99a1 |
@author
|
|
Packit |
df99a1 |
L\'eon Bottou <leonb@research.att.com> \\
|
|
Packit |
df99a1 |
Patrick Haffner <haffner@research.att.com>
|
|
Packit |
df99a1 |
*/
|
|
Packit |
df99a1 |
//@{
|
|
Packit |
df99a1 |
//@}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#include "GString.h"
|
|
Packit |
df99a1 |
#include "GException.h"
|
|
Packit |
df99a1 |
#include "DjVuImage.h"
|
|
Packit |
df99a1 |
#include "MMRDecoder.h"
|
|
Packit |
df99a1 |
#include "IFFByteStream.h"
|
|
Packit |
df99a1 |
#include "JB2Image.h"
|
|
Packit |
df99a1 |
#include "IW44Image.h"
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#include "GPixmap.h"
|
|
Packit |
df99a1 |
#include "GBitmap.h"
|
|
Packit |
df99a1 |
#include "GContainer.h"
|
|
Packit |
df99a1 |
#include "GRect.h"
|
|
Packit |
df99a1 |
#include "DjVuMessage.h"
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#include "common.h"
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
int flag_contains_fg = 0;
|
|
Packit |
df99a1 |
int flag_contains_bg = 0;
|
|
Packit |
df99a1 |
int flag_contains_stencil = 0;
|
|
Packit |
df99a1 |
int flag_contains_incl = 0;
|
|
Packit |
df99a1 |
int flag_fg_needs_palette = 0;
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
struct DJVUMAKEGlobal
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
// Globals that need static initialization
|
|
Packit |
df99a1 |
// are grouped here to work around broken compilers.
|
|
Packit |
df99a1 |
GP<ByteStream> jb2stencil;
|
|
Packit |
df99a1 |
GP<ByteStream> mmrstencil;
|
|
Packit |
df99a1 |
GP<JB2Image> stencil;
|
|
Packit |
df99a1 |
GP<JB2Dict> dictionary;
|
|
Packit |
df99a1 |
GTArray<GRect> colorzones;
|
|
Packit |
df99a1 |
GP<ByteStream> colorpalette;
|
|
Packit |
df99a1 |
};
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static DJVUMAKEGlobal& g(void)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
static DJVUMAKEGlobal g;
|
|
Packit |
df99a1 |
return g;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
int w = -1;
|
|
Packit |
df99a1 |
int h = -1;
|
|
Packit |
df99a1 |
int dpi = 300;
|
|
Packit |
df99a1 |
int blit_count = -1;
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// -- Display brief usage information
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
usage()
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
DjVuPrintErrorUTF8(
|
|
Packit |
df99a1 |
#ifdef DJVULIBRE_VERSION
|
|
Packit |
df99a1 |
"DJVUMAKE --- DjVuLibre-" DJVULIBRE_VERSION "\n"
|
|
Packit |
df99a1 |
#endif
|
|
Packit |
df99a1 |
"Utility for manually assembling DjVu files\n\n"
|
|
Packit |
df99a1 |
"Usage: djvumake djvufile ...arguments...\n"
|
|
Packit |
df99a1 |
"\n"
|
|
Packit |
df99a1 |
"The arguments describe the successive chunks of the DJVU file.\n"
|
|
Packit |
df99a1 |
"Possible arguments are:\n"
|
|
Packit |
df99a1 |
"\n"
|
|
Packit |
df99a1 |
" INFO=w[,[h[,[dpi]]]] -- Create the initial information chunk\n"
|
|
Packit |
df99a1 |
" Sjbz=jb2file -- Create a JB2 mask chunk\n"
|
|
Packit |
df99a1 |
" Djbz=jb2file -- Create a JB2 shape dictionary\n"
|
|
Packit |
df99a1 |
" Smmr=mmrfile -- Create a MMR mask chunk\n"
|
|
Packit |
df99a1 |
" BG44=[iw4file][:nchunks] -- Create one or more IW44 background chunks\n"
|
|
Packit |
df99a1 |
" BGjp=jpegfile -- Create a JPEG background chunk\n"
|
|
Packit |
df99a1 |
" BG2k=jpeg2000file -- Create a JP2K background chunk\n"
|
|
Packit |
df99a1 |
" FG44=iw4file -- Create an IW44 foreground chunk\n"
|
|
Packit |
df99a1 |
" FGbz=bzzfile -- Create a foreground color chunk from a file\n"
|
|
Packit |
df99a1 |
" FGbz={#color:x,y,w,h} -- Create a foreground color chunk from zones\n"
|
|
Packit |
df99a1 |
" FGjp=jpegfile -- Create a JPEG foreground image chunk\n"
|
|
Packit |
df99a1 |
" FG2k=jpeg2000file -- Create a JP2K foreground image chunk\n"
|
|
Packit |
df99a1 |
" INCL=fileid -- Create an INCL chunk\n"
|
|
Packit |
df99a1 |
" chunk=rawdatafile -- Create the specified chunk from the raw data file\n"
|
|
Packit |
df99a1 |
" PPM=ppmfile -- Create IW44 foreground and background chunks\n"
|
|
Packit |
df99a1 |
" by masking and subsampling a PPM file.\n"
|
|
Packit |
df99a1 |
"\n"
|
|
Packit |
df99a1 |
"You may omit the specification of the information chunk. An information\n"
|
|
Packit |
df99a1 |
"chunk will be created using the image size of the first mask chunk\n"
|
|
Packit |
df99a1 |
"This program is sometimes able to issue a warning when you are building an\n"
|
|
Packit |
df99a1 |
"incorrect djvu file.\n"
|
|
Packit |
df99a1 |
"\n");
|
|
Packit |
df99a1 |
exit(1);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// -- Obtain image size from mmr chunk
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
analyze_mmr_chunk(const GURL &url)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (!g().mmrstencil || !g().mmrstencil->size())
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
GP<ByteStream> gbs=ByteStream::create(url,"rb");
|
|
Packit |
df99a1 |
ByteStream &bs=*gbs;
|
|
Packit |
df99a1 |
g().mmrstencil = ByteStream::create();
|
|
Packit |
df99a1 |
// Check if file is an IFF file
|
|
Packit |
df99a1 |
char magic[4];
|
|
Packit |
df99a1 |
memset(magic,0,sizeof(magic));
|
|
Packit |
df99a1 |
bs.readall(magic,sizeof(magic));
|
|
Packit |
df99a1 |
if (!GStringRep::cmp(magic,"AT&T",4))
|
|
Packit |
df99a1 |
bs.readall(magic,sizeof(magic));
|
|
Packit |
df99a1 |
if (GStringRep::cmp(magic,"FORM",4))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
// Must be a raw file
|
|
Packit |
df99a1 |
bs.seek(0);
|
|
Packit |
df99a1 |
g().mmrstencil->copy(bs);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
// Search Smmr chunk
|
|
Packit |
df99a1 |
bs.seek(0);
|
|
Packit |
df99a1 |
GUTF8String chkid;
|
|
Packit |
df99a1 |
GP<IFFByteStream> giff=IFFByteStream::create(gbs);
|
|
Packit |
df99a1 |
IFFByteStream &iff=*giff;
|
|
Packit |
df99a1 |
if (iff.get_chunk(chkid)==0 || chkid!="FORM:DJVU")
|
|
Packit |
df99a1 |
G_THROW("Expecting a DjVu file!");
|
|
Packit |
df99a1 |
for(; iff.get_chunk(chkid); iff.close_chunk())
|
|
Packit |
df99a1 |
if (chkid=="Smmr") { g().mmrstencil->copy(bs); break; }
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
// Check result
|
|
Packit |
df99a1 |
g().mmrstencil->seek(0);
|
|
Packit |
df99a1 |
if (!g().mmrstencil->size())
|
|
Packit |
df99a1 |
G_THROW("Could not find MMR data");
|
|
Packit |
df99a1 |
// Decode
|
|
Packit |
df99a1 |
g().stencil = MMRDecoder::decode(g().mmrstencil);
|
|
Packit |
df99a1 |
int jw = g().stencil->get_width();
|
|
Packit |
df99a1 |
int jh = g().stencil->get_height();
|
|
Packit |
df99a1 |
if (w < 0) w = jw;
|
|
Packit |
df99a1 |
if (h < 0) h = jh;
|
|
Packit |
df99a1 |
if (jw!=w || jh!=h)
|
|
Packit |
df99a1 |
DjVuPrintErrorUTF8("djvumake: mask size (%s) does not match info size\n", (const char *)url);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// -- Obtain shape dictionary
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
analyze_djbz_chunk(GP<ByteStream> gbs)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (g().dictionary)
|
|
Packit |
df99a1 |
G_THROW("Duplicate Djbz dictionary");
|
|
Packit |
df99a1 |
g().dictionary = JB2Dict::create();
|
|
Packit |
df99a1 |
g().dictionary->decode(gbs);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
analyze_djbz_chunk(const GURL &url)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
GP<ByteStream> gbs = ByteStream::create(url, "rb");
|
|
Packit |
df99a1 |
analyze_djbz_chunk(gbs);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// -- Obtain image size and blit count from jb2 chunk
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
GP<JB2Dict>
|
|
Packit |
df99a1 |
provide_shared_dict( void* )
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
return(g().dictionary);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
analyze_jb2_chunk(const GURL &url)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (!g().jb2stencil || !g().jb2stencil->size())
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
GP<ByteStream> gbs=ByteStream::create(url,"rb");
|
|
Packit |
df99a1 |
ByteStream &bs=*gbs;
|
|
Packit |
df99a1 |
g().jb2stencil = ByteStream::create();
|
|
Packit |
df99a1 |
// Check if file is an IFF file
|
|
Packit |
df99a1 |
char magic[4];
|
|
Packit |
df99a1 |
memset(magic,0,sizeof(magic));
|
|
Packit |
df99a1 |
bs.readall(magic,sizeof(magic));
|
|
Packit |
df99a1 |
if (!GStringRep::cmp(magic,"AT&T",4))
|
|
Packit |
df99a1 |
bs.readall(magic,sizeof(magic));
|
|
Packit |
df99a1 |
if (GStringRep::cmp(magic,"FORM",4))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
// Must be a raw file
|
|
Packit |
df99a1 |
bs.seek(0);
|
|
Packit |
df99a1 |
g().jb2stencil->copy(bs);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
// Search Sjbz chunk
|
|
Packit |
df99a1 |
bs.seek(0);
|
|
Packit |
df99a1 |
GUTF8String chkid;
|
|
Packit |
df99a1 |
GP<IFFByteStream> giff=IFFByteStream::create(gbs);
|
|
Packit |
df99a1 |
IFFByteStream &iff=*giff;
|
|
Packit |
df99a1 |
if (iff.get_chunk(chkid)==0 || chkid!="FORM:DJVU")
|
|
Packit |
df99a1 |
G_THROW("Expecting a DjVu file!");
|
|
Packit |
df99a1 |
for(; iff.get_chunk(chkid); iff.close_chunk())
|
|
Packit |
df99a1 |
if (chkid=="Sjbz") { g().jb2stencil->copy(bs); break; }
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
// Check result
|
|
Packit |
df99a1 |
g().jb2stencil->seek(0);
|
|
Packit |
df99a1 |
if (!g().jb2stencil->size())
|
|
Packit |
df99a1 |
G_THROW("Could not find JB2 data");
|
|
Packit |
df99a1 |
// Decode
|
|
Packit |
df99a1 |
g().stencil=JB2Image::create();
|
|
Packit |
df99a1 |
g().stencil->decode(g().jb2stencil,&provide_shared_dict,NULL);
|
|
Packit |
df99a1 |
int jw = g().stencil->get_width();
|
|
Packit |
df99a1 |
int jh = g().stencil->get_height();
|
|
Packit |
df99a1 |
if (w < 0)
|
|
Packit |
df99a1 |
w = jw;
|
|
Packit |
df99a1 |
if (h < 0)
|
|
Packit |
df99a1 |
h = jh;
|
|
Packit |
df99a1 |
if (blit_count < 0)
|
|
Packit |
df99a1 |
blit_count = g().stencil->get_blit_count();
|
|
Packit |
df99a1 |
if (jw!=w || jh!=h)
|
|
Packit |
df99a1 |
DjVuPrintErrorUTF8("djvumake: mask size (%s) does not match info size\n", (const char *)url);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// -- Load dictionary from an INCL chunk
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
analyze_incl_chunk(const GURL &url)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
GP<ByteStream> gbs = ByteStream::create(url,"rb");
|
|
Packit |
df99a1 |
char buffer[24];
|
|
Packit |
df99a1 |
memset(buffer, 0, sizeof(buffer));
|
|
Packit |
df99a1 |
gbs->read(buffer,sizeof(buffer));
|
|
Packit |
df99a1 |
char *s = buffer;
|
|
Packit |
df99a1 |
if (!strncmp(s, "AT&T", 4))
|
|
Packit |
df99a1 |
s += 4;
|
|
Packit |
df99a1 |
if (strncmp(s, "FORM", 4) || strncmp(s+8, "DJVI", 4))
|
|
Packit |
df99a1 |
G_THROW("Expecting a valid FORM:DJVI chunk in the included file");
|
|
Packit |
df99a1 |
gbs->seek(0);
|
|
Packit |
df99a1 |
GP<IFFByteStream> giff=IFFByteStream::create(gbs);
|
|
Packit |
df99a1 |
GUTF8String chkid;
|
|
Packit |
df99a1 |
giff->get_chunk(chkid); // FORM:DJVI
|
|
Packit |
df99a1 |
for(; giff->get_chunk(chkid); giff->close_chunk())
|
|
Packit |
df99a1 |
if (chkid=="Djbz")
|
|
Packit |
df99a1 |
analyze_djbz_chunk(giff->get_bytestream());
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
check_for_shared_dict(GArray<GUTF8String> &argv)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
const int argc=argv.hbound()+1;
|
|
Packit |
df99a1 |
for (int i=2; i
|
|
Packit |
df99a1 |
if (!argv[i].cmp("INCL=",5))
|
|
Packit |
df99a1 |
analyze_incl_chunk(GURL::Filename::UTF8(5+(const char *)argv[i]));
|
|
Packit |
df99a1 |
else if (!argv[i].cmp("Djbz=", 5))
|
|
Packit |
df99a1 |
analyze_djbz_chunk(GURL::Filename::UTF8(5+(const char *)argv[i]));
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// -- Create info chunk from specification or mask
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
create_info_chunk(IFFByteStream &iff, GArray<GUTF8String> &argv)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
const int argc=argv.hbound()+1;
|
|
Packit |
df99a1 |
// Process info specification
|
|
Packit |
df99a1 |
for (int i=2; i
|
|
Packit |
df99a1 |
if (!argv[i].cmp("INFO=",5))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int narg = 0;
|
|
Packit |
df99a1 |
const char *ptr = 5+(const char *)argv[i];
|
|
Packit |
df99a1 |
while (*ptr)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (*ptr != ',')
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int x = strtol((char *)ptr, (char **)&ptr, 10);
|
|
Packit |
df99a1 |
switch(narg)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
case 0:
|
|
Packit |
df99a1 |
w = x; break;
|
|
Packit |
df99a1 |
case 1:
|
|
Packit |
df99a1 |
h = x; break;
|
|
Packit |
df99a1 |
case 2:
|
|
Packit |
df99a1 |
dpi = x; break;
|
|
Packit |
df99a1 |
default:
|
|
Packit |
df99a1 |
G_THROW("djvumake: incorrect 'INFO' chunk specification\n");
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
narg++;
|
|
Packit |
df99a1 |
if (*ptr && *ptr++!=',')
|
|
Packit |
df99a1 |
G_THROW("djvumake: comma expected in 'INFO' chunk specification\n");
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
break;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
if (w>0 && (w<=0 || w>=32768))
|
|
Packit |
df99a1 |
G_THROW("djvumake: incorrect width in 'INFO' chunk specification\n");
|
|
Packit |
df99a1 |
if (h>0 && (h<=0 || h>=32768))
|
|
Packit |
df99a1 |
G_THROW("djvumake: incorrect height in 'INFO' chunk specification\n");
|
|
Packit |
df99a1 |
if (dpi>0 && (dpi<25 || dpi>6000))
|
|
Packit |
df99a1 |
G_THROW("djvumake: incorrect dpi in 'INFO' chunk specification\n");
|
|
Packit |
df99a1 |
// Search first mask chunks if size is still unknown
|
|
Packit |
df99a1 |
if (h<0 || w<0)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
for (int i=2; i
|
|
Packit |
df99a1 |
if (!argv[i].cmp("Sjbz=",5))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
analyze_jb2_chunk(GURL::Filename::UTF8(5+(const char *)argv[i]));
|
|
Packit |
df99a1 |
break;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else if (!argv[i].cmp("Smmr=",5))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
analyze_mmr_chunk(GURL::Filename::UTF8(5+(const char *)argv[i]));
|
|
Packit |
df99a1 |
break;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// Check that we have everything
|
|
Packit |
df99a1 |
if (w<0 || h<0)
|
|
Packit |
df99a1 |
G_THROW("djvumake: cannot determine image size\n");
|
|
Packit |
df99a1 |
// write info chunk
|
|
Packit |
df99a1 |
GP<DjVuInfo> ginfo=DjVuInfo::create();
|
|
Packit |
df99a1 |
DjVuInfo &info=*ginfo;
|
|
Packit |
df99a1 |
info.width = w;
|
|
Packit |
df99a1 |
info.height = h;
|
|
Packit |
df99a1 |
info.dpi = dpi;
|
|
Packit |
df99a1 |
iff.put_chunk("INFO");
|
|
Packit |
df99a1 |
info.encode(*iff.get_bytestream());
|
|
Packit |
df99a1 |
iff.close_chunk();
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// -- Create MMR mask chunk
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
create_mmr_chunk(IFFByteStream &iff, const char *chkid, const GURL &url)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
analyze_mmr_chunk(url);
|
|
Packit |
df99a1 |
g().mmrstencil->seek(0);
|
|
Packit |
df99a1 |
iff.put_chunk(chkid);
|
|
Packit |
df99a1 |
iff.copy(*g().mmrstencil);
|
|
Packit |
df99a1 |
iff.close_chunk();
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// -- Create FGbz palette chunk
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
create_fgbz_chunk(IFFByteStream &iff)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int nzones = g().colorzones.size();
|
|
Packit |
df99a1 |
int npalette = g().colorpalette->size() / 3;
|
|
Packit |
df99a1 |
GP<DjVuPalette> pal = DjVuPalette::create();
|
|
Packit |
df99a1 |
g().colorpalette->seek(0);
|
|
Packit |
df99a1 |
pal->decode_rgb_entries(*g().colorpalette, npalette);
|
|
Packit |
df99a1 |
pal->colordata.resize(0,blit_count-1);
|
|
Packit |
df99a1 |
for (int d=0; d
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
JB2Blit *blit = g().stencil->get_blit(d);
|
|
Packit |
df99a1 |
const JB2Shape &shape = g().stencil->get_shape(blit->shapeno);
|
|
Packit |
df99a1 |
GRect brect(blit->left, blit->bottom, shape.bits->columns(), shape.bits->rows());
|
|
Packit |
df99a1 |
int index = nzones;
|
|
Packit |
df99a1 |
for (int i=0; i
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
GRect zrect = g().colorzones[i];
|
|
Packit |
df99a1 |
if (zrect.isempty() || zrect.intersect(brect, zrect))
|
|
Packit |
df99a1 |
index = i;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
if (index >= npalette)
|
|
Packit |
df99a1 |
G_THROW("create_fgbz_chunk: internal error");
|
|
Packit |
df99a1 |
pal->colordata[d] = index;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
iff.put_chunk("FGbz");
|
|
Packit |
df99a1 |
pal->encode(iff.get_bytestream());
|
|
Packit |
df99a1 |
iff.close_chunk();
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// -- Create JB2 mask chunk
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
create_jb2_chunk(IFFByteStream &iff, const char *chkid, const GURL &url)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
analyze_jb2_chunk(url);
|
|
Packit |
df99a1 |
g().jb2stencil->seek(0);
|
|
Packit |
df99a1 |
iff.put_chunk(chkid);
|
|
Packit |
df99a1 |
iff.copy(*g().jb2stencil);
|
|
Packit |
df99a1 |
iff.close_chunk();
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// -- Create inclusion chunk
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
create_incl_chunk(IFFByteStream &iff, const char *chkid, const char *fileid)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
iff.put_chunk("INCL");
|
|
Packit |
df99a1 |
iff.write(fileid, strlen(fileid));
|
|
Packit |
df99a1 |
iff.close_chunk();
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// -- Create chunk by copying file contents
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
create_raw_chunk(IFFByteStream &iff, const GUTF8String &chkid, const GURL &url)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
iff.put_chunk(chkid);
|
|
Packit |
df99a1 |
GP<ByteStream> ibs=ByteStream::create(url,"rb");
|
|
Packit |
df99a1 |
iff.copy(*ibs);
|
|
Packit |
df99a1 |
iff.close_chunk();
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// -- Internal headers for IW44
|
|
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 |
// -- Create and check FG44 chunk
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
create_fg44_chunk(IFFByteStream &iff, const char *ckid, const GURL &url)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
GP<ByteStream> gbs=ByteStream::create(url,"rb");
|
|
Packit |
df99a1 |
GP<IFFByteStream> gbsi=IFFByteStream::create(gbs);
|
|
Packit |
df99a1 |
IFFByteStream &bsi=*gbsi;
|
|
Packit |
df99a1 |
GUTF8String chkid;
|
|
Packit |
df99a1 |
bsi.get_chunk(chkid);
|
|
Packit |
df99a1 |
if (chkid != "FORM:PM44" && chkid != "FORM:BM44")
|
|
Packit |
df99a1 |
G_THROW("djvumake: FG44 file has incorrect format (wrong IFF header)");
|
|
Packit |
df99a1 |
bsi.get_chunk(chkid);
|
|
Packit |
df99a1 |
if (chkid!="PM44" && chkid!="BM44")
|
|
Packit |
df99a1 |
G_THROW("djvumake: FG44 file has incorrect format (wring IFF header)");
|
|
Packit |
df99a1 |
GP<ByteStream> gmbs=ByteStream::create();
|
|
Packit |
df99a1 |
ByteStream &mbs=*gmbs;
|
|
Packit |
df99a1 |
mbs.copy(*bsi.get_bytestream());
|
|
Packit |
df99a1 |
bsi.close_chunk();
|
|
Packit |
df99a1 |
if (bsi.get_chunk(chkid))
|
|
Packit |
df99a1 |
DjVuPrintErrorUTF8("%s","djvumake: FG44 file contains more than one chunk\n");
|
|
Packit |
df99a1 |
bsi.close_chunk();
|
|
Packit |
df99a1 |
mbs.seek(0);
|
|
Packit |
df99a1 |
if (mbs.readall((void*)&primary, sizeof(primary)) != sizeof(primary))
|
|
Packit |
df99a1 |
G_THROW("djvumake: FG44 file is corrupted (cannot read primary header)");
|
|
Packit |
df99a1 |
if (primary.serial != 0)
|
|
Packit |
df99a1 |
G_THROW("djvumake: FG44 file is corrupted (wrong serial number)");
|
|
Packit |
df99a1 |
if (mbs.readall((void*)&secondary, sizeof(secondary)) != sizeof(secondary))
|
|
Packit |
df99a1 |
G_THROW("djvumake: FG44 file is corrupted (cannot read secondary header)");
|
|
Packit |
df99a1 |
int iw = (secondary.xhi<<8) + secondary.xlo;
|
|
Packit |
df99a1 |
int ih = (secondary.yhi<<8) + secondary.ylo;
|
|
Packit |
df99a1 |
int red;
|
|
Packit |
df99a1 |
for (red=1; red<=12; red++)
|
|
Packit |
df99a1 |
if (iw==(w+red-1)/red && ih==(h+red-1)/red)
|
|
Packit |
df99a1 |
break;
|
|
Packit |
df99a1 |
flag_contains_fg = red;
|
|
Packit |
df99a1 |
if (red>12)
|
|
Packit |
df99a1 |
DjVuPrintErrorUTF8("%s","djvumake: FG44 subsampling is not in [1..12] range\n");
|
|
Packit |
df99a1 |
mbs.seek(0);
|
|
Packit |
df99a1 |
iff.put_chunk(ckid);
|
|
Packit |
df99a1 |
iff.copy(mbs);
|
|
Packit |
df99a1 |
iff.close_chunk();
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// -- Create and check BG44 chunk
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
create_bg44_chunk(IFFByteStream &iff, const char *ckid, GUTF8String filespec)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
static GP<IFFByteStream> bg44iff;
|
|
Packit |
df99a1 |
if (! bg44iff)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (flag_contains_bg)
|
|
Packit |
df99a1 |
DjVuPrintErrorUTF8("%s","djvumake: Duplicate BGxx chunk\n");
|
|
Packit |
df99a1 |
int i=filespec.rsearch(':');
|
|
Packit |
df99a1 |
for (int j=i+1; i>0 && j<(int)filespec.length(); j++)
|
|
Packit |
df99a1 |
if (filespec[j] < '0' || filespec[j] > '9')
|
|
Packit |
df99a1 |
i = -1;
|
|
Packit |
df99a1 |
if (!i)
|
|
Packit |
df99a1 |
G_THROW("djvumake: no filename specified in first BG44 specification");
|
|
Packit |
df99a1 |
GUTF8String filename=(i<0)?filespec:GUTF8String(filespec, i);
|
|
Packit |
df99a1 |
const GURL::Filename::UTF8 url(filename);
|
|
Packit |
df99a1 |
const GP<ByteStream> gbs(ByteStream::create(url,"rb"));
|
|
Packit |
df99a1 |
if(!gbs)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
G_THROW("djvumake: no such file as"+filename);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
bg44iff = IFFByteStream::create(gbs);
|
|
Packit |
df99a1 |
GUTF8String chkid;
|
|
Packit |
df99a1 |
bg44iff->get_chunk(chkid);
|
|
Packit |
df99a1 |
if (chkid != "FORM:PM44" && chkid != "FORM:BM44")
|
|
Packit |
df99a1 |
G_THROW("djvumake: BG44 file has incorrect format (wrong IFF header)");
|
|
Packit |
df99a1 |
if (i>=0)
|
|
Packit |
df99a1 |
filespec = i+1+(const char *)filespec;
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
filespec = "99";
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (filespec.length() && filespec[0]!=':')
|
|
Packit |
df99a1 |
G_THROW("djvumake: filename specified in BG44 refinement");
|
|
Packit |
df99a1 |
filespec = 1+(const char *)filespec;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
const char *s=filespec;
|
|
Packit |
df99a1 |
int nchunks = strtol((char *)s, (char **)&s, 10);
|
|
Packit |
df99a1 |
if (nchunks<1 || nchunks>99)
|
|
Packit |
df99a1 |
G_THROW("djvumake: invalid number of chunks in BG44 specification");
|
|
Packit |
df99a1 |
if (*s)
|
|
Packit |
df99a1 |
G_THROW("djvumake: invalid BG44 specification (syntax error)");
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
int flag = (nchunks>=99);
|
|
Packit |
df99a1 |
GUTF8String chkid;
|
|
Packit |
df99a1 |
while (nchunks-->0 && bg44iff->get_chunk(chkid))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (chkid!="PM44" && chkid!="BM44")
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
DjVuPrintErrorUTF8("%s","djvumake: BG44 file contains unrecognized chunks (fixed)\n");
|
|
Packit |
df99a1 |
nchunks += 1;
|
|
Packit |
df99a1 |
bg44iff->close_chunk();
|
|
Packit |
df99a1 |
continue;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
GP<ByteStream> gmbs=ByteStream::create();
|
|
Packit |
df99a1 |
ByteStream &mbs=*gmbs;
|
|
Packit |
df99a1 |
mbs.copy(*(bg44iff->get_bytestream()));
|
|
Packit |
df99a1 |
bg44iff->close_chunk();
|
|
Packit |
df99a1 |
mbs.seek(0);
|
|
Packit |
df99a1 |
if (mbs.readall((void*)&primary, sizeof(primary)) != sizeof(primary))
|
|
Packit |
df99a1 |
G_THROW("djvumake: BG44 file is corrupted (cannot read primary header)\n");
|
|
Packit |
df99a1 |
if (primary.serial == 0)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (mbs.readall((void*)&secondary, sizeof(secondary)) != sizeof(secondary))
|
|
Packit |
df99a1 |
G_THROW("djvumake: BG44 file is corrupted (cannot read secondary header)\n");
|
|
Packit |
df99a1 |
int iw = (secondary.xhi<<8) + secondary.xlo;
|
|
Packit |
df99a1 |
int ih = (secondary.yhi<<8) + secondary.ylo;
|
|
Packit |
df99a1 |
int red;
|
|
Packit |
df99a1 |
for (red=1; red<=12; red++)
|
|
Packit |
df99a1 |
if (iw==(w+red-1)/red && ih==(h+red-1)/red)
|
|
Packit |
df99a1 |
break;
|
|
Packit |
df99a1 |
flag_contains_bg = red;
|
|
Packit |
df99a1 |
if (red>12)
|
|
Packit |
df99a1 |
DjVuPrintErrorUTF8("%s","djvumake: BG44 subsampling is not in [1..12] range\n");
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
mbs.seek(0);
|
|
Packit |
df99a1 |
iff.put_chunk(ckid);
|
|
Packit |
df99a1 |
iff.copy(mbs);
|
|
Packit |
df99a1 |
iff.close_chunk();
|
|
Packit |
df99a1 |
flag = 1;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
if (!flag)
|
|
Packit |
df99a1 |
DjVuPrintErrorUTF8("%s","djvumake: no more chunks in BG44 file\n");
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// -- Forward declarations
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void processForeground(const GPixmap* image, const JB2Image *mask,
|
|
Packit |
df99a1 |
GPixmap& subsampled_image, GBitmap& subsampled_mask);
|
|
Packit |
df99a1 |
void processBackground(const GPixmap* image, const JB2Image *mask,
|
|
Packit |
df99a1 |
GPixmap& subsampled_image, GBitmap& subsampled_mask);
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// -- Create both foreground and background by masking and subsampling
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
create_masksub_chunks(IFFByteStream &iff, const GURL &url)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
// Check and load pixmap file
|
|
Packit |
df99a1 |
if (!g().stencil)
|
|
Packit |
df99a1 |
G_THROW("The use of a raw ppm image requires a stencil");
|
|
Packit |
df99a1 |
GP<ByteStream> gibs=ByteStream::create(url, "rb");
|
|
Packit |
df99a1 |
ByteStream &ibs=*gibs;
|
|
Packit |
df99a1 |
GP<GPixmap> graw_pm=GPixmap::create(ibs);
|
|
Packit |
df99a1 |
GPixmap &raw_pm=*graw_pm;
|
|
Packit |
df99a1 |
if ((int) g().stencil->get_width() != (int) raw_pm.columns())
|
|
Packit |
df99a1 |
G_THROW("Stencil and raw image have different widths!");
|
|
Packit |
df99a1 |
if ((int) g().stencil->get_height() != (int) raw_pm.rows())
|
|
Packit |
df99a1 |
G_THROW("Stencil and raw image have different heights!");
|
|
Packit |
df99a1 |
// Encode foreground
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
GP<GPixmap> gfg_img=GPixmap::create();
|
|
Packit |
df99a1 |
GPixmap &fg_img=*gfg_img;
|
|
Packit |
df99a1 |
GP<GBitmap> fg_mask=GBitmap::create();
|
|
Packit |
df99a1 |
processForeground(&raw_pm, g().stencil, fg_img, *fg_mask);
|
|
Packit |
df99a1 |
GP<IW44Image> fg_pm = IW44Image::create_encode(fg_img, fg_mask, IW44Image::CRCBfull);
|
|
Packit |
df99a1 |
IWEncoderParms parms[8];
|
|
Packit |
df99a1 |
iff.put_chunk("FG44");
|
|
Packit |
df99a1 |
parms[0].slices = 100;
|
|
Packit |
df99a1 |
fg_pm->encode_chunk(iff.get_bytestream(), parms[0]);
|
|
Packit |
df99a1 |
iff.close_chunk();
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
// Encode backgound
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
GP<GPixmap> gbg_img=GPixmap::create();
|
|
Packit |
df99a1 |
GPixmap &bg_img=*gbg_img;
|
|
Packit |
df99a1 |
GP<GBitmap> bg_mask=GBitmap::create();
|
|
Packit |
df99a1 |
processBackground(&raw_pm, g().stencil, bg_img, *bg_mask);
|
|
Packit |
df99a1 |
GP<IW44Image> bg_pm = IW44Image::create_encode(bg_img, bg_mask, IW44Image::CRCBnormal);
|
|
Packit |
df99a1 |
IWEncoderParms parms[4];
|
|
Packit |
df99a1 |
parms[0].bytes = 10000;
|
|
Packit |
df99a1 |
parms[0].slices = 74;
|
|
Packit |
df99a1 |
iff.put_chunk("BG44");
|
|
Packit |
df99a1 |
bg_pm->encode_chunk(iff.get_bytestream(), parms[0]);
|
|
Packit |
df99a1 |
iff.close_chunk();
|
|
Packit |
df99a1 |
parms[1].slices = 84;
|
|
Packit |
df99a1 |
iff.put_chunk("BG44");
|
|
Packit |
df99a1 |
bg_pm->encode_chunk(iff.get_bytestream(), parms[1]);
|
|
Packit |
df99a1 |
iff.close_chunk();
|
|
Packit |
df99a1 |
parms[2].slices = 90;
|
|
Packit |
df99a1 |
iff.put_chunk("BG44");
|
|
Packit |
df99a1 |
bg_pm->encode_chunk(iff.get_bytestream(), parms[2]);
|
|
Packit |
df99a1 |
iff.close_chunk();
|
|
Packit |
df99a1 |
parms[3].slices = 97;
|
|
Packit |
df99a1 |
iff.put_chunk("BG44");
|
|
Packit |
df99a1 |
bg_pm->encode_chunk(iff.get_bytestream(), parms[3]);
|
|
Packit |
df99a1 |
iff.close_chunk();
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
const char *
|
|
Packit |
df99a1 |
parse_color_name(const char *s, char *rgb)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
static struct {
|
|
Packit |
df99a1 |
const char *name;
|
|
Packit |
df99a1 |
unsigned char r, g, b;
|
|
Packit |
df99a1 |
} stdcols[] = {
|
|
Packit |
df99a1 |
{"aqua", 0x00, 0xFF, 0xFF},
|
|
Packit |
df99a1 |
{"black", 0x00, 0x00, 0x00},
|
|
Packit |
df99a1 |
{"blue", 0x00, 0x00, 0xFF},
|
|
Packit |
df99a1 |
{"fuchsia", 0xFF, 0x00, 0xFF},
|
|
Packit |
df99a1 |
{"gray", 0x80, 0x80, 0x80},
|
|
Packit |
df99a1 |
{"green", 0x00, 0x80, 0x00},
|
|
Packit |
df99a1 |
{"lime", 0x00, 0xFF, 0x00},
|
|
Packit |
df99a1 |
{"maroon", 0x80, 0x00, 0x00},
|
|
Packit |
df99a1 |
{"navy", 0x00, 0x00, 0x80},
|
|
Packit |
df99a1 |
{"olive", 0x80, 0x80, 0x00},
|
|
Packit |
df99a1 |
{"purple", 0x80, 0x00, 0x80},
|
|
Packit |
df99a1 |
{"red", 0xFF, 0x00, 0x00},
|
|
Packit |
df99a1 |
{"silver", 0xC0, 0xC0, 0xC0},
|
|
Packit |
df99a1 |
{"teal", 0x00, 0x80, 0x80},
|
|
Packit |
df99a1 |
{"white", 0xFF, 0xFF, 0xFF},
|
|
Packit |
df99a1 |
{"yellow", 0xFF, 0xFF, 0x00},
|
|
Packit |
df99a1 |
{0}
|
|
Packit |
df99a1 |
};
|
|
Packit |
df99a1 |
// potential color names
|
|
Packit |
df99a1 |
int len = 0;
|
|
Packit |
df99a1 |
while (s[len] && s[len]!=':' && s[len]!='#')
|
|
Packit |
df99a1 |
len += 1;
|
|
Packit |
df99a1 |
GUTF8String name(s, len);
|
|
Packit |
df99a1 |
name = name.downcase();
|
|
Packit |
df99a1 |
for (int i=0; stdcols[i].name; i++)
|
|
Packit |
df99a1 |
if (name == stdcols[i].name)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
rgb[0] = stdcols[i].r;
|
|
Packit |
df99a1 |
rgb[1] = stdcols[i].g;
|
|
Packit |
df99a1 |
rgb[2] = stdcols[i].b;
|
|
Packit |
df99a1 |
return s+len;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
// potential hex specifications
|
|
Packit |
df99a1 |
unsigned int r,g,b;
|
|
Packit |
df99a1 |
if (sscanf(s,"%2x%2x%2x",&r,&g,&b) == 3)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
rgb[0] = r;
|
|
Packit |
df99a1 |
rgb[1] = g;
|
|
Packit |
df99a1 |
rgb[2] = b;
|
|
Packit |
df99a1 |
return s+6;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
G_THROW("Unrecognized color name in FGbz chunk specification");
|
|
Packit |
df99a1 |
return 0; // win
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
parse_color_zones(const char *s)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
bool fullpage = false;
|
|
Packit |
df99a1 |
int zones = 0;
|
|
Packit |
df99a1 |
g().colorzones.empty();
|
|
Packit |
df99a1 |
g().colorpalette = ByteStream::create();
|
|
Packit |
df99a1 |
// zones
|
|
Packit |
df99a1 |
while (s[0] == '#')
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
char rgb[3];
|
|
Packit |
df99a1 |
GRect rect;
|
|
Packit |
df99a1 |
s = parse_color_name(s+1, rgb);
|
|
Packit |
df99a1 |
if (s[0] == ':')
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int c[4];
|
|
Packit |
df99a1 |
for (int i=0; i<4; i++)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
char *e = 0;
|
|
Packit |
df99a1 |
c[i] = strtol(s+1, &e, 10);
|
|
Packit |
df99a1 |
if (e <= s || (i>=2 && c[i]<0) || (i<3 && e[0]!=','))
|
|
Packit |
df99a1 |
G_THROW("Invalid coordinates in FGbz chunk specification");
|
|
Packit |
df99a1 |
s = e;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
rect = GRect(c[0],c[1],c[2],c[3]);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
if (rect.isempty())
|
|
Packit |
df99a1 |
fullpage = true;
|
|
Packit |
df99a1 |
g().colorpalette->writall(rgb, 3);
|
|
Packit |
df99a1 |
g().colorzones.touch(zones);
|
|
Packit |
df99a1 |
g().colorzones[zones] = rect;
|
|
Packit |
df99a1 |
zones++;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
if (s[0])
|
|
Packit |
df99a1 |
G_THROW("Syntax error in FGbz chunk specification");
|
|
Packit |
df99a1 |
// add extra black palette entry
|
|
Packit |
df99a1 |
if (! fullpage)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
char rgb[3] = {0,0,0};
|
|
Packit |
df99a1 |
g().colorpalette->writall(rgb, 3);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// -- Main
|
|
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 |
// Print usage when called without enough arguments
|
|
Packit |
df99a1 |
if (argc <= 2)
|
|
Packit |
df99a1 |
usage();
|
|
Packit |
df99a1 |
// Open djvu file
|
|
Packit |
df99a1 |
remove(dargv[1]);
|
|
Packit |
df99a1 |
GP<IFFByteStream> giff =
|
|
Packit |
df99a1 |
IFFByteStream::create(ByteStream::create(GURL::Filename::UTF8(dargv[1]),"wb"));
|
|
Packit |
df99a1 |
IFFByteStream &iff=*giff;
|
|
Packit |
df99a1 |
// Create header
|
|
Packit |
df99a1 |
iff.put_chunk("FORM:DJVU", 1);
|
|
Packit |
df99a1 |
// Check if shared dicts are present
|
|
Packit |
df99a1 |
check_for_shared_dict(dargv);
|
|
Packit |
df99a1 |
// Create information chunk
|
|
Packit |
df99a1 |
create_info_chunk(iff, dargv);
|
|
Packit |
df99a1 |
// Parse all arguments
|
|
Packit |
df99a1 |
for (int i=2; i
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (!dargv[i].cmp("INFO=",5))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (i>2)
|
|
Packit |
df99a1 |
DjVuPrintErrorUTF8("%s","djvumake: 'INFO' chunk should appear first (ignored)\n");
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else if (!dargv[i].cmp("Sjbz=",5))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (flag_contains_stencil)
|
|
Packit |
df99a1 |
DjVuPrintErrorUTF8("%s","djvumake: duplicate stencil chunk\n");
|
|
Packit |
df99a1 |
create_jb2_chunk(iff, "Sjbz", GURL::Filename::UTF8(5+(const char *)dargv[i]));
|
|
Packit |
df99a1 |
flag_contains_stencil = 1;
|
|
Packit |
df99a1 |
if (flag_fg_needs_palette && blit_count >= 0)
|
|
Packit |
df99a1 |
create_fgbz_chunk(iff);
|
|
Packit |
df99a1 |
flag_fg_needs_palette = 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else if (!dargv[i].cmp("Smmr=",5))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
create_mmr_chunk(iff, "Smmr",
|
|
Packit |
df99a1 |
GURL::Filename::UTF8(5+(const char *)dargv[i]));
|
|
Packit |
df99a1 |
if (flag_contains_stencil)
|
|
Packit |
df99a1 |
DjVuPrintErrorUTF8("%s","djvumake: duplicate stencil chunk\n");
|
|
Packit |
df99a1 |
flag_contains_stencil = 1;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else if (!dargv[i].cmp("FGbz=",5))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
const char *c = 5 + (const char*)dargv[i];
|
|
Packit |
df99a1 |
if (flag_contains_fg)
|
|
Packit |
df99a1 |
DjVuPrintErrorUTF8("%s","djvumake: duplicate 'FGxx' chunk\n");
|
|
Packit |
df99a1 |
if (c[0] != '#')
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
create_raw_chunk(iff, "FGbz", GURL::Filename::UTF8(c));
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
parse_color_zones(c);
|
|
Packit |
df99a1 |
if (flag_contains_stencil && blit_count >= 0)
|
|
Packit |
df99a1 |
create_fgbz_chunk(iff);
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
flag_fg_needs_palette = 1;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
flag_contains_fg = 1;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else if (!dargv[i].cmp("FG44=",5))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (flag_contains_fg)
|
|
Packit |
df99a1 |
DjVuPrintErrorUTF8("%s","djvumake: duplicate 'FGxx' chunk\n");
|
|
Packit |
df99a1 |
create_fg44_chunk(iff, "FG44",
|
|
Packit |
df99a1 |
GURL::Filename::UTF8(5+(const char *)dargv[i]));
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else if (!dargv[i].cmp("BG44=",5))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
create_bg44_chunk(iff, "BG44", 5+(const char *)dargv[i]);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else if (!dargv[i].cmp("BGjp=",5) ||
|
|
Packit |
df99a1 |
!dargv[i].cmp("BG2k=",5) )
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (flag_contains_bg)
|
|
Packit |
df99a1 |
DjVuPrintErrorUTF8("%s","djvumake: Duplicate BGxx chunk\n");
|
|
Packit |
df99a1 |
GUTF8String chkid = dargv[i].substr(0,4);
|
|
Packit |
df99a1 |
create_raw_chunk(iff, chkid, GURL::Filename::UTF8(5+(const char *)dargv[i]));
|
|
Packit |
df99a1 |
flag_contains_bg = 1;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else if (!dargv[i].cmp("FGjp=",5) || !dargv[i].cmp("FG2k=",5))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (flag_contains_fg)
|
|
Packit |
df99a1 |
DjVuPrintErrorUTF8("%s","djvumake: duplicate 'FGxx' chunk\n");
|
|
Packit |
df99a1 |
GUTF8String chkid = dargv[i].substr(0,4);
|
|
Packit |
df99a1 |
create_raw_chunk(iff, chkid, GURL::Filename::UTF8(5+(const char *)dargv[i]));
|
|
Packit |
df99a1 |
flag_contains_fg = 1;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else if (!dargv[i].cmp("INCL=",5))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
create_incl_chunk(iff, "INCL", GURL::Filename::UTF8(5+(const char *)dargv[i]).fname());
|
|
Packit |
df99a1 |
flag_contains_incl = 1;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else if (!dargv[i].cmp("PPM=",4))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (flag_contains_bg || flag_contains_fg)
|
|
Packit |
df99a1 |
DjVuPrintErrorUTF8("%s","djvumake: Duplicate 'FGxx' or 'BGxx' chunk\n");
|
|
Packit |
df99a1 |
create_masksub_chunks(iff, GURL::Filename::UTF8(4+(const char *)dargv[i]));
|
|
Packit |
df99a1 |
flag_contains_bg = 1;
|
|
Packit |
df99a1 |
flag_contains_fg = 1;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else if (dargv[i].length() > 4 && dargv[i][4] == '=')
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
GNativeString chkid = dargv[i].substr(0,4);
|
|
Packit |
df99a1 |
if (chkid != "TXTz" && chkid != "TXTa"
|
|
Packit |
df99a1 |
&& chkid != "ANTz" && chkid != "ANTa"
|
|
Packit |
df99a1 |
&& chkid != "Djbz" )
|
|
Packit |
df99a1 |
DjVuPrintErrorUTF8("djvumake: creating chunk of unknown type ``%s''.\n",
|
|
Packit |
df99a1 |
(const char*)chkid);
|
|
Packit |
df99a1 |
create_raw_chunk(iff, chkid, GURL::Filename::UTF8(5+(const char *)dargv[i]));
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
DjVuPrintErrorUTF8("djvumake: illegal argument : ``%s'' (ignored)\n",
|
|
Packit |
df99a1 |
(const char *)dargv[i]);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
// Common cases for missing chunks
|
|
Packit |
df99a1 |
if (flag_contains_stencil)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (flag_contains_bg && ! flag_contains_fg)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
DjVuPrintErrorUTF8("%s","djvumake: generating black FGbz chunk\n");
|
|
Packit |
df99a1 |
g().colorzones.empty();
|
|
Packit |
df99a1 |
g().colorpalette = ByteStream::create();
|
|
Packit |
df99a1 |
char rgb[3] = {0,0,0};
|
|
Packit |
df99a1 |
g().colorpalette->writall(rgb, 3);
|
|
Packit |
df99a1 |
create_fgbz_chunk(iff);
|
|
Packit |
df99a1 |
flag_contains_fg = 1;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
if (flag_contains_fg && !flag_contains_bg)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
DjVuPrintErrorUTF8("%s","djvumake: generating white BG44 chunk\n");
|
|
Packit |
df99a1 |
GPixel bgcolor = GPixel::WHITE;
|
|
Packit |
df99a1 |
GP<GPixmap> inputsub=GPixmap::create((h+11)/12, (w+11)/12, &bgcolor);
|
|
Packit |
df99a1 |
GP<IW44Image> iw = IW44Image::create_encode(*inputsub, 0, IW44Image::CRCBnone);
|
|
Packit |
df99a1 |
IWEncoderParms iwparms;
|
|
Packit |
df99a1 |
iff.put_chunk("BG44");
|
|
Packit |
df99a1 |
iwparms.slices = 97;
|
|
Packit |
df99a1 |
iw->encode_chunk(iff.get_bytestream(), iwparms);
|
|
Packit |
df99a1 |
iff.close_chunk();
|
|
Packit |
df99a1 |
flag_contains_bg = 1;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
// Close
|
|
Packit |
df99a1 |
iff.close_chunk();
|
|
Packit |
df99a1 |
// Sanity checks
|
|
Packit |
df99a1 |
if (flag_contains_stencil)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
// Compound or Bilevel
|
|
Packit |
df99a1 |
if (flag_contains_bg && ! flag_contains_fg)
|
|
Packit |
df99a1 |
DjVuPrintErrorUTF8("%s","djvumake: djvu file contains a BGxx chunk but no FGxx chunk\n");
|
|
Packit |
df99a1 |
if (flag_contains_fg && ! flag_contains_bg)
|
|
Packit |
df99a1 |
DjVuPrintErrorUTF8("%s","djvumake: djvu file contains a FGxx chunk but no BGxx chunk\n");
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else if (flag_contains_bg)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
// Photo DjVu Image
|
|
Packit |
df99a1 |
if (flag_contains_bg!=1)
|
|
Packit |
df99a1 |
DjVuPrintErrorUTF8("%s","djvumake: photo djvu image has subsampled BGxx chunk\n");
|
|
Packit |
df99a1 |
if (flag_fg_needs_palette)
|
|
Packit |
df99a1 |
DjVuPrintErrorUTF8("%s","djvumake: could not generate FGbz chunk, as stencil is not available\n");
|
|
Packit |
df99a1 |
else if (flag_contains_fg)
|
|
Packit |
df99a1 |
DjVuPrintErrorUTF8("%s","djvumake: photo djvu file contains FGxx chunk\n");
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
DjVuPrintErrorUTF8("%s","djvumake: djvu file contains neither Sxxx nor BGxx chunks\n");
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
G_CATCH(ex)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
remove(dargv[1]);
|
|
Packit |
df99a1 |
ex.perror();
|
|
Packit |
df99a1 |
exit(1);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
G_ENDCATCH;
|
|
Packit |
df99a1 |
return 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
////////////////////////////////////////
|
|
Packit |
df99a1 |
// MASKING AND SUBSAMPLING
|
|
Packit |
df99a1 |
////////////////////////////////////////
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// -- Returns a dilated version of a bitmap with the same size
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static GP<GBitmap>
|
|
Packit |
df99a1 |
dilate8(const GBitmap *p_bm)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
const GBitmap& bm = *p_bm;
|
|
Packit |
df99a1 |
GP<GBitmap> p_newbm = GBitmap::create(bm.rows(),bm.columns(),1);
|
|
Packit |
df99a1 |
GBitmap& newbm = *p_newbm;
|
|
Packit |
df99a1 |
int nrows = bm.rows();
|
|
Packit |
df99a1 |
int ncols = bm.columns();
|
|
Packit |
df99a1 |
for(int y=0; y
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
const unsigned char *bmrow = bm[y];
|
|
Packit |
df99a1 |
unsigned char *nbmprow = (y-1>=0) ? newbm[y-1] : 0;
|
|
Packit |
df99a1 |
unsigned char *nbmrow = newbm[y];
|
|
Packit |
df99a1 |
unsigned char *nbmnrow = (y+1
|
|
Packit |
df99a1 |
for(int x=0; x
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if(bmrow[x])
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
// Set all the 8-neighborhood to black
|
|
Packit |
df99a1 |
if (nbmprow)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
nbmprow[x-1]=1;
|
|
Packit |
df99a1 |
nbmprow[x]=1;
|
|
Packit |
df99a1 |
nbmprow[x+1]=1;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
nbmrow[x-1]=1;
|
|
Packit |
df99a1 |
nbmrow[x]=1;
|
|
Packit |
df99a1 |
nbmrow[x+1]=1;
|
|
Packit |
df99a1 |
if (nbmnrow)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
nbmnrow[x-1]=1;
|
|
Packit |
df99a1 |
nbmnrow[x]=1;
|
|
Packit |
df99a1 |
nbmnrow[x+1]=1;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
return p_newbm;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// -- Returns a smaller eroded version of a bitmap
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static GP<GBitmap>
|
|
Packit |
df99a1 |
erode8(const GBitmap *p_bm)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
const GBitmap& bm = *p_bm;
|
|
Packit |
df99a1 |
int newnrows = bm.rows()-2;
|
|
Packit |
df99a1 |
int newncolumns = bm.columns()-2;
|
|
Packit |
df99a1 |
if(newnrows<=0 || newncolumns<=0) // then return an empty GBitmap
|
|
Packit |
df99a1 |
return GBitmap::create();
|
|
Packit |
df99a1 |
GP<GBitmap> p_newbm = GBitmap::create(newnrows,newncolumns);
|
|
Packit |
df99a1 |
GBitmap& newbm = *p_newbm;
|
|
Packit |
df99a1 |
for(int y=0; y
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
for(int x=0; x
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
// Check if there's a white pixel in the 8-neighborhood
|
|
Packit |
df99a1 |
if( !( bm[y ][x] && bm[y ][x+1] && bm[y ][x+2]
|
|
Packit |
df99a1 |
&& bm[y+1][x] && bm[y+1][x+1] && bm[y+1][x+2]
|
|
Packit |
df99a1 |
&& bm[y+2][x] && bm[y+2][x+1] && bm[y+2][x+2]))
|
|
Packit |
df99a1 |
newbm[y][x] = 0; // then set current to white
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
newbm[y][x] = 1; // else set current to black
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
return p_newbm;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// -- Returns a smaller eroded version of a jb2image
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
GP<JB2Image>
|
|
Packit |
df99a1 |
erode8(const JB2Image *im)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int i;
|
|
Packit |
df99a1 |
GP<JB2Image> newim = JB2Image::create();
|
|
Packit |
df99a1 |
newim->set_dimension(im->get_width(),im->get_height());
|
|
Packit |
df99a1 |
for(i=0; i<im->get_shape_count(); i++)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
const JB2Shape &shape = im->get_shape(i);
|
|
Packit |
df99a1 |
JB2Shape newshape;
|
|
Packit |
df99a1 |
newshape.parent = shape.parent;
|
|
Packit |
df99a1 |
if (shape.bits)
|
|
Packit |
df99a1 |
newshape.bits = erode8(shape.bits);
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
newshape.bits = 0;
|
|
Packit |
df99a1 |
newim->add_shape(newshape);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
for(i=0; i<im->get_blit_count(); i++)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
const JB2Blit* blit = im->get_blit(i);
|
|
Packit |
df99a1 |
JB2Blit newblit;
|
|
Packit |
df99a1 |
newblit.bottom = blit->bottom + 1;
|
|
Packit |
df99a1 |
newblit.left = blit->left + 1;
|
|
Packit |
df99a1 |
newblit.shapeno = blit->shapeno;
|
|
Packit |
df99a1 |
newim->add_blit(newblit);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
return newim;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// Subsamples only the pixels of <image> that are not masked (<mask>). This
|
|
Packit |
df99a1 |
// call resizes and fills the resulting <subsampled_image> and
|
|
Packit |
df99a1 |
// <subsampled_mask>. Their dimension is the dimension of the original
|
|
Packit |
df99a1 |
// <image> divided by <gridwidth> and rounded to the superior integer. For
|
|
Packit |
df99a1 |
// each square grid (gridwidth times gridwidth) of the subsampling mesh that
|
|
Packit |
df99a1 |
// contains at least <minpixels> non-masked pixels, their value is averaged to
|
|
Packit |
df99a1 |
// give the value of the corresponding <subsampled_image> pixel, and the
|
|
Packit |
df99a1 |
// <subsampled_mask> is cleared at this position. If <inverted_mask> is true,
|
|
Packit |
df99a1 |
// then pixels are considered to be masked when mask==0
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static void
|
|
Packit |
df99a1 |
maskedSubsample(const GPixmap* img,
|
|
Packit |
df99a1 |
const GBitmap *p_mask,
|
|
Packit |
df99a1 |
GPixmap& subsampled_image,
|
|
Packit |
df99a1 |
GBitmap& subsampled_mask,
|
|
Packit |
df99a1 |
int gridwidth, int inverted_mask,
|
|
Packit |
df99a1 |
int minpixels=1
|
|
Packit |
df99a1 |
)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
const GPixmap& image= *img;
|
|
Packit |
df99a1 |
const GBitmap& mask = *p_mask;
|
|
Packit |
df99a1 |
int imageheight = image.rows();
|
|
Packit |
df99a1 |
int imagewidth = image.columns();
|
|
Packit |
df99a1 |
// compute the size of the resulting subsampled image
|
|
Packit |
df99a1 |
int subheight = imageheight/gridwidth;
|
|
Packit |
df99a1 |
if(imageheight%gridwidth)
|
|
Packit |
df99a1 |
subheight++;
|
|
Packit |
df99a1 |
int subwidth = imagewidth/gridwidth;
|
|
Packit |
df99a1 |
if(imagewidth%gridwidth)
|
|
Packit |
df99a1 |
subwidth++;
|
|
Packit |
df99a1 |
// set the sizes unless in incremental mode
|
|
Packit |
df99a1 |
subsampled_image.init(subheight, subwidth);
|
|
Packit |
df99a1 |
subsampled_mask.init(subheight, subwidth);
|
|
Packit |
df99a1 |
// go subsampling
|
|
Packit |
df99a1 |
int row, col; // row and col in the subsampled image
|
|
Packit |
df99a1 |
int posx, posxend, posy, posyend; // corresponding square in the original image
|
|
Packit |
df99a1 |
for(row=0, posy=0; row
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
GPixel* subsampled_image_row = subsampled_image[row]; // row row of subsampled image
|
|
Packit |
df99a1 |
unsigned char* subsampled_mask_row = subsampled_mask[row]; // row row of subsampled mask
|
|
Packit |
df99a1 |
posyend = posy+gridwidth;
|
|
Packit |
df99a1 |
if(posyend>imageheight)
|
|
Packit |
df99a1 |
posyend = imageheight;
|
|
Packit |
df99a1 |
for(col=0, posx=0; col
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
posxend = posx+gridwidth;
|
|
Packit |
df99a1 |
if(posxend>imagewidth)
|
|
Packit |
df99a1 |
posxend = imagewidth;
|
|
Packit |
df99a1 |
int count = 0;
|
|
Packit |
df99a1 |
int r = 0;
|
|
Packit |
df99a1 |
int g = 0;
|
|
Packit |
df99a1 |
int b = 0;
|
|
Packit |
df99a1 |
for(int y=posy; y
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
const unsigned char* mask_y = mask[y]; // Row y of the mask
|
|
Packit |
df99a1 |
for(int x=posx; x
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
unsigned char masked = (inverted_mask ? !mask_y[x] :mask_y[x]);
|
|
Packit |
df99a1 |
if(!masked)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
GPixel p = image[y][x];
|
|
Packit |
df99a1 |
r += p.r;
|
|
Packit |
df99a1 |
g += p.g;
|
|
Packit |
df99a1 |
b += p.b;
|
|
Packit |
df99a1 |
count ++;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
/* minpixels pixels are enough to give the color */
|
|
Packit |
df99a1 |
/* so set it, and do not mask this point */
|
|
Packit |
df99a1 |
if(count >= minpixels)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
GPixel p;
|
|
Packit |
df99a1 |
p.r = r/count;
|
|
Packit |
df99a1 |
p.g = g/count;
|
|
Packit |
df99a1 |
p.b = b/count;
|
|
Packit |
df99a1 |
subsampled_image_row[col] = p;
|
|
Packit |
df99a1 |
subsampled_mask_row[col] = 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else /* make it bright red and masked */
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
subsampled_image_row[col] = GPixel::RED;
|
|
Packit |
df99a1 |
subsampled_mask_row[col] = 1;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// -- Computes foreground image and mask
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
processForeground(const GPixmap* image, const JB2Image *mask,
|
|
Packit |
df99a1 |
GPixmap& subsampled_image, GBitmap& subsampled_mask)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
GP<JB2Image> eroded_mask = erode8(mask);
|
|
Packit |
df99a1 |
maskedSubsample(image, eroded_mask->get_bitmap(),
|
|
Packit |
df99a1 |
subsampled_image, subsampled_mask,
|
|
Packit |
df99a1 |
6, 1); // foreground subsample is 6 (300dpi->50dpi)
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// -- Computes background image and mask
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
processBackground(const GPixmap* image, const JB2Image *mask,
|
|
Packit |
df99a1 |
GPixmap& subsampled_image, GBitmap& subsampled_mask)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
GP<GBitmap> b = mask->get_bitmap();
|
|
Packit |
df99a1 |
b = dilate8(b);
|
|
Packit |
df99a1 |
b = dilate8(b);
|
|
Packit |
df99a1 |
maskedSubsample(image, b, subsampled_image, subsampled_mask, 3, 0);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|