From dff6b9fdfeb78fe21a66aa459ddc1d5f7e362dfa Mon Sep 17 00:00:00 2001 From: giraffedata Date: Sun, 27 Mar 2016 01:46:26 +0000 Subject: Promote Advanced (10.73) to Stable git-svn-id: http://svn.code.sf.net/p/netpbm/code/stable@2692 9d0c8265-081b-0410-96cb-a4ca84ce46f8 --- converter/bmp.h | 56 +- converter/other/Makefile | 204 +- converter/other/anytopnm | 7 +- converter/other/avstopam.c | 103 + converter/other/bmepsoe.c | 560 --- converter/other/bmepsoe.h | 79 - converter/other/bmptopnm.c | 374 +- converter/other/cameratopam/Makefile | 22 +- converter/other/cameratopam/camera.c | 375 +- converter/other/cameratopam/camera.h | 95 +- converter/other/cameratopam/cameratopam.c | 1237 ++--- converter/other/cameratopam/cameratopam.h | 6 + converter/other/cameratopam/canon.c | 6 +- converter/other/cameratopam/canon.h | 11 +- converter/other/cameratopam/dng.c | 151 +- converter/other/cameratopam/dng.h | 4 +- converter/other/cameratopam/foveon.c | 37 +- converter/other/cameratopam/foveon.h | 13 +- converter/other/cameratopam/global_variables.h | 1 - converter/other/cameratopam/identify.c | 2256 ++++----- converter/other/cameratopam/identify.h | 4 +- converter/other/cameratopam/ljpeg.c | 238 +- converter/other/cameratopam/ljpeg.h | 14 +- converter/other/exif.c | 1216 ++--- converter/other/exif.h | 24 +- converter/other/fiasco/Makefile | 16 +- converter/other/fiasco/binerror.c | 8 - converter/other/fiasco/codec/approx.c | 4 +- converter/other/fiasco/codec/coder.c | 161 +- converter/other/fiasco/codec/control.c | 6 +- converter/other/fiasco/codec/decoder.c | 1809 ++++---- converter/other/fiasco/codec/dfiasco.c | 8 +- converter/other/fiasco/codec/domain-pool.c | 16 +- converter/other/fiasco/codec/ip.c | 4 +- converter/other/fiasco/codec/motion.c | 12 +- converter/other/fiasco/codec/mwfa.c | 17 +- converter/other/fiasco/codec/options.c | 7 +- converter/other/fiasco/codec/prediction.c | 6 +- converter/other/fiasco/codec/subdivide.c | 56 +- converter/other/fiasco/codec/tiling.c | 80 +- converter/other/fiasco/codec/wfa.h | 4 +- converter/other/fiasco/codec/wfalib.c | 11 +- converter/other/fiasco/config.h | 3 - converter/other/fiasco/display.c | 15 +- converter/other/fiasco/fiascotopnm.c | 10 +- converter/other/fiasco/getopt.c | 10 +- converter/other/fiasco/input/basis.c | 2 + converter/other/fiasco/input/read.c | 8 +- converter/other/fiasco/input/weights.c | 204 +- converter/other/fiasco/lib/arith.c | 4 +- converter/other/fiasco/lib/bit-io.c | 6 +- converter/other/fiasco/lib/dither.c | 32 +- converter/other/fiasco/lib/error.c | 39 +- converter/other/fiasco/lib/image.c | 6 +- converter/other/fiasco/lib/list.c | 6 +- converter/other/fiasco/lib/macros.h | 11 - converter/other/fiasco/lib/misc.c | 33 +- converter/other/fiasco/lib/misc.h | 4 - converter/other/fiasco/output/matrices.c | 8 +- converter/other/fiasco/output/weights.c | 293 +- converter/other/fiasco/params.c | 151 +- converter/other/fiasco/pnmtofiasco.c | 418 +- converter/other/fitstopnm.c | 203 +- converter/other/giftopnm.c | 1610 ++++--- converter/other/hdifftopam.c | 4 +- converter/other/infotopam.c | 70 +- converter/other/ipdb.c | 384 ++ converter/other/ipdb.h | 243 + converter/other/jbig/ANNOUNCE | 243 - converter/other/jbig/Makefile | 39 +- converter/other/jbig/README | 20 + converter/other/jbig/README.Netpbm | 12 - converter/other/jbig/jbig.c | 2905 ------------ converter/other/jbig/jbig.doc | 721 --- converter/other/jbig/jbig.h | 267 -- converter/other/jbig/jbig_tab.c | 428 -- converter/other/jbig/jbigtopnm.c | 2 +- converter/other/jbig/libjbig/ANNOUNCE | 172 + converter/other/jbig/libjbig/COPYING | 339 ++ converter/other/jbig/libjbig/Makefile | 24 + converter/other/jbig/libjbig/include/jbig.h | 233 + converter/other/jbig/libjbig/include/jbig_ar.h | 53 + converter/other/jbig/libjbig/jbig.c | 3285 +++++++++++++ converter/other/jbig/libjbig/jbig.txt | 810 ++++ converter/other/jbig/libjbig/jbig_ar.c | 417 ++ converter/other/jbig/pnmtojbig.c | 2 +- converter/other/jpeg2000/Makefile | 26 +- converter/other/jpeg2000/jpeg2ktopam.c | 68 +- converter/other/jpeg2000/libjasper/README | 4 +- .../other/jpeg2000/libjasper/base/jas_image.c | 8 +- converter/other/jpeg2000/libjasper/base/jas_seq.c | 3 +- .../other/jpeg2000/libjasper/base/jas_stream.c | 9 +- converter/other/jpeg2000/libjasper/common.mk | 8 +- .../jpeg2000/libjasper/include/jasper/jas_image.h | 40 +- .../jpeg2000/libjasper/include/jasper/jas_types.h | 2 +- .../libjasper/include/jasper/jas_types.h.orig | 228 - converter/other/jpeg2000/libjasper/jp2/jp2_cod.c | 1055 ++--- converter/other/jpeg2000/libjasper/jp2/jp2_dec.c | 8 +- converter/other/jpeg2000/libjasper/jpc/jpc_bs.c | 4 - converter/other/jpeg2000/libjasper/jpc/jpc_bs.h | 2 +- converter/other/jpeg2000/libjasper/jpc/jpc_cs.c | 2010 ++++---- converter/other/jpeg2000/libjasper/jpc/jpc_cs.h | 2 +- converter/other/jpeg2000/libjasper/jpc/jpc_dec.c | 3524 +++++++------- converter/other/jpeg2000/libjasper/jpc/jpc_dec.h | 2 +- converter/other/jpeg2000/libjasper/jpc/jpc_enc.c | 4810 ++++++++++---------- converter/other/jpeg2000/libjasper/jpc/jpc_math.h | 2 +- converter/other/jpeg2000/libjasper/jpc/jpc_mqcod.h | 2 +- converter/other/jpeg2000/libjasper/jpc/jpc_mqenc.c | 392 +- converter/other/jpeg2000/libjasper/jpc/jpc_qmfb.c | 8 +- converter/other/jpeg2000/libjasper/jpc/jpc_t2cod.h | 4 +- converter/other/jpeg2000/pamtojpeg2k.c | 143 +- converter/other/jpegtopnm.c | 24 +- converter/other/pamrgbatopng.c | 150 - converter/other/pamtoavs.c | 150 + converter/other/pamtodjvurle.c | 4 +- converter/other/pamtofits.c | 8 +- converter/other/pamtogif.c | 14 +- converter/other/pamtohdiff.c | 4 +- converter/other/pamtohtmltbl.c | 4 +- converter/other/pamtompfont.c | 6 +- converter/other/pamtooctaveimg.c | 4 +- converter/other/pamtopam.c | 2 +- converter/other/pamtopdbimg.c | 810 ++++ converter/other/pamtopfm.c | 8 +- converter/other/pamtopng.c | 768 ++++ converter/other/pamtopnm.c | 36 +- converter/other/pamtosrf.c | 217 + converter/other/pamtosvg/Makefile | 32 +- converter/other/pamtosvg/bitmap.c | 4 +- converter/other/pamtosvg/bitmap.h | 2 +- converter/other/pamtosvg/image-proc.c | 4 +- converter/other/pamtosvg/message.h | 16 - converter/other/pamtosvg/pamtosvg.c | 14 +- converter/other/pamtosvg/pxl-outline.c | 1 - converter/other/pamtosvg/thin-image.c | 6 +- converter/other/pamtosvg/vector.c | 1 + converter/other/pamtotga.c | 6 +- converter/other/pamtotiff.c | 593 ++- converter/other/pamtouil.c | 8 +- converter/other/pamtowinicon.c | 1177 +++++ converter/other/pamtoxvmini.c | 4 +- converter/other/pdbimgtopam.c | 774 ++++ converter/other/pfmtopam.c | 4 +- converter/other/pgmtopbm.c | 6 +- converter/other/pgmtoppm.c | 5 +- converter/other/pngtopam.c | 1238 +++-- converter/other/pngtopnm.c | 1249 ----- converter/other/pngtxt.c | 468 +- converter/other/pngtxt.h | 14 +- converter/other/pngx.c | 733 +++ converter/other/pngx.h | 268 ++ converter/other/pnmtojpeg.c | 13 +- converter/other/pnmtopalm/Makefile | 16 +- converter/other/pnmtopalm/gen_palm_colormap.c | 4 +- converter/other/pnmtopalm/palm.h | 8 +- converter/other/pnmtopalm/palmcolormap.c | 8 +- converter/other/pnmtopalm/palmtopnm.c | 4 +- converter/other/pnmtopalm/pnmtopalm.c | 13 +- converter/other/pnmtopclxl.c | 1075 ++--- converter/other/pnmtopng.README | 101 - converter/other/pnmtopng.c | 1402 +++--- converter/other/pnmtops.c | 1711 +++++-- converter/other/pnmtorast.c | 501 +- converter/other/pnmtosgi.c | 513 ++- converter/other/pnmtoxwd.c | 24 +- converter/other/ppmtopgm.c | 4 +- converter/other/pstopnm.c | 874 ++-- converter/other/rast.c | 83 +- converter/other/rast.h | 15 +- converter/other/rasttopnm.c | 703 ++- converter/other/rletopnm.c | 154 +- converter/other/sgi.h | 8 +- converter/other/sgitopnm.c | 747 +-- converter/other/srf.c | 653 +++ converter/other/srf.h | 170 + converter/other/srftopam.c | 226 + converter/other/sunicontopnm.c | 172 + converter/other/svgtopam.c | 18 +- converter/other/tiff.c | 6 - converter/other/tifftopnm.c | 273 +- converter/other/winicon.h | 82 + converter/other/winicontopam.c | 1286 ++++++ converter/other/xwdtopnm.c | 6 +- converter/other/yuy2topam.c | 266 ++ converter/pbm/Makefile | 17 +- converter/pbm/atktopbm.c | 425 +- converter/pbm/brushtopbm.c | 174 +- converter/pbm/cistopbm.c | 180 + converter/pbm/cmuwm.h | 17 - converter/pbm/cmuwmtopbm.c | 21 +- converter/pbm/escp2topbm.c | 384 +- converter/pbm/g3topbm.c | 93 +- converter/pbm/icontopbm.c | 159 - converter/pbm/macp.h | 18 +- converter/pbm/macptopbm.c | 426 +- converter/pbm/pbmto10x.c | 117 +- converter/pbm/pbmtoascii.c | 324 +- converter/pbm/pbmtoatk.c | 69 +- converter/pbm/pbmtocis.c | 170 + converter/pbm/pbmtocmuwm.c | 8 +- converter/pbm/pbmtoepsi.c | 128 +- converter/pbm/pbmtoepson.c | 61 +- converter/pbm/pbmtoescp2.c | 260 +- converter/pbm/pbmtog3.c | 8 +- converter/pbm/pbmtog3.test | 23 - converter/pbm/pbmtogem.c | 252 +- converter/pbm/pbmtoibm23xx.c | 2 +- converter/pbm/pbmtoicon.c | 186 - converter/pbm/pbmtolj.c | 6 +- converter/pbm/pbmtomacp.c | 655 +-- converter/pbm/pbmtomatrixorbital.c | 35 +- converter/pbm/pbmtomgr.c | 6 +- converter/pbm/pbmtonokia.c | 17 +- converter/pbm/pbmtopi3.c | 164 +- converter/pbm/pbmtopk.c | 30 +- converter/pbm/pbmtoppa/Makefile | 17 +- converter/pbm/pbmtopsg3.c | 4 +- converter/pbm/pbmtoptx.c | 135 +- converter/pbm/pbmtosunicon.c | 165 + converter/pbm/pbmtoxbm.c | 65 +- converter/pbm/pbmtoybm.c | 143 +- converter/pbm/pbmtozinc.c | 241 +- converter/pbm/pi3topbm.c | 224 +- converter/pbm/thinkjettopbm.l | 15 +- converter/pbm/xbmtopbm.c | 10 +- converter/pbm/ybmtopbm.c | 161 +- converter/pgm/Makefile | 4 +- converter/pgm/asciitopgm.c | 272 +- converter/pgm/fstopgm.c | 235 +- converter/pgm/pgmtolispm.c | 224 +- converter/pgm/pgmtosbig.c | 130 + converter/pgm/pgmtost4.c | 104 + converter/pgm/rawtopgm.c | 100 +- converter/pgm/sbigtopgm.c | 465 +- converter/pgm/st4topgm.c | 260 ++ converter/ppm/411toppm.c | 219 +- converter/ppm/Makefile | 7 +- converter/ppm/eyuvtoppm.c | 291 +- converter/ppm/hpcdtoppm/pcdovtoppm | 2 +- converter/ppm/ilbm.h | 6 +- converter/ppm/ilbmtoppm.c | 558 ++- converter/ppm/pc1toppm.c | 2 +- converter/ppm/pcxtoppm.c | 16 +- converter/ppm/picttoppm.c | 671 +-- converter/ppm/ppmtoacad.c | 5 +- converter/ppm/ppmtoapplevol.c | 95 + converter/ppm/ppmtoarbtxt.c | 1530 +++++-- converter/ppm/ppmtoascii.c | 236 + converter/ppm/ppmtobmp.c | 89 +- converter/ppm/ppmtogif.c | 50 +- converter/ppm/ppmtoicr.c | 532 +-- converter/ppm/ppmtoilbm.c | 2552 +++++------ converter/ppm/ppmtompeg/BUGS | 2 +- converter/ppm/ppmtompeg/CHANGES | 2 +- converter/ppm/ppmtompeg/Makefile | 69 +- converter/ppm/ppmtompeg/bframe.c | 2 +- converter/ppm/ppmtompeg/bitio.c | 4 +- converter/ppm/ppmtompeg/bsearch.c | 3 +- converter/ppm/ppmtompeg/combine.c | 10 +- converter/ppm/ppmtompeg/docs/template.param | 2 +- converter/ppm/ppmtompeg/examples/template.param | 2 +- converter/ppm/ppmtompeg/frame.c | 2 +- converter/ppm/ppmtompeg/gethostname.c | 1 + converter/ppm/ppmtompeg/gethostname_win32.c | 2 +- converter/ppm/ppmtompeg/headers/all.h | 3 +- converter/ppm/ppmtompeg/headers/ansi.h | 76 - converter/ppm/ppmtompeg/headers/bitio.h | 1 - converter/ppm/ppmtompeg/headers/dct.h | 8 +- converter/ppm/ppmtompeg/headers/frame.h | 21 +- converter/ppm/ppmtompeg/headers/frames.h | 2 - converter/ppm/ppmtompeg/headers/frametype.h | 2 +- converter/ppm/ppmtompeg/headers/general.h | 10 - converter/ppm/ppmtompeg/headers/huff.h | 5 +- converter/ppm/ppmtompeg/headers/jpeg.h | 4 +- converter/ppm/ppmtompeg/headers/mheaders.h | 23 +- converter/ppm/ppmtompeg/headers/motion_search.h | 3 +- converter/ppm/ppmtompeg/headers/mpeg.h | 5 +- converter/ppm/ppmtompeg/headers/mproto.h | 47 +- converter/ppm/ppmtompeg/headers/mtypes.h | 15 +- converter/ppm/ppmtompeg/headers/opts.h | 15 +- converter/ppm/ppmtompeg/headers/parallel.h | 1 - converter/ppm/ppmtompeg/headers/param.h | 18 +- converter/ppm/ppmtompeg/headers/prototypes.h | 35 +- converter/ppm/ppmtompeg/headers/rate.h | 20 +- converter/ppm/ppmtompeg/headers/specifics.h | 9 +- converter/ppm/ppmtompeg/huff.c | 3 +- converter/ppm/ppmtompeg/input.c | 14 +- converter/ppm/ppmtompeg/jpeg.c | 24 +- converter/ppm/ppmtompeg/jrevdct.c | 9 +- converter/ppm/ppmtompeg/mfwddct.c | 180 +- converter/ppm/ppmtompeg/mpeg.c | 25 +- converter/ppm/ppmtompeg/opts.c | 6 +- converter/ppm/ppmtompeg/parallel.c | 86 +- converter/ppm/ppmtompeg/param.c | 67 +- converter/ppm/ppmtompeg/ppmtompeg.c | 28 +- converter/ppm/ppmtompeg/psearch.c | 2 +- converter/ppm/ppmtompeg/psocket.c | 44 +- converter/ppm/ppmtompeg/rate.c | 20 +- converter/ppm/ppmtompeg/readframe.c | 83 +- converter/ppm/ppmtompeg/rgbtoycc.c | 6 +- converter/ppm/ppmtompeg/specifics.c | 24 +- converter/ppm/ppmtopcx.c | 20 +- converter/ppm/ppmtopict.c | 860 ++-- converter/ppm/ppmtopjxl.c | 190 +- converter/ppm/ppmtorgb3.c | 8 +- converter/ppm/ppmtospu.c | 593 +++ converter/ppm/ppmtoterm.c | 238 +- converter/ppm/ppmtowinicon.c | 20 +- converter/ppm/ppmtoxpm.c | 20 +- converter/ppm/ppmtoyuv.c | 141 +- converter/ppm/ppmtoyuvsplit.c | 12 +- converter/ppm/sldtoppm.c | 137 +- converter/ppm/sputoppm.c | 135 +- converter/ppm/tgatoppm.c | 2 +- converter/ppm/winicontoppm.c | 822 ++-- converter/ppm/xim.h | 2 +- converter/ppm/ximtoppm.c | 4 +- converter/ppm/xpmtoppm.c | 1149 +++-- converter/ppm/yuvsplittoppm.c | 16 +- converter/ppm/yuvtoppm.c | 255 +- 320 files changed, 44488 insertions(+), 30857 deletions(-) create mode 100644 converter/other/avstopam.c delete mode 100644 converter/other/bmepsoe.c delete mode 100644 converter/other/bmepsoe.h create mode 100644 converter/other/cameratopam/cameratopam.h create mode 100644 converter/other/ipdb.c create mode 100644 converter/other/ipdb.h delete mode 100644 converter/other/jbig/ANNOUNCE create mode 100644 converter/other/jbig/README delete mode 100644 converter/other/jbig/README.Netpbm delete mode 100644 converter/other/jbig/jbig.c delete mode 100644 converter/other/jbig/jbig.doc delete mode 100644 converter/other/jbig/jbig.h delete mode 100644 converter/other/jbig/jbig_tab.c create mode 100644 converter/other/jbig/libjbig/ANNOUNCE create mode 100644 converter/other/jbig/libjbig/COPYING create mode 100644 converter/other/jbig/libjbig/Makefile create mode 100644 converter/other/jbig/libjbig/include/jbig.h create mode 100644 converter/other/jbig/libjbig/include/jbig_ar.h create mode 100644 converter/other/jbig/libjbig/jbig.c create mode 100644 converter/other/jbig/libjbig/jbig.txt create mode 100644 converter/other/jbig/libjbig/jbig_ar.c delete mode 100644 converter/other/jpeg2000/libjasper/include/jasper/jas_types.h.orig delete mode 100644 converter/other/pamrgbatopng.c create mode 100644 converter/other/pamtoavs.c create mode 100644 converter/other/pamtopdbimg.c create mode 100644 converter/other/pamtopng.c create mode 100644 converter/other/pamtosrf.c create mode 100644 converter/other/pamtowinicon.c create mode 100644 converter/other/pdbimgtopam.c delete mode 100644 converter/other/pngtopnm.c create mode 100644 converter/other/pngx.c create mode 100644 converter/other/pngx.h delete mode 100644 converter/other/pnmtopng.README create mode 100644 converter/other/srf.c create mode 100644 converter/other/srf.h create mode 100644 converter/other/srftopam.c create mode 100644 converter/other/sunicontopnm.c create mode 100644 converter/other/winicon.h create mode 100644 converter/other/winicontopam.c create mode 100644 converter/other/yuy2topam.c create mode 100644 converter/pbm/cistopbm.c delete mode 100644 converter/pbm/cmuwm.h delete mode 100644 converter/pbm/icontopbm.c create mode 100644 converter/pbm/pbmtocis.c delete mode 100644 converter/pbm/pbmtog3.test delete mode 100644 converter/pbm/pbmtoicon.c create mode 100644 converter/pbm/pbmtosunicon.c create mode 100644 converter/pgm/pgmtosbig.c create mode 100644 converter/pgm/pgmtost4.c create mode 100644 converter/pgm/st4topgm.c create mode 100644 converter/ppm/ppmtoapplevol.c create mode 100644 converter/ppm/ppmtoascii.c delete mode 100644 converter/ppm/ppmtompeg/headers/ansi.h create mode 100644 converter/ppm/ppmtospu.c (limited to 'converter') diff --git a/converter/bmp.h b/converter/bmp.h index 8b2aa302..524bbf7e 100644 --- a/converter/bmp.h +++ b/converter/bmp.h @@ -88,12 +88,30 @@ enum bmpClass {C_WIN=1, C_OS2=2}; static char const er_internal[] = "%s: internal error!"; /* Values of the "compression" field of the BMP info header */ -#define COMP_RGB 0 -#define COMP_RLE8 1 -#define COMP_RLE4 2 -#define COMP_BITFIELDS 3 -#define COMP_JPEG 4 -#define COMP_PNG 5 +typedef enum BMPCompType { + BMPCOMP_RGB = 0, + BMPCOMP_RLE8 = 1, + BMPCOMP_RLE4 = 2, + BMPCOMP_BITFIELDS = 3, + BMPCOMP_JPEG = 4, + BMPCOMP_PNG = 5 +} BMPCompType; + +static __inline__ const char * +BMPCompTypeName(BMPCompType const compression) { + + switch (compression) { + case BMPCOMP_RGB: return "none (RBG)"; + case BMPCOMP_RLE4: return "4 bit run-length coding"; + case BMPCOMP_RLE8: return "8 bit run-length coding"; + case BMPCOMP_BITFIELDS: return "none (bitfields)"; + case BMPCOMP_JPEG: return "JPEG"; + case BMPCOMP_PNG: return "PNG"; + } + return 0; /* Default compiler warning */ +} + + static __inline__ unsigned int BMPlenfileheader(enum bmpClass const class) { @@ -127,7 +145,13 @@ static __inline__ unsigned int BMPlencolormap(enum bmpClass const class, unsigned int const bitcount, unsigned int const cmapsize) { +/*---------------------------------------------------------------------------- + The number of bytes of the BMP stream occupied by the colormap in a + BMP of class 'class' with 'bitcount' bits per pixel and 'cmapsize' + entries in the palette. + 'cmapsize' == 0 means there is no palette. +-----------------------------------------------------------------------------*/ unsigned int lenrgb; unsigned int lencolormap; @@ -214,21 +238,21 @@ BMPoffbits(enum bmpClass const class, static __inline__ unsigned int -BMPlenfileGen(enum bmpClass const class, - unsigned int const bitcount, - unsigned int const cmapsize, - unsigned int const x, - unsigned int const y, - unsigned int const imageSize, - unsigned long int const compression) { +BMPlenfileGen(enum bmpClass const class, + unsigned int const bitcount, + unsigned int const cmapsize, + unsigned int const x, + unsigned int const y, + unsigned int const imageSize, + BMPCompType const compression) { /*---------------------------------------------------------------------------- Return the size of the BMP file in bytes. -----------------------------------------------------------------------------*/ unsigned int retval; switch (compression) { - case COMP_RGB: - case COMP_BITFIELDS: + case BMPCOMP_RGB: + case BMPCOMP_BITFIELDS: retval = BMPoffbits(class, bitcount, cmapsize) + BMPlenbits(class, bitcount, x, y); @@ -250,7 +274,7 @@ BMPlenfile(enum bmpClass const class, /*---------------------------------------------------------------------------- return the size of the BMP file in bytes; no compression -----------------------------------------------------------------------------*/ - return BMPlenfileGen(class, bitcount, cmapsize, x, y, 0, COMP_RGB); + return BMPlenfileGen(class, bitcount, cmapsize, x, y, 0, BMPCOMP_RGB); } #endif diff --git a/converter/other/Makefile b/converter/other/Makefile index df084ceb..f51a780b 100644 --- a/converter/other/Makefile +++ b/converter/other/Makefile @@ -7,12 +7,20 @@ VPATH=.:$(SRCDIR)/$(SUBDIR) include $(BUILDDIR)/config.mk -ifeq ($(shell xml2-config --version),) - XML2_LIBS=NONE - XML2_CFLAGS=NONE +TEST_PKGCONFIG_LIBXML2 = if pkg-config libxml-2.0; then echo exists; fi + +ifneq ($(shell $(TEST_PKGCONFIG_LIBXML2)),) + # pkg-config libxml2 works on this system + XML2_LIBS = $(shell pkg-config libxml-2.0 --libs) + XML2_CFLAGS = $(shell pkg-config libxml-2.0 --cflags) else - XML2_LIBS=$(shell xml2-config --libs) - XML2_CFLAGS=$(shell xml2-config --cflags) + ifeq ($(shell xml2-config --version),) + XML2_LIBS=NONE + XML2_CFLAGS=NONE + else + XML2_LIBS=$(shell xml2-config --libs) + XML2_CFLAGS=$(shell xml2-config --cflags) + endif endif SUBDIRS = jbig pnmtopalm jpeg2000 cameratopam pamtosvg @@ -26,19 +34,29 @@ ifneq ($(TIFFLIB),NONE) endif endif -ifeq ($(shell libpng$(PNGVER)-config --version),) - ifneq ($(PNGLIB),NONE) +TEST_PKGCONFIG_LIBPNG = if pkg-config libpng$(PNGVER); then echo exists; fi + +ifneq ($(shell $(TEST_PKGCONFIG_LIBPNG)),) + # pkg-config libpng works on this system + HAVE_PNGLIB = Y + EXTERN_INCLUDES += $(shell pkg-config libpng$(PNGVER) --cflags) +else + ifneq ($(shell libpng$(PNGVER)-config --version),) + # No pkg-config, but we have libpng-config on this system HAVE_PNGLIB = Y - ifneq ($(PNGHDR_DIR)x,x) - EXTERN_INCLUDES += -I$(PNGHDR_DIR) - endif - ifneq ($(ZHDR_DIR)x,x) - EXTERN_INCLUDES += -I$(ZHDR_DIR) + EXTERN_INCLUDES += $(shell libpng$(PNGVER)-config --cflags) + else + # System can't tell us where libpng is; use stuff from config.mk + ifneq ($(PNGLIB),NONE) + HAVE_PNGLIB = Y + ifneq ($(PNGHDR_DIR)x,x) + EXTERN_INCLUDES += -I$(PNGHDR_DIR) + endif + ifneq ($(ZHDR_DIR)x,x) + EXTERN_INCLUDES += -I$(ZHDR_DIR) + endif endif endif -else - HAVE_PNGLIB = Y - EXTERN_INCLUDES += $(shell libpng$(PNGVER)-config --cflags) endif ifneq ($(JPEGLIB),NONE) @@ -77,49 +95,66 @@ ifeq ($(TIFFLIB_NEEDS_Z),Y) endif endif -PORTBINARIES = bmptopnm fitstopnm \ +# TIFFLIB_USERLIBS is for the user to set manually, on the make command line +# or manually added to config.mk. There are arcane situations where the TIFF +# library refers to additional libraries not handled above. + +TIFFLIB_EXTRALIBS += $(TIFFLIB_USERLIBS) + +# Pnmtops's "flate" compression function requires libz. But if we don't +# have libz, we still build Pnmtops; we just omit the flate compression +# capability. +ifeq ($(ZLIB),NONE) + PNMTOPS_ZLIB_OPT = + PNMTOPS_NOFLATE_OPT = -DNOFLATE +else + PNMTOPS_ZLIB_OPT = $(ZLIB) + PNMTOPS_NOFLATE_OPT = +endif + + +PORTBINARIES = avstopam bmptopnm fitstopnm \ gemtopnm giftopnm hdifftopam infotopam \ - pamtodjvurle pamtofits pamtogif \ + pamtoavs pamtodjvurle pamtofits pamtogif \ pamtohdiff pamtohtmltbl pamtompfont pamtooctaveimg \ - pamtopam pamtopfm pamtopnm pamtouil \ - pamtoxvmini \ - pbmtopgm pfmtopam \ + pamtopam pamtopdbimg pamtopfm pamtopnm pamtosrf pamtouil \ + pamtowinicon pamtoxvmini \ + pbmtopgm pdbimgtopam pfmtopam \ pgmtopbm pgmtoppm ppmtopgm pnmtoddif \ - pnmtopclxl \ + pnmtopclxl pnmtorast \ pnmtosgi pnmtosir pamtotga pnmtoxwd \ - rlatopam sgitopnm sirtopnm xwdtopnm zeisstopnm + rasttopnm rlatopam sgitopnm sirtopnm srftopam sunicontopnm \ + winicontopam xwdtopnm yuy2topam zeisstopnm ifneq ($(DONT_HAVE_PROCESS_MGMT),Y) - PORTBINARIES += pstopnm + PORTBINARIES += pstopnm pnmtops endif -BINARIES = $(PORTBINARIES) pnmtorast rasttopnm - ifeq ($(HAVE_PNGLIB),Y) - BINARIES += pnmtopng pngtopnm pngtopam pamrgbatopng + PORTBINARIES += pamtopng pnmtopng pngtopam endif ifneq ($(JPEGLIB),NONE) - BINARIES += jpegtopnm pnmtojpeg + PORTBINARIES += jpegtopnm pnmtojpeg endif ifneq ($(TIFF_PREREQ_MISSING),Y) - BINARIES += tifftopnm pamtotiff pnmtotiffcmyk + PORTBINARIES += tifftopnm pamtotiff pnmtotiffcmyk endif ifneq ($(URTLIB),NONE) - BINARIES += rletopnm pnmtorle -endif -ifneq ($(ZLIB),NONE) - BINARIES += pnmtops + PORTBINARIES += rletopnm pnmtorle endif ifneq ($(XML2_LIBS),NONE) - BINARIES += svgtopam + PORTBINARIES += svgtopam endif +BINARIES = $(PORTBINARIES) + MERGEBINARIES = $(BINARIES) -EXTRA_OBJECTS = exif.o rast.o bmepsoe.o +EXTRA_OBJECTS = exif.o rast.o ipdb.o srf.o ifeq ($(HAVE_PNGLIB),Y) EXTRA_OBJECTS += pngtxt.o + EXTRA_OBJECTS += pngx.o endif ifneq ($(JPEGLIB),NONE) EXTRA_OBJECTS += jpegdatasource.o @@ -131,6 +166,7 @@ endif OBJECTS = $(BINARIES:%=%.o) $(EXTRA_OBJECTS) MERGE_OBJECTS = $(MERGEBINARIES:%=%.o2) $(EXTRA_OBJECTS) +pnmtops.o pnmtops.o2: CFLAGS_TARGET=$(PNMTOPS_NOFLATE_OPT) SCRIPTS = anytopnm pnmtoplainpnm @@ -145,69 +181,68 @@ else LIBOPTR = endif -LIBOPTS_TIFF = $(shell $(LIBOPT) $(NETPBMLIB) \ +LIBOPTS_TIFF = $(shell $(LIBOPT) \ $(LIBOPTR) $(TIFFLIB) $(TIFFLIB_EXTRALIBS)) -tifftopnm pamtotiff pnmtotiffcmyk: %: %.o tiff.o $(NETPBMLIB) $(LIBOPT) - $(LD) -o $@ $@.o tiff.o \ - $(LIBOPTS_TIFF) $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD) +tifftopnm pamtotiff pnmtotiffcmyk: tiff.o +tifftopnm pamtotiff pnmtotiffcmyk: ADDL_OBJECTS = tiff.o +tifftopnm pamtotiff pnmtotiffcmyk: \ + LDFLAGS_TARGET = \ + $(shell $(LIBOPT) $(LIBOPTR) $(TIFFLIB) $(TIFFLIB_EXTRALIBS)) -ifeq ($(shell libpng$(PNGVER)-config --version),) - PNGLIB_LIBOPTS = $(shell $(LIBOPT) $(LIBOPTR) $(PNGLIB) $(ZLIB)) +ifneq ($(shell $(TEST_PKGCONFIG_LIBPNG)),) + # pkg-config libpng works on this system + PNGLIB_LIBOPTS = $(shell pkg-config libpng$(PNGVER) --libs) else - PNGLIB_LIBOPTS = $(shell libpng$(PNGVER)-config --ldflags) + ifneq ($(shell libpng$(PNGVER)-config --version),) + # No pkg-config, but we have libpng-config on this system + PNGLIB_LIBOPTS = $(shell libpng$(PNGVER)-config --ldflags) + else + # System can't tell us where libpng is; use stuff from config.mk + PNGLIB_LIBOPTS = $(shell $(LIBOPT) $(LIBOPTR) $(PNGLIB) $(ZLIB)) + endif endif -pngtopnm pngtopam: %: %.o $(NETPBMLIB) $(LIBOPT) - $(LD) -o $@ $@.o \ - $(shell $(LIBOPT) $(NETPBMLIB)) \ - $(PNGLIB_LIBOPTS) $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD) +pngtopam: pngx.o +pngtopam: ADDL_OBJECTS = pngx.o +pngtopam: LDFLAGS_TARGET = $(PNGLIB_LIBOPTS) + +pamtopng: pngx.o pngtxt.o +pamtopng: ADDL_OBJECTS = pngx.o pngtxt.o +pamtopng: LDFLAGS_TARGET = $(PNGLIB_LIBOPTS) -pnmtopng: %: %.o pngtxt.o $(NETPBMLIB) $(LIBOPT) - $(LD) -o $@ $@.o pngtxt.o \ - $(shell $(LIBOPT) $(NETPBMLIB)) \ - $(PNGLIB_LIBOPTS) $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD) +pnmtopng: pngx.o pngtxt.o +pnmtopng: ADDL_OBJECTS = pngx.o pngtxt.o +pnmtopng: LDFLAGS_TARGET = $(PNGLIB_LIBOPTS) -pamrgbatopng: %: %.o $(NETPBMLIB) $(LIBOPT) - $(LD) -o $@ $@.o \ - $(shell $(LIBOPT) $(NETPBMLIB)) $(PNGLIB_LIBOPTS) \ - $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD) +jpegtopnm: jpegdatasource.o exif.o +jpegtopnm: ADDL_OBJECTS = jpegdatasource.o exif.o +jpegtopnm: LDFLAGS_TARGET = $(shell $(LIBOPT) $(LIBOPTR) $(JPEGLIB)) -jpegtopnm: %: %.o jpegdatasource.o exif.o $(NETPBMLIB) $(LIBOPT) - $(LD) -o $@ $< jpegdatasource.o exif.o \ - $(shell $(LIBOPT) $(NETPBMLIB) $(LIBOPTR) $(JPEGLIB)) \ - $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD) +srftopam pamtosrf: srf.o +srftopam pamtosrf: ADDL_OBJECTS = srf.o -pnmtojpeg: %: %.o $(NETPBMLIB) $(LIBOPT) - $(LD) -o $@ $@.o \ - $(shell $(LIBOPT) $(NETPBMLIB) $(LIBOPTR) $(JPEGLIB)) \ - $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD) +pnmtojpeg: LDFLAGS_TARGET = $(shell $(LIBOPT) $(LIBOPTR) $(JPEGLIB)) -svgtopam: %: %.o $(NETPBMLIB) $(LIBOPT) - $(LD) -o $@ $@.o \ - $(shell $(LIBOPT) $(NETPBMLIB) $(LIBOPTR)) \ - $(XML2_LIBS) $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD) +svgtopam: LDFLAGS_TARGET = $(XML2_LIBS) # If URTLIB is BUNDLED_URTLIB, then we're responsible for building it, which # means it needs to be a dependency: ifeq ($(URTLIB), $(BUNDLED_URTLIB)) - URTLIBDEP = $(URTLIB) +rletopnm pnmtorle: $(URTLIB) endif -rletopnm pnmtorle: %: %.o $(NETPBMLIB) $(URTLIBDEP) $(LIBOPT) - $(LD) -o $@ $@.o \ - $(shell $(LIBOPT) $(URTLIB) $(NETPBMLIB)) \ - $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD) +rletopnm pnmtorle: LDFLAGS_TARGET = $(shell $(LIBOPT) $(URTLIB)) + +pnmtops: LDFLAGS_TARGET = $(shell $(LIBOPT) $(PNMTOPS_ZLIB_OPT)) + +pnmtorast rasttopnm: rast.o +pnmtorast rasttopnm: ADDL_OBJECTS = rast.o -pnmtops: %: %.o bmepsoe.o $(NETPBMLIB) $(LIBOPT) - $(LD) -o $@ $@.o bmepsoe.o \ - $(shell $(LIBOPT) $(NETPBMLIB) $(ZLIB)) \ - $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD) +pdbimgtopam pamtopdbimg: ipdb.o +pdbimgtopam pamtopdbimg: ADDL_OBJECTS = ipdb.o -pnmtorast rasttopnm: %: %.o rast.o $(NETPBMLIB) $(LIBOPT) - $(LD) -o $@ $@.o rast.o \ - $(shell $(LIBOPT) $(NETPBMLIB)) \ - $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD) +# Declare dependencies on created header files (symbolic links, actually). bmptopnm.o bmptopnm.o2: bmp.h @@ -248,3 +283,16 @@ ifneq ($(TIFF_PREREQ_MISSING),Y) cd $(PKGDIR)/bin ; \ $(SYMLINK) pamtotiff$(EXE) pnmtotiff$(EXE) endif +ifeq ($(HAVE_PNGLIB),Y) +# In September 2009, pngtopam replaced pngtopnm + cd $(PKGDIR)/bin ; \ + $(SYMLINK) pngtopam$(EXE) pngtopnm$(EXE) +endif +# In December 2010, sunicontopnm replaced icontopbm + cd $(PKGDIR)/bin ; \ + $(SYMLINK) sunicontopnm$(EXE) icontopbm$(EXE) +ifeq ($(HAVE_PNGLIB),Y) +# In June 2015, pamtopng replaced pamrgbapng + cd $(PKGDIR)/bin ; \ + $(SYMLINK) pamtopng$(EXE) pamrgbatopng$(EXE) +endif diff --git a/converter/other/anytopnm b/converter/other/anytopnm index 06f48b4f..397faae5 100755 --- a/converter/other/anytopnm +++ b/converter/other/anytopnm @@ -150,7 +150,8 @@ computeTypeFromTypeDescription () { filetype=tiff ;; - *PC*bitmap*data* ) + # We have seen "PC bitmap" and "PC bitmap data" + *PC*bitmap* ) filetype=bmp ;; @@ -399,7 +400,7 @@ case "$2" in ;; gif ) - giftopnm "$file" + giftopnm -image=all "$file" ;; tiff ) @@ -437,7 +438,7 @@ case "$2" in ;; png ) - pngtopnm "$file" + pngtopam "$file" ;; mda ) diff --git a/converter/other/avstopam.c b/converter/other/avstopam.c new file mode 100644 index 00000000..322f387d --- /dev/null +++ b/converter/other/avstopam.c @@ -0,0 +1,103 @@ +/* ---------------------------------------------------------------------- + * + * Convert an AVS X image to a PAM image + * + * By Scott Pakin + * + * ---------------------------------------------------------------------- + * + * Copyright (C) 2010 Scott Pakin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + * ---------------------------------------------------------------------- + */ + +#include + +#include "pm.h" +#include "pam.h" + + + +static void +producePam(FILE * const avsFileP, + struct pam * const pamP) { + + tuple * tuplerow; + unsigned int row; + + tuplerow = pnm_allocpamrow(pamP); + for (row = 0; row < pamP->height; ++row) { + unsigned int col; + for (col = 0; col < pamP->width; ++col) { + tuple const thisTuple = tuplerow[col]; + unsigned char c; + pm_readcharu(avsFileP, &c); thisTuple[3] = c; + pm_readcharu(avsFileP, &c); thisTuple[0] = c; + pm_readcharu(avsFileP, &c); thisTuple[1] = c; + pm_readcharu(avsFileP, &c); thisTuple[2] = c; + } + pnm_writepamrow(pamP, tuplerow); + } + pnm_freepamrow(tuplerow); +} + + + +int +main(int argc, const char *argv[]) { + + const char * comment = "Produced by avstopam"; /* constant */ + + struct pam outPam; + const char * inputFilename; + FILE * inFileP; + long width; + long height; + + pm_proginit(&argc, argv); + + inputFilename = (argc > 1) ? argv[1] : "-"; + + inFileP = pm_openr(inputFilename); + + pm_readbiglong(inFileP, &width); + pm_readbiglong(inFileP, &height); + + outPam.size = sizeof(struct pam); + outPam.len = PAM_STRUCT_SIZE(comment_p); + outPam.file = stdout; + outPam.format = PAM_FORMAT; + outPam.plainformat = 0; + outPam.width = width; + outPam.height = height; + outPam.depth = 4; + outPam.maxval = 255; + outPam.bytes_per_sample = 1; + sprintf(outPam.tuple_type, "RGB_ALPHA"); + outPam.allocation_depth = 4; + outPam.comment_p = &comment; + + /* Produce a PAM output header. Note that AVS files *always* + contain four channels with one byte per channel. + */ + pnm_writepaminit(&outPam); + + producePam(inFileP, &outPam); + + pm_closer(inFileP); + + return 0; +} diff --git a/converter/other/bmepsoe.c b/converter/other/bmepsoe.c deleted file mode 100644 index 02bf39aa..00000000 --- a/converter/other/bmepsoe.c +++ /dev/null @@ -1,560 +0,0 @@ -/* - * This was adapted for Netpbm from bmpesoe.c in Dirk Krause's Bmeps package - * by Bryan Henderson on 2005.01.05. - * - * Differences: - * - doesn't require Bmeps configuration stuff (bmepsco.h) - * - doesn't include pngeps.h - * - doesn't have test scaffold code - * - a few compiler warnings fixed - * - * Copyright (C) 2000 - Dirk Krause - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * In this package the copy of the GNU Library General Public License - * is placed in file COPYING. - */ - -#include "bmepsoe.h" - -#define RL_RUNLENGTH(i) (257 - (i)) -#define RL_STRINGLENGTH(i) ((i) - 1) -#define RL_MAXLENGTH (127) - -#define FINALOUTPUT(c) fputc((c),o->out) - -void oe_init(Output_Encoder *o, FILE *out, int mode, int rate, int *buf, - Bytef *flib, size_t flis, Bytef *flob, size_t flos -) -{ - - o->out = out; - o->mode = mode; - o->textpos = 0; - o->a85_value = 0UL; o->a85_consumed = 0; - o->a85_0 = 1UL; - o->a85_1 = 85UL; - o->a85_2 = 85UL * 85UL; - o->a85_3 = 85UL * o->a85_2; - o->a85_4 = 85UL * o->a85_3; - o->rl_lastbyte = 0; - o->rl_buffer = buf; - o->rl_bufused = 0; - o->rl_state = 0; - o->bit_value = 0; - o->bit_consumed = 0; - o->flate_rate = rate; - if(o->flate_rate < 0) { - o->mode &= (~OE_FLATE); - } - if(o->flate_rate > 9) { - o->flate_rate = 9; - } - if((o->mode & OE_FLATE) && flib && flis && flob && flos) { - (o->flate_stream).zfree = (free_func)0; - (o->flate_stream).zalloc = (alloc_func)0; - (o->flate_stream).opaque = (voidpf)0; - if(deflateInit((&(o->flate_stream)),o->flate_rate) != Z_OK) { - o->mode &= (~OE_FLATE); - } - } - o->fl_i_buffer = flib; - o->fl_o_buffer = flob; - o->fl_i_size = flis; - o->fl_o_size = flos; - o->fl_i_used = 0; - -} - -static char hexdigits[] = { - "0123456789ABCDEF" -}; - -static void asciihex_add(Output_Encoder *o, int b) -{ - - FINALOUTPUT(hexdigits[(b/16)]) ; - FINALOUTPUT(hexdigits[(b%16)]) ; - o->textpos = o->textpos + 2; - if(o->textpos >= 64) { - FINALOUTPUT('\n') ; - o->textpos = 0; - } - -} - -static void asciihex_flush(Output_Encoder *o) -{ - - if(o->textpos > 0) { - FINALOUTPUT('\n') ; - o->textpos = 0; - } - -} - -static char ascii85_char(unsigned long x) -{ - unsigned u; - int i; - char back; - back = (char)0; - u = (unsigned)x; - i = (int)u; - i += 33; - back = (char)i; - return back; -} - - - -static void -ascii85_output(Output_Encoder * const o) { - unsigned long value; - - value = o->a85_value; /* initial value */ - - if (value == 0 && o->a85_consumed == 4) { - FINALOUTPUT('z'); - ++o->textpos; - } else { - unsigned int i; - unsigned int j; - char buffer[6]; - - buffer[0] = ascii85_char(value / (o->a85_4)); - value = value % (o->a85_4); - buffer[1] = ascii85_char(value / (o->a85_3)); - value = value % (o->a85_3); - buffer[2] = ascii85_char(value / (o->a85_2)); - value = value % (o->a85_2); - buffer[3] = ascii85_char(value / (o->a85_1)); - value = value % (o->a85_1); - buffer[4] = ascii85_char(value); - buffer[5] = '\0'; - - i = o->a85_consumed + 1; - o->textpos += i; - - for (j = 0; j < i; ++j) - FINALOUTPUT(buffer[j]); - } - if (o->textpos >= 64) { - FINALOUTPUT('\n'); - o->textpos = 0; - } -} - - - -static void ascii85_add(Output_Encoder *o, int b) -{ - unsigned u; - unsigned long ul; - - u = (unsigned)b; - ul = (unsigned long)u; - o->a85_value = 256UL * (o->a85_value) + ul; - o->a85_consumed = o->a85_consumed + 1; - if(o->a85_consumed >= 4) { - ascii85_output(o); - o->a85_value = 0UL; - o->a85_consumed = 0; - } - -} - -static void ascii85_flush(Output_Encoder *o) -{ - int i; - - if(o->a85_consumed > 0) { - i = o->a85_consumed; - while(i < 4) { - o->a85_value = 256UL * o->a85_value; - i++; - } - ascii85_output(o); - o->a85_value = 0UL; - o->a85_consumed = 0; - } - if(o->textpos > 0) { - FINALOUTPUT('\n') ; - o->textpos = 0; - } - -} - -static void after_flate_add(Output_Encoder *o, int b) -{ - - if(o->mode & OE_ASC85) { - ascii85_add(o,b); - } else { - asciihex_add(o,b); - } - -} - - - -static void -do_flate_flush(Output_Encoder * const oP, - int const final) { - - Bytef *iptr, *optr, *xptr; - unsigned long is; - unsigned long os; - unsigned long xs; - int err; - int mustContinue; - - iptr = oP->fl_i_buffer; optr = oP->fl_o_buffer; - is = oP->fl_i_size; os = oP->fl_o_size; - - if (iptr && optr && is && os) { - is = oP->fl_i_used; - if (is || final) { - oP->flate_stream.next_in = iptr; - oP->flate_stream.avail_in = is; - if (final) { - mustContinue = 1; - while (mustContinue) { - oP->flate_stream.next_out = optr; - oP->flate_stream.avail_out = os; - mustContinue = 0; - err = deflate(&oP->flate_stream, Z_FINISH); - switch (err) { - case Z_STREAM_END: { - xptr = optr; - - xs = os - (oP->flate_stream.avail_out); - while (xs--) { - after_flate_add(oP, *(xptr++)); - } - } break; - case Z_OK : { - mustContinue = 1; - xptr = optr; - - xs = os - (oP->flate_stream.avail_out); - while (xs--) { - after_flate_add(oP, *(xptr++)); - } - } break; - default : { - } break; - } - } - } else { - mustContinue = 1; - while (mustContinue) { - mustContinue = 0; - oP->flate_stream.avail_out = os; - oP->flate_stream.next_out = optr; - err = deflate(&oP->flate_stream, 0); - switch (err) { - case Z_OK: { - if (oP->flate_stream.avail_in) { - mustContinue = 1; - } - - xptr = optr; xs = os - (oP->flate_stream.avail_out); - while (xs--) { - after_flate_add(oP, *(xptr++)); - } - } break; - default : { - } break; - } - } - } - } - } -} - - - -static void flate_add(Output_Encoder *o, int b) -{ - Byte bt; - Bytef *btptr; - - btptr = o->fl_i_buffer; - if(btptr) { - bt = (Byte)b; - btptr[(o->fl_i_used)] = bt; - o->fl_i_used += 1UL; - if(o->fl_i_used >= o->fl_i_size) { - do_flate_flush(o, 0); - o->fl_i_used = 0UL; - } - } - -} - -static void after_flate_flush(Output_Encoder *o) -{ - - if(o->mode & OE_ASC85) { - ascii85_flush(o); - } else { - asciihex_flush(o); - } - -} - -static void flate_flush(Output_Encoder *o) -{ - do_flate_flush(o,1); - deflateEnd(&(o->flate_stream)); - after_flate_flush(o); -} - - -static void after_rl_add(Output_Encoder *o, int b) -{ - - if(o->mode & OE_FLATE) { - flate_add(o,b); - } else { - after_flate_add(o,b); - } - -} - -static void rl_add(Output_Encoder *o, int b) -{ - int lgt, i; - int *buffer; - /* ##### */ - - buffer = o->rl_buffer; - lgt = o->rl_bufused; - if(buffer) { - - if(lgt > 0) { - if(o->rl_lastbyte == b) { - switch(o->rl_state) { - case 2: { - buffer[lgt++] = b; - o->rl_bufused = lgt; - o->rl_state = 2; - o->rl_lastbyte = b; - if(lgt >= RL_MAXLENGTH) { - after_rl_add(o, RL_RUNLENGTH(lgt)); - after_rl_add(o, b); - o->rl_bufused = 0; - o->rl_state = 0; - o->rl_lastbyte = b; - } - } break; - case 1: { - buffer[lgt++] = b; - o->rl_bufused = lgt; - o->rl_state = 2; - o->rl_lastbyte = b; - lgt = lgt - 3; - if(lgt > 0) { - after_rl_add(o, RL_STRINGLENGTH(lgt)); - for(i = 0; i < lgt; i++) { - after_rl_add(o, buffer[i]); - } - buffer[0] = buffer[1] = buffer[2] = b; - o->rl_bufused = 3; - o->rl_state = 2; - o->rl_lastbyte = b; - } - } break; - default: { - buffer[lgt++] = b; - o->rl_bufused = lgt; - o->rl_state = 1; - o->rl_lastbyte = b; - if(lgt >= RL_MAXLENGTH) { - lgt = lgt - 2; - after_rl_add(o, RL_STRINGLENGTH(lgt)); - for(i = 0; i < lgt; i++) { - after_rl_add(o, buffer[i]); - } - buffer[0] = buffer[1] = b; - o->rl_bufused = 2; - o->rl_state = 1; - o->rl_lastbyte = b; - } - } break; - } - } else { - if(o->rl_state == 2) { - after_rl_add(o, RL_RUNLENGTH(lgt)); - after_rl_add(o, (o->rl_lastbyte)); - buffer[0] = b; o->rl_bufused = 1; o->rl_lastbyte = b; - o->rl_state = 0; - } else { - buffer[lgt++] = b; - o->rl_bufused = lgt; - o->rl_lastbyte = b; - if(lgt >= RL_MAXLENGTH) { - after_rl_add(o, RL_STRINGLENGTH(lgt)); - for(i = 0; i < lgt; i++) { - after_rl_add(o, buffer[i]); - } - o->rl_bufused = 0; - } - o->rl_state = 0; - } - } - } else { - buffer[0] = b; - o->rl_bufused = 1; - o->rl_lastbyte = b; - } - o->rl_lastbyte = b; - - } else { - after_rl_add(o,0); - after_rl_add(o,b); - } - -} - -static void after_rl_flush(Output_Encoder *o) -{ - - if(o->mode & OE_FLATE) { - flate_flush(o); - } else { - after_flate_flush(o); - } - -} - -static void rl_flush(Output_Encoder *o) -{ - int lgt; - int *buffer; - int i; - - buffer = o->rl_buffer; - lgt = o->rl_bufused; - if(lgt > 0) { - if(o->rl_state == 2) { - i = o->rl_lastbyte; - after_rl_add(o,RL_RUNLENGTH(lgt)); - after_rl_add(o,i); - } else { - after_rl_add(o,RL_STRINGLENGTH(lgt)); - for(i = 0; i < lgt; i++) { - after_rl_add(o,buffer[i]); - } - } - } - after_rl_flush(o); - -} - - - -static void -internal_byte_add(Output_Encoder * const oP, - int const b) { - - if (oP->mode & OE_RL) - rl_add(oP, b); - else - after_rl_add(oP, b); -} - - - -static void internal_byte_flush(Output_Encoder *o) -{ - - if((o->mode) & OE_RL) { - rl_flush(o); - } else { - after_rl_flush(o); - } - -} - - - -void -oe_bit_add(Output_Encoder * const oP, - int const b) { - - oP->bit_value = 2 * oP->bit_value + (b ? 1 : 0); - oP->bit_consumed = oP->bit_consumed + 1; - if (oP->bit_consumed >= 8) { - oP->bit_consumed = 0; - internal_byte_add(oP, oP->bit_value); - oP->bit_value = 0; - } -} - - - -void oe_bit_flush(Output_Encoder *o) -{ - - if(o->bit_consumed) { - int v, i; - v = o->bit_value; - i = o->bit_consumed; - while(i < 8) { - i++; - v = v * 2; - } - internal_byte_add(o,v); - o->bit_value = 0; - o->bit_consumed = 0; - } - internal_byte_flush(o); - -} - - - -void -oe_byte_add(Output_Encoder * const oP, - int const b) { - - if (oP->bit_consumed) { - int testval; - int i; - testval = 128; - for (i = 0; i < 8; ++i) { - if (b & testval) { - oe_bit_add(oP, 1); - } else { - oe_bit_add(oP, 0); - } - testval = testval / 2; - } - } else { - internal_byte_add(oP, b); - } -} - - - -void oe_byte_flush(Output_Encoder *o) -{ - - oe_bit_flush(o); - -} diff --git a/converter/other/bmepsoe.h b/converter/other/bmepsoe.h deleted file mode 100644 index 99c59f77..00000000 --- a/converter/other/bmepsoe.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * libbmeps - Bitmap to EPS conversion library - * Copyright (C) 2000 - Dirk Krause - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * In this package the copy of the GNU Library General Public License - * is placed in file COPYING. - */ - -#ifndef BMPESOE_H_INCLUDED -#define BMPESOE_H_INCLUDED - -#include - -#include - -typedef struct { - int mode; - FILE *out; - int textpos; - unsigned long a85_value; - int a85_consumed; - unsigned long a85_4; - unsigned long a85_3; - unsigned long a85_2; - unsigned long a85_1; - unsigned long a85_0; - int rl_lastbyte; - int *rl_buffer; - int rl_bufused; - int rl_state; - int bit_value; - int bit_consumed; - z_stream flate_stream; - Bytef *fl_i_buffer; - Bytef *fl_o_buffer; - uLong fl_i_size; - uLong fl_o_size; - uLong fl_i_used; - int flate_rate; -} Output_Encoder; - -#ifdef __cplusplus -extern "C" { -#endif - -void oe_init(Output_Encoder *o, FILE *out, int mode, int rate, int *buf, - Bytef *flib, size_t flis, Bytef *flob, size_t flos -); -void oe_byte_add(Output_Encoder *o, int b); -void oe_byte_flush(Output_Encoder *o); -void oe_bit_add(Output_Encoder *o, int b); -void oe_bit_flush(Output_Encoder *o); - -#ifdef __cplusplus -} -#endif - - - -#define OE_ASC85 1 -#define OE_FLATE 2 -#define OE_RL 4 - -#endif - diff --git a/converter/other/bmptopnm.c b/converter/other/bmptopnm.c index 9a405d70..a069092f 100644 --- a/converter/other/bmptopnm.c +++ b/converter/other/bmptopnm.c @@ -28,14 +28,12 @@ #include #include "pm_c_util.h" -#include "pnm.h" +#include "mallocvar.h" #include "shhopt.h" #include "nstring.h" +#include "pnm.h" #include "bmp.h" -/* MAXCOLORS is the maximum size of a color map in a BMP image */ -#define MAXCOLORS 256 - static xelval const bmpMaxval = 255; /* The maxval for intensity values in a BMP image -- either in a truecolor raster or in a colormap @@ -84,8 +82,8 @@ struct pixelformat { struct bmpInfoHeader { enum rowOrder rowOrder; - int cols; - int rows; + unsigned int cols; + unsigned int rows; unsigned int cBitCount; /* Number of bits in the BMP file that each pixel occupies. */ enum bmpClass class; @@ -103,59 +101,57 @@ struct bmpInfoHeader { /* Size in bytes of the image data. We only reference this when the image is compressed. */ unsigned short cPlanes; - unsigned long int compression; + BMPCompType compression; struct pixelformat pixelformat; }; -struct cmdline_info { +struct cmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ - const char *input_filespec; /* Filespecs of input files */ - int verbose; /* -verbose option */ + const char * inputFileName; + unsigned int verbose; }; -static const char *ifname; +static const char * ifname; static void -parse_command_line(int argc, char ** argv, - struct cmdline_info *cmdline_p) { +parseCommandLine(int argc, const char ** argv, + struct cmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- Note that the file spec array we return is stored in the storage that was passed to us as the argv array. -----------------------------------------------------------------------------*/ - optStruct *option_def = malloc(100*sizeof(optStruct)); + optEntry * option_def; /* Instructions to OptParseOptions2 on how to parse our options. */ - optStruct2 opt; + optStruct3 opt; unsigned int option_def_index; - option_def_index = 0; /* incremented by OPTENTRY */ - OPTENTRY(0, "verbose", OPT_FLAG, &cmdline_p->verbose, 0); - - /* Set the defaults */ - cmdline_p->verbose = FALSE; + MALLOCARRAY_NOFAIL(option_def, 100); + option_def_index = 0; /* incremented by OPTENT3 */ + OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); + opt.opt_table = option_def; opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions2(&argc, argv, opt, 0); - /* Uses and sets argc, argv, and some of *cmdline_p and others. */ + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (argc-1 == 0) - cmdline_p->input_filespec = "-"; + cmdlineP->inputFileName = "-"; else if (argc-1 != 1) pm_error("Program takes zero or one argument (filename). You " "specified %d", argc-1); else - cmdline_p->input_filespec = argv[1]; - + cmdlineP->inputFileName = argv[1]; } @@ -249,13 +245,13 @@ readOffBytes(FILE * const fp, unsigned int const nbytes) { static void -BMPreadfileheader(FILE * const ifP, +bmpReadfileheader(FILE * const ifP, unsigned int * const bytesReadP, unsigned int * const offBitsP) { - unsigned short xHotSpot; - unsigned short yHotSpot; - unsigned long offBits; + unsigned short xHotSpot; + unsigned short yHotSpot; + unsigned long offBits; unsigned long int fileSize; @@ -268,9 +264,9 @@ BMPreadfileheader(FILE * const ifP, fileSize = GetLong(ifP); /* This is not always reliable. */ - xHotSpot = GetShort(ifP); - yHotSpot = GetShort(ifP); - offBits = GetLong(ifP); + xHotSpot = GetShort(ifP); + yHotSpot = GetShort(ifP); + offBits = GetLong(ifP); *offBitsP = offBits; @@ -283,13 +279,28 @@ static void readOs2InfoHeader(FILE * const ifP, struct bmpInfoHeader * const headerP) { + unsigned short colsField, rowsField; + unsigned short planesField, bitCountField; + headerP->class = C_OS2; - headerP->cols = GetShort(ifP); - headerP->rows = GetShort(ifP); + pm_readlittleshortu(ifP, &colsField); + if (colsField == 0) + pm_error("Invalid BMP file: says width is zero"); + else + headerP->cols = colsField; + + pm_readlittleshortu(ifP, &rowsField); + if (rowsField == 0) + pm_error("Invalid BMP file: says height is zero"); + else + headerP->rows = rowsField; + headerP->rowOrder = BOTTOMUP; - headerP->cPlanes = GetShort(ifP); - headerP->cBitCount = GetShort(ifP); + pm_readlittleshortu(ifP, &planesField); + headerP->cPlanes = planesField; + pm_readlittleshortu(ifP, &bitCountField); + headerP->cBitCount = bitCountField; /* I actually don't know if the OS/2 BMP format allows cBitCount > 8 or if it does, what it means, but ppmtobmp creates such BMPs, more or less as a byproduct of creating @@ -307,7 +318,7 @@ readOs2InfoHeader(FILE * const ifP, pm_error("Unrecognized bits per pixel in OS/2 BMP file header: %d", headerP->cBitCount); - headerP->compression = COMP_RGB; + headerP->compression = BMPCOMP_RGB; pm_message("OS/2 BMP, %dx%dx%d", headerP->cols, headerP->rows, headerP->cBitCount); @@ -320,26 +331,26 @@ validateCompression(unsigned long const compression, enum rowOrder const rowOrder, unsigned int const cBitCount) { - if (compression != COMP_RGB && compression != COMP_BITFIELDS && - compression != COMP_RLE4 && compression != COMP_RLE8 ) + if (compression != BMPCOMP_RGB && compression != BMPCOMP_BITFIELDS && + compression != BMPCOMP_RLE4 && compression != BMPCOMP_RLE8) pm_error("Input has unknown encoding. " "Compression type code = %ld. The only ones we know " "are RGB (%u), BITFIELDS (%u), " "RLE4 (%u), and RLE8 (%u)", - compression, COMP_RGB, COMP_BITFIELDS, - COMP_RLE4, COMP_RLE8); + compression, BMPCOMP_RGB, BMPCOMP_BITFIELDS, + BMPCOMP_RLE4, BMPCOMP_RLE8); - if ((compression == COMP_RLE4 || compression == COMP_RLE8) && + if ((compression == BMPCOMP_RLE4 || compression == BMPCOMP_RLE8) && rowOrder == TOPDOWN ) pm_error("Invalid BMP header. Claims image is top-down and also " "compressed, which is an impossible combination."); - if ( (compression == COMP_RLE4 && cBitCount !=4) || - (compression == COMP_RLE8 && cBitCount !=8) ) + if ((compression == BMPCOMP_RLE4 && cBitCount !=4 ) || + (compression == BMPCOMP_RLE8 && cBitCount !=8 )) pm_error("Invalid BMP header. " "Compression type (%s) disagrees with " "number of bits per pixel (%u).", - compression == COMP_RLE4 ? "RLE4" : "RLE8", + compression == BMPCOMP_RLE4 ? "RLE4" : "RLE8", cBitCount); } @@ -357,12 +368,16 @@ readWindowsBasic40ByteInfoHeader(FILE * const ifP, -----------------------------------------------------------------------------*/ int colorsimportant; /* ColorsImportant value from header */ int colorsused; /* ColorsUsed value from header */ + unsigned short planesField, bitCountField; headerP->class = C_WIN; headerP->cols = GetLong(ifP); + if (headerP->cols == 0) + pm_error("Invalid BMP file: says width is zero"); { long const cy = GetLong(ifP); + if (cy == 0) pm_error("Invalid BMP file: says height is zero"); if (cy < 0) { @@ -373,17 +388,18 @@ readWindowsBasic40ByteInfoHeader(FILE * const ifP, headerP->rows = cy; } } - headerP->cPlanes = GetShort(ifP); - headerP->cBitCount = GetShort(ifP); - + pm_readlittleshortu(ifP, &planesField); + headerP->cPlanes = planesField; + pm_readlittleshortu(ifP, &bitCountField); + headerP->cBitCount = bitCountField; { unsigned long int const compression = GetLong(ifP); - headerP->bitFields = (compression == COMP_BITFIELDS); - validateCompression(compression, headerP->rowOrder, headerP->cBitCount); + headerP->bitFields = (compression == BMPCOMP_BITFIELDS); + headerP->compression = compression; } /* And read the rest of the junk in the 40 byte header */ @@ -596,7 +612,7 @@ readWindowsInfoHeader(FILE * const ifP, static void -BMPreadinfoheader(FILE * const ifP, +bmpReadinfoheader(FILE * const ifP, unsigned int * const bytesReadP, struct bmpInfoHeader * const headerP) { @@ -622,7 +638,7 @@ BMPreadinfoheader(FILE * const ifP, static void -BMPreadcolormap(FILE * const ifP, +bmpReadColormap(FILE * const ifP, int const class, xel ** const colormapP, unsigned int const cmapsize, @@ -837,7 +853,7 @@ convertRow(unsigned char const bmprow[], unsigned int col; for (col = 0; col < cols; ++col) xelrow[col] = colormap[bmprow[col]]; - } else if (cBitCount < 8) { + } else if (cBitCount == 1 || cBitCount == 2 || cBitCount == 4) { /* It's a bit field color index */ unsigned char const mask = ( 1 << cBitCount ) - 1; @@ -850,18 +866,21 @@ convertRow(unsigned char const bmprow[], (bmprow[cursor] & (mask << shift)) >> shift; xelrow[col] = colormap[index]; } - } else - pm_error("Internal error: invalid cBitCount in convertRow()"); + } else { + /* Every possible BMP bits per pixel is handled above */ + assert(false); + } } static unsigned char ** -allocBMPraster(unsigned int const rows, unsigned int const bytesPerRow) { +allocBmpRaster(unsigned int const rows, + unsigned int const bytesPerRow) { unsigned int const storageSize = rows * sizeof(unsigned char *) + rows * bytesPerRow; - unsigned char ** BMPraster; + unsigned char ** bmpRaster; unsigned int row; unsigned char * startOfRows; @@ -872,18 +891,18 @@ allocBMPraster(unsigned int const rows, unsigned int const bytesPerRow) { if (UINT_MAX / (bytesPerRow + sizeof(unsigned char *)) < rows) pm_error("raster is ridiculously large."); - BMPraster = (unsigned char **) malloc(storageSize); + bmpRaster = (unsigned char **) malloc(storageSize); - if (BMPraster == NULL) + if (bmpRaster == NULL) pm_error("Unable to allocate %u bytes for the BMP raster\n", storageSize); - startOfRows = (unsigned char *)(BMPraster + rows); + startOfRows = (unsigned char *)(bmpRaster + rows); for (row = 0; row < rows; ++row) - BMPraster[row] = startOfRows + row * bytesPerRow; + bmpRaster[row] = startOfRows + row * bytesPerRow; - return BMPraster; + return bmpRaster; } @@ -892,14 +911,14 @@ static void readrow(FILE * const ifP, unsigned int const row, unsigned int const bytesPerRow, - unsigned char ** const BMPraster, + unsigned char ** const bmpRaster, unsigned int * const bytesReadP) { size_t bytesRead; assert(bytesPerRow > 0); - bytesRead = fread(BMPraster[row], 1, bytesPerRow, ifP); + bytesRead = fread(bmpRaster[row], 1, bytesPerRow, ifP); if (bytesRead < bytesPerRow) { if (feof(ifP)) @@ -975,12 +994,12 @@ readrowRLE(FILE * const ifP, unsigned int const row, unsigned int const cols, bool const lastrow, - unsigned long const compression, - unsigned char ** const BMPraster, + BMPCompType const compression, + unsigned char ** const bmpRaster, unsigned int * const bytesReadP) { - bool const RLE4 = (compression == COMP_RLE4); - int const pixelsPerRowMargin = RLE4 ? cols % 2 : 0; + bool const rle4 = (compression == BMPCOMP_RLE4); + int const pixelsPerRowMargin = rle4 ? cols % 2 : 0; char const err_decode[] = "Error while decoding compressed BMP image. " @@ -998,17 +1017,17 @@ readrowRLE(FILE * const ifP, totalBytesRead = 0; /* Initial value */ pixelsRead = 0; /* Initial value */ - while (TRUE) { + while (true) { unsigned int n; /* decompressed bytes already read; current write point */ unsigned int cnt; unsigned char code; - n = RLE4 ? (pixelsRead + 1) / 2 : pixelsRead; + n = rle4 ? (pixelsRead + 1) / 2 : pixelsRead; switch (readRLEcode(ifP, &cnt, &code)) { case ENC_MODE: { - unsigned int const byteCnt = RLE4 ? (cnt + 1) /2 : cnt; + unsigned int const byteCnt = rle4 ? (cnt + 1) /2 : cnt; unsigned int i; if (pixelsRead + cnt > cols + pixelsPerRowMargin) @@ -1016,11 +1035,11 @@ readrowRLE(FILE * const ifP, row, pixelsRead ); for (i = 0; i < byteCnt; ++i) - BMPraster[row][n+i] = code; + bmpRaster[row][n+i] = code; - if (RLE4 && pixelsRead % 2 == 1) + if (rle4 && pixelsRead % 2 == 1) /* previous read ended odd */ - nibbleAlign(&BMPraster[row][n-1], cnt); + nibbleAlign(&bmpRaster[row][n-1], cnt); pixelsRead += cnt; totalBytesRead += 2; @@ -1030,13 +1049,13 @@ readrowRLE(FILE * const ifP, unsigned int cmpBytesRead; /* compressed bytes read */ /* align read-end to 16 bit boundary */ unsigned int const bytesToRead = - RLE4 ? (cnt + 3) / 4 * 2 : (cnt + 1) / 2 * 2; + rle4 ? (cnt + 3) / 4 * 2 : (cnt + 1) / 2 * 2; if (pixelsRead + cnt > cols + pixelsPerRowMargin) pm_error(err_decode, "Too many pixels in absolute mode", row, pixelsRead); - cmpBytesRead = fread(&BMPraster[row][n], + cmpBytesRead = fread(&bmpRaster[row][n], sizeof(char), bytesToRead, ifP); if (cmpBytesRead < bytesToRead) { @@ -1047,8 +1066,8 @@ readrowRLE(FILE * const ifP, pm_error("Error reading BMP raster. Errno=%d (%s)", errno, strerror(errno)); } - if (RLE4 && pixelsRead % 2 == 1) /* previous read ended odd */ - nibbleAlign(&BMPraster[row][n-1], cnt); + if (rle4 && pixelsRead % 2 == 1) /* previous read ended odd */ + nibbleAlign(&bmpRaster[row][n-1], cnt); pixelsRead += cnt; totalBytesRead += cmpBytesRead + 2; @@ -1098,25 +1117,36 @@ readrowRLE(FILE * const ifP, static void -BMPreadraster(FILE * const ifP, +bmpReadraster(FILE * const ifP, unsigned int const cols, unsigned int const rows, enum rowOrder const rowOrder, unsigned int const cBitCount, - unsigned long int const compression, - unsigned char *** const BMPrasterP, + BMPCompType const compression, + unsigned char *** const bmpRasterP, unsigned int * const bytesReadP) { +/*---------------------------------------------------------------------------- + Read the raster from the BMP file on *ifP (which is positioned to the + raster). The raster is 'rows' rows of 'cols' columns, 'cBitCount' bits per + pixel, with rows in order 'rowOrder'. + Return the raster in a newly malloced 2-dimensional array and return + a pointer to that array as *bmpRasterP. + + Leave the input file positioned immediately after the raster and return + as *bytesReadP the number of bytes we read from the file (i.e. the number + of bytes in the raster portion of the file). +-----------------------------------------------------------------------------*/ unsigned int const bytesPerRow = - (compression == COMP_RLE4) ? cols / 2 + 2 : - (compression == COMP_RLE8) ? cols + 1 : + (compression == BMPCOMP_RLE4) ? cols / 2 + 2 : + (compression == BMPCOMP_RLE8) ? cols + 1 : ((cols * cBitCount + 31) / 32) * 4; /* A BMP raster row is a multiple of 4 bytes, padded on the right with don't cares. */ - unsigned char ** BMPraster; + unsigned char ** bmpRaster; - BMPraster = allocBMPraster(rows, bytesPerRow); + bmpRaster = allocBmpRaster(rows, bytesPerRow); *bytesReadP = 0; @@ -1127,31 +1157,36 @@ BMPreadraster(FILE * const ifP, */ switch(compression){ - case COMP_RGB: - case COMP_BITFIELDS: { + case BMPCOMP_RGB: + case BMPCOMP_BITFIELDS: { unsigned int i; for (i = 0; i < rows; ++i) readrow(ifP, rowOrder == TOPDOWN ? i : rows - i - 1, - bytesPerRow, BMPraster, bytesReadP); + bytesPerRow, bmpRaster, bytesReadP); } break; - case COMP_RLE4: - case COMP_RLE8: { + case BMPCOMP_RLE4: + case BMPCOMP_RLE8: { unsigned int i; /* Read all rows except last */ + assert(rows >= 1); for (i = 0; i < rows - 1; ++i){ readrowRLE(ifP, rowOrder == TOPDOWN ? i : rows - i - 1, - cols, FALSE, compression, BMPraster, bytesReadP); + cols, FALSE, compression, bmpRaster, bytesReadP); } /* Read last row */ readrowRLE(ifP, rowOrder == TOPDOWN ? i : rows - i - 1, - cols, TRUE, compression, BMPraster, bytesReadP); + cols, TRUE, compression, bmpRaster, bytesReadP); } break; - default: - pm_error("The BMP specifies a compression scheme we don't " - "recognize. Code= %lu", compression); + case BMPCOMP_JPEG: + pm_error("BMP file uses JPEG compression. We don't know how to " + "interpret that."); + break; + case BMPCOMP_PNG: + pm_error("BMP file uses PNG compression. We don't know how to " + "interpret that."); + break; } - - *BMPrasterP = BMPraster; + *bmpRasterP = bmpRaster; } @@ -1172,14 +1207,7 @@ reportHeader(struct bmpInfoHeader const header, header.rowOrder == BOTTOMUP ? "bottom up" : "top down"); pm_message(" Byte offset of raster within file: %u", offBits); pm_message(" Bits per pixel in raster: %u", header.cBitCount); - pm_message(" Compression: %s", - header.compression == COMP_RGB ? "none" : - header.compression == COMP_RLE4 ? "4 bit run-length coding" : - header.compression == COMP_RLE8 ? "8 bit run-length coding" : - header.compression == COMP_BITFIELDS ? "none" : - header.compression == COMP_JPEG ? "JPEG (not supported)" : - header.compression == COMP_PNG ? "PNG (not supported)" : - "???"); + pm_message(" Compression: %s", BMPCompTypeName(header.compression)); pm_message(" Colors in color map: %u", header.cmapsize); } @@ -1217,11 +1245,11 @@ analyzeColors(xel const colormap[], static void -warnIfOffBitsWrong(struct bmpInfoHeader const BMPheader, +warnIfOffBitsWrong(struct bmpInfoHeader const bmpHeader, unsigned int const offBits) { - if (offBits != BMPoffbits(BMPheader.class, BMPheader.cBitCount, - BMPheader.cmapsize)) { + if (offBits != BMPoffbits(bmpHeader.class, bmpHeader.cBitCount, + bmpHeader.cmapsize)) { pm_message("warning: the BMP header says the raster starts " "at offset %u bytes into the file (offbits), " @@ -1229,8 +1257,8 @@ warnIfOffBitsWrong(struct bmpInfoHeader const BMPheader, "the raster. This inconsistency probably means the " "input file is not a legal BMP file and is unusable.", offBits, - BMPoffbits(BMPheader.class, BMPheader.cBitCount, - BMPheader.cmapsize)); + BMPoffbits(bmpHeader.class, bmpHeader.cBitCount, + bmpHeader.cmapsize)); } } @@ -1238,63 +1266,37 @@ warnIfOffBitsWrong(struct bmpInfoHeader const BMPheader, static void readColorMap(FILE * const ifP, - struct bmpInfoHeader const BMPheader, + struct bmpInfoHeader const bmpHeader, xel ** const colorMapP, unsigned int * const posP) { unsigned int bytesRead; - BMPreadcolormap(ifP, BMPheader.class, - colorMapP, BMPheader.cmapsize, &bytesRead); + bmpReadColormap(ifP, bmpHeader.class, + colorMapP, bmpHeader.cmapsize, &bytesRead); *posP += bytesRead; - - if (bytesRead != BMPlencolormap(BMPheader.class, BMPheader.cBitCount, - BMPheader.cmapsize)) { - - pm_message("warning: %u-byte RGB table, expected %u bytes", - bytesRead, - BMPlencolormap(BMPheader.class, BMPheader.cBitCount, - BMPheader.cmapsize)); - } } static void readRaster(FILE * const ifP, - struct bmpInfoHeader const BMPheader, - unsigned char *** const BMPrasterP, + struct bmpInfoHeader const bmpHeader, + unsigned char *** const bmpRasterP, unsigned int * const posP) { unsigned int bytesRead; - BMPreadraster(ifP, BMPheader.cols, BMPheader.rows, BMPheader.rowOrder, - BMPheader.cBitCount, BMPheader.compression, - BMPrasterP, &bytesRead); + bmpReadraster(ifP, bmpHeader.cols, bmpHeader.rows, bmpHeader.rowOrder, + bmpHeader.cBitCount, bmpHeader.compression, + bmpRasterP, &bytesRead); *posP += bytesRead; } -static void -warnIfBadFileSize(struct bmpInfoHeader const BMPheader, - unsigned int const pos) { - - unsigned int const expectedSize = - BMPlenfileGen(BMPheader.class, BMPheader.cBitCount, - BMPheader.cmapsize, BMPheader.cols, - BMPheader.rows, BMPheader.imageSize, - BMPheader.compression); - - if (pos != expectedSize) - pm_message("warning: read %u bytes, expected to read %u bytes", - pos, expectedSize); -} - - - static bool isValidBmpBpp(unsigned int const cBitCount) { @@ -1316,7 +1318,7 @@ isValidBmpBpp(unsigned int const cBitCount) { static void readBmp(FILE * const ifP, - unsigned char *** const BMPrasterP, + unsigned char *** const bmpRasterP, int * const colsP, int * const rowsP, bool * const grayPresentP, @@ -1334,59 +1336,58 @@ readBmp(FILE * const ifP, unsigned int offBits; /* Byte offset into file of raster */ - struct bmpInfoHeader BMPheader; + struct bmpInfoHeader bmpHeader; pos = 0; /* Starting at the beginning ... */ { unsigned int bytesRead; - BMPreadfileheader(ifP, &bytesRead, &offBits); + bmpReadfileheader(ifP, &bytesRead, &offBits); pos += bytesRead; } { unsigned int bytesRead; - BMPreadinfoheader(ifP, &bytesRead, &BMPheader); + bmpReadinfoheader(ifP, &bytesRead, &bmpHeader); if (verbose) pm_message("Read %u bytes of header", bytesRead); pos += bytesRead; } if (verbose) - reportHeader(BMPheader, offBits); + reportHeader(bmpHeader, offBits); - warnIfOffBitsWrong(BMPheader, offBits); + warnIfOffBitsWrong(bmpHeader, offBits); - readColorMap(ifP, BMPheader, &colormap, &pos); + readColorMap(ifP, bmpHeader, &colormap, &pos); - analyzeColors(colormap, BMPheader.cmapsize, bmpMaxval, + analyzeColors(colormap, bmpHeader.cmapsize, bmpMaxval, grayPresentP, colorPresentP); readOffBytes(ifP, offBits - pos); pos = offBits; - readRaster(ifP, BMPheader, BMPrasterP, &pos); + readRaster(ifP, bmpHeader, bmpRasterP, &pos); - warnIfBadFileSize(BMPheader, pos); - if (fgetc(ifP) != EOF) pm_message("warning: some image data remains unread."); - if (!isValidBmpBpp(BMPheader.cBitCount)) + if (!isValidBmpBpp(bmpHeader.cBitCount)) pm_error("Invalid BMP image: 'cBitCount' field of header " "(number of bits for each pixel in raster) is %u", - BMPheader.cBitCount); + bmpHeader.cBitCount); + + *cBitCountP = bmpHeader.cBitCount; - *colsP = BMPheader.cols; - *rowsP = BMPheader.rows; - *cBitCountP = BMPheader.cBitCount; - *pixelformatP = BMPheader.pixelformat; + *colsP = bmpHeader.cols; + *rowsP = bmpHeader.rows; + *pixelformatP = bmpHeader.pixelformat; *colormapP = colormap; } static void -writeRasterGen(unsigned char ** const BMPraster, +writeRasterGen(unsigned char ** const bmpRaster, int const cols, int const rows, int const format, @@ -1395,7 +1396,7 @@ writeRasterGen(unsigned char ** const BMPraster, xel const colormap[]) { /*---------------------------------------------------------------------------- Write the PNM raster to Standard Output, corresponding to the raw BMP - raster BMPraster. Write the raster assuming the PNM image has + raster bmpRaster. Write the raster assuming the PNM image has dimensions 'cols' by 'rows' and format 'format', with maxval 255. The BMP image has 'cBitCount' bits per pixel, arranged in format @@ -1412,7 +1413,7 @@ writeRasterGen(unsigned char ** const BMPraster, xelrow = pnm_allocrow(cols); for (row = 0; row < rows; ++row) { - convertRow(BMPraster[row], xelrow, cols, cBitCount, pixelformat, + convertRow(bmpRaster[row], xelrow, cols, cBitCount, pixelformat, colormap); pnm_writepnmrow(stdout, xelrow, cols, bmpMaxval, format, FALSE); } @@ -1422,13 +1423,13 @@ writeRasterGen(unsigned char ** const BMPraster, static void -writeRasterPbm(unsigned char ** const BMPraster, +writeRasterPbm(unsigned char ** const bmpRaster, int const cols, int const rows, xel const colormap[]) { /*---------------------------------------------------------------------------- Write the PBM raster to Standard Output corresponding to the raw BMP - raster BMPraster. Write the raster assuming the PBM image has + raster bmpRaster. Write the raster assuming the PBM image has dimensions 'cols' by 'rows'. The BMP image has 'cBitCount' bits per pixel, arranged in format @@ -1439,10 +1440,8 @@ writeRasterPbm(unsigned char ** const BMPraster, abnormal case in which colormap[0] and colormap[1] have the same value (i.e. both white or both black.) - We destroy *BMPraster as a side effect. + We destroy *bmpRaster as a side effect. -----------------------------------------------------------------------------*/ - unsigned int const charBits = (sizeof(unsigned char) * 8); - /* Number of bits in a character */ unsigned int const colChars = pbm_packed_bytes(cols); int row; @@ -1455,20 +1454,15 @@ writeRasterPbm(unsigned char ** const BMPraster, colorformat = BlackWhite; for (row=0; row < rows; ++row){ - unsigned char * const bitrow = BMPraster[row]; + unsigned char * const bitrow = bmpRaster[row]; if (colorformat == BlackWhite) { unsigned int i; for (i = 0; i < colChars; ++i) bitrow[i] = ~bitrow[i]; /* flip all pixels */ } - - if (cols % 8 > 0) { - /* adjust final partial byte */ - bitrow[colChars-1] >>= charBits - cols % charBits; - bitrow[colChars-1] <<= charBits - cols % charBits; - } - + + pbm_cleanrowend_packed(bitrow, cols); pbm_writepbmrow_packed(stdout, bitrow, cols, FALSE); } } @@ -1476,9 +1470,9 @@ writeRasterPbm(unsigned char ** const BMPraster, int -main(int argc, char ** argv) { +main(int argc, const char ** argv) { - struct cmdline_info cmdline; + struct cmdlineInfo cmdline; FILE * ifP; int outputType; @@ -1488,10 +1482,10 @@ main(int argc, char ** argv) { and gray. */ int cols, rows; - unsigned char **BMPraster; + unsigned char **bmpRaster; /* The raster part of the BMP image, as a row x column array, with each element being a raw byte from the BMP raster. Note that - BMPraster[0] is really Row 0 -- the top row of the image, even + bmpRaster[0] is really Row 0 -- the top row of the image, even though the bottom row comes first in the BMP format. */ unsigned int cBitCount; @@ -1503,17 +1497,17 @@ main(int argc, char ** argv) { undefined if not a colormapped BMP. */ - pnm_init(&argc, argv); + pm_proginit(&argc, argv); - parse_command_line(argc, argv, &cmdline); + parseCommandLine(argc, argv, &cmdline); - ifP = pm_openr(cmdline.input_filespec); - if (streq(cmdline.input_filespec, "-")) + ifP = pm_openr(cmdline.inputFileName); + if (streq(cmdline.inputFileName, "-")) ifname = "Standard Input"; else - ifname = cmdline.input_filespec; + ifname = cmdline.inputFileName; - readBmp(ifP, &BMPraster, &cols, &rows, &grayPresent, &colorPresent, + readBmp(ifP, &bmpRaster, &cols, &rows, &grayPresent, &colorPresent, &cBitCount, &pixelformat, &colormap, cmdline.verbose); pm_close(ifP); @@ -1531,14 +1525,14 @@ main(int argc, char ** argv) { if (outputType == PBM_TYPE && cBitCount == 1){ pbm_writepbminit(stdout, cols, rows, FALSE); - writeRasterPbm(BMPraster, cols, rows, colormap); + writeRasterPbm(bmpRaster, cols, rows, colormap); } else { pnm_writepnminit(stdout, cols, rows, bmpMaxval, outputType, FALSE); - writeRasterGen(BMPraster, cols, rows, outputType, cBitCount, + writeRasterGen(bmpRaster, cols, rows, outputType, cBitCount, pixelformat, colormap); } free(colormap); - free(BMPraster); + free(bmpRaster); return 0; } diff --git a/converter/other/cameratopam/Makefile b/converter/other/cameratopam/Makefile index 20a95aa2..d6207aea 100644 --- a/converter/other/cameratopam/Makefile +++ b/converter/other/cameratopam/Makefile @@ -9,7 +9,7 @@ EXTERN_INCLUDES = ifneq ($(JPEGLIB),NONE) ifneq ($(JPEGHDR_DIR)x,x) EXTERN_INCLUDES += -I$(JPEGHDR_DIR) - CFLAGS += -DHAVE_JPEG + HAVE_JPEG_DEFINE = -DHAVE_JPEG endif endif @@ -19,20 +19,20 @@ include $(BUILDDIR)/config.mk .PHONY: all all: cameratopam -OBJECTS = util.o identify.o cameratopam.o camera.o foveon.o decode.o \ +ADDL_OBJECTS = util.o identify.o camera.o foveon.o decode.o \ canon.o ljpeg.o dng.o -MERGE_OBJECTS = +OBJECTS = cameratopam.o $(ADDL_OBJECTS) -BINARIES = cameratopam -MERGEBINARIES = +camera.o camera.o2: CFLAGS_TARGET = $(HAVE_JPEG_DEFINE) + +MERGE_OBJECTS = cameratopam.o2 $(ADDL_OBJECTS) + +PORTBINARIES = cameratopam +BINARIES = $(PORTBINARIES) +MERGEBINARIES = cameratopam SCRIPTS = include $(SRCDIR)/common.mk -cameratopam: $(OBJECTS) $(NETPBMLIB) $(LIBOPT) - $(LD) -o $@ \ - $(OBJECTS) $(shell $(LIBOPT) $(NETPBMLIB) $(LIBOPTR)) \ - $(MATHLIB) $(LDFLAGS) $(LDLIBS) \ - $(RPATH) $(LADD) - +cameratopam: $(ADDL_OBJECTS) diff --git a/converter/other/cameratopam/camera.c b/converter/other/cameratopam/camera.c index 98d6d37a..a1adba95 100644 --- a/converter/other/cameratopam/camera.c +++ b/converter/other/cameratopam/camera.c @@ -12,10 +12,13 @@ #include #endif +#include "pm_config.h" #include "pm.h" #include "mallocvar.h" +#include "pm_c_util.h" #include "global_variables.h" +#include "cameratopam.h" #include "util.h" #include "decode.h" #include "bayer.h" @@ -54,67 +57,76 @@ merror (const void *ptr, const char *where) static void -adobe_copy_pixel (int row, int col, unsigned short **rp, bool use_secondary) -{ - unsigned r=row, c=col; - - if (fuji_secondary && use_secondary) (*rp)++; - if (filters) { - if (fuji_width) { - r = row + fuji_width - 1 - (col >> 1); - c = row + ((col+1) >> 1); - } - if (r < height && c < width) - BAYER(r,c) = **rp < 0x1000 ? curve[**rp] : **rp; - *rp += 1 + fuji_secondary; - } else - for (c=0; c < tiff_samples; c++) { - image[row*width+col][c] = **rp < 0x1000 ? curve[**rp] : **rp; - (*rp)++; +adobeCopyPixel(Image const image, + unsigned int const row, + unsigned int const col, + unsigned short ** const rp, + bool const useSecondary) { + + unsigned r=row, c=col; + + if (fuji_secondary && useSecondary) + ++(*rp); + if (filters) { + if (fuji_width) { + r = row + fuji_width - 1 - (col >> 1); + c = row + ((col+1) >> 1); + } + if (r < height && c < width) + BAYER(r,c) = **rp < 0x1000 ? curve[**rp] : **rp; + *rp += 1 + fuji_secondary; + } else { + unsigned int c; + for (c = 0; c < tiff_samples; ++c) { + image[row*width+col][c] = **rp < 0x1000 ? curve[**rp] : **rp; + ++(*rp); + } } - if (fuji_secondary && use_secondary) (*rp)--; + if (fuji_secondary && useSecondary) + --(*rp); } void -adobe_dng_load_raw_lj() -{ - int save, twide, trow=0, tcol=0, jrow, jcol; - struct jhead jh; - unsigned short *rp; +adobe_dng_load_raw_lj(Image const image) { - while (1) { - save = ftell(ifp); - fseek (ifp, get4(ifp), SEEK_SET); - if (!ljpeg_start (ifp, &jh)) break; - if (trow >= raw_height) break; - if (jh.high > raw_height-trow) - jh.high = raw_height-trow; - twide = jh.wide; - if (filters) twide *= jh.clrs; - else colors = jh.clrs; - if (fuji_secondary) twide /= 2; - if (twide > raw_width-tcol) - twide = raw_width-tcol; - - for (jrow=0; jrow < jh.high; jrow++) { - ljpeg_row (&jh); - for (rp=jh.row, jcol=0; jcol < twide; jcol++) - adobe_copy_pixel (trow+jrow, tcol+jcol, &rp, use_secondary); - } - fseek (ifp, save+4, SEEK_SET); - if ((tcol += twide) >= raw_width) { - tcol = 0; - trow += jh.high; + int save, twide, trow=0, tcol=0, jrow, jcol; + struct jhead jh; + unsigned short *rp; + + while (1) { + save = ftell(ifp); + fseek (ifp, get4(ifp), SEEK_SET); + if (!ljpeg_start (ifp, &jh)) break; + if (trow >= raw_height) break; + if (jh.high > raw_height-trow) + jh.high = raw_height-trow; + twide = jh.wide; + if (filters) twide *= jh.clrs; + else colors = jh.clrs; + if (fuji_secondary) twide /= 2; + if (twide > raw_width-tcol) + twide = raw_width-tcol; + + for (jrow=0; jrow < jh.high; jrow++) { + ljpeg_row(ifp, &jh); + for (rp=jh.row, jcol=0; jcol < twide; jcol++) + adobeCopyPixel(image, + trow+jrow, tcol+jcol, &rp, use_secondary); + } + fseek (ifp, save+4, SEEK_SET); + if ((tcol += twide) >= raw_width) { + tcol = 0; + trow += jh.high; + } + free (jh.row); } - free (jh.row); - } } void -adobe_dng_load_raw_nc() -{ +adobe_dng_load_raw_nc(Image const image) { + unsigned short *pixel, *rp; int row, col; @@ -123,7 +135,7 @@ adobe_dng_load_raw_nc() for (row=0; row < raw_height; row++) { read_shorts (ifp, pixel, raw_width * tiff_samples); for (rp=pixel, col=0; col < raw_width; col++) - adobe_copy_pixel (row, col, &rp, use_secondary); + adobeCopyPixel(image, row, col, &rp, use_secondary); } free (pixel); } @@ -133,8 +145,8 @@ adobe_dng_load_raw_nc() static int nikon_curve_offset; void -nikon_compressed_load_raw(void) -{ +nikon_compressed_load_raw(Image const image) { + static const unsigned char nikon_tree[] = { 0,1,5,1,1,1,1,1,1,2,0,0,0,0,0,0, 5,4,3,6,2,7,1,0,8,9,11,10,12 @@ -158,7 +170,7 @@ nikon_compressed_load_raw(void) for (row=0; row < height; row++) for (col=0; col < raw_width; col++) { - diff = ljpeg_diff (first_decode); + diff = ljpeg_diff (ifp, first_decode); if (col < 2) { i = 2*(row & 1) + (col & 1); vpred[i] += diff; @@ -175,8 +187,8 @@ nikon_compressed_load_raw(void) } void -nikon_load_raw() -{ +nikon_load_raw(Image const image) { + int irow, row, col, i; getbits(ifp, -1); @@ -293,8 +305,8 @@ minolta_z2() } void -nikon_e2100_load_raw() -{ +nikon_e2100_load_raw(Image const image) { + unsigned char data[3432], *dp; unsigned short pixel[2288], *pix; int row, col; @@ -321,8 +333,8 @@ nikon_e2100_load_raw() } void -nikon_e950_load_raw() -{ +nikon_e950_load_raw(Image const image) { + int irow, row, col; getbits(ifp, -1); @@ -340,8 +352,7 @@ nikon_e950_load_raw() The Fuji Super CCD is just a Bayer grid rotated 45 degrees. */ void -fuji_s2_load_raw() -{ +fuji_s2_load_raw(Image const image) { unsigned short pixel[2944]; int row, col, r, c; @@ -357,8 +368,7 @@ fuji_s2_load_raw() } void -fuji_s3_load_raw() -{ +fuji_s3_load_raw(Image const image) { unsigned short pixel[4352]; int row, col, r, c; @@ -373,42 +383,52 @@ fuji_s3_load_raw() } } -static void fuji_common_load_raw (int ncol, int icol, int nrow) -{ - unsigned short pixel[2048]; - int row, col, r, c; - - for (row=0; row < nrow; row++) { - read_shorts(ifp, pixel, ncol); - for (col=0; col <= icol; col++) { - r = icol - col + (row >> 1); - c = col + ((row+1) >> 1); - BAYER(r,c) = pixel[col]; +static void +fuji_common_load_raw(Image const image, + unsigned int const ncol, + unsigned int const icol, + unsigned int const nrow) { + + unsigned short pixel[2048]; + unsigned int row; + + for (row = 0; row < nrow; ++row) { + unsigned int col; + read_shorts(ifp, pixel, ncol); + for (col = 0; col <= icol; ++col) { + int const r = icol - col + (row >> 1); + int const c = col + ((row+1) >> 1); + BAYER(r,c) = pixel[col]; + } } - } } + + void -fuji_s5000_load_raw() -{ +fuji_s5000_load_raw(Image const image) { + fseek (ifp, (1472*4+24)*2, SEEK_CUR); - fuji_common_load_raw (1472, 1423, 2152); + fuji_common_load_raw(image, 1472, 1423, 2152); } + + void -fuji_s7000_load_raw() -{ - fuji_common_load_raw (2048, 2047, 3080); +fuji_s7000_load_raw(Image const image) { + + fuji_common_load_raw(image, 2048, 2047, 3080); } + + /* The Fuji Super CCD SR has two photodiodes for each pixel. The secondary has about 1/16 the sensitivity of the primary, but this ratio may vary. */ void -fuji_f700_load_raw() -{ +fuji_f700_load_raw(Image const image) { unsigned short pixel[2944]; int row, col, r, c, val; @@ -424,8 +444,7 @@ fuji_f700_load_raw() } void -rollei_load_raw() -{ +rollei_load_raw(Image const image) { unsigned char pixel[10]; unsigned iten=0, isix, i, buffer=0, row, col, todo[16]; @@ -451,8 +470,7 @@ rollei_load_raw() } void -phase_one_load_raw() -{ +phase_one_load_raw(Image const image) { int row, col, a, b; unsigned short *pixel, akey, bkey; @@ -478,8 +496,7 @@ phase_one_load_raw() } void -ixpress_load_raw() -{ +ixpress_load_raw(Image const image) { unsigned short pixel[4090]; int row, col; @@ -493,8 +510,7 @@ ixpress_load_raw() } void -leaf_load_raw() -{ +leaf_load_raw(Image const image) { unsigned short *pixel; int r, c, row, col; @@ -513,8 +529,7 @@ leaf_load_raw() For this function only, raw_width is in bytes, not pixels! */ void -packed_12_load_raw() -{ +packed_12_load_raw(Image const image) { int row, col; getbits(ifp, -1); @@ -527,8 +542,7 @@ packed_12_load_raw() } void -unpacked_load_raw() -{ +unpacked_load_raw(Image const image) { unsigned short *pixel; int row, col; @@ -543,8 +557,7 @@ unpacked_load_raw() } void -olympus_e300_load_raw() -{ +olympus_e300_load_raw(Image const image) { unsigned char *data, *dp; unsigned short *pixel, *pix; int dwide, row, col; @@ -567,8 +580,7 @@ olympus_e300_load_raw() } void -olympus_cseries_load_raw() -{ +olympus_cseries_load_raw(Image const image) { int irow, row, col; for (irow=0; irow < height; irow++) { @@ -583,8 +595,7 @@ olympus_cseries_load_raw() } void -eight_bit_load_raw() -{ +eight_bit_load_raw(Image const image) { unsigned char *pixel; int row, col; @@ -600,8 +611,7 @@ eight_bit_load_raw() } void -casio_qv5700_load_raw() -{ +casio_qv5700_load_raw(Image const image) { unsigned char data[3232], *dp; unsigned short pixel[2576], *pix; int row, col; @@ -621,8 +631,7 @@ casio_qv5700_load_raw() } void -nucore_load_raw() -{ +nucore_load_raw(Image const image) { unsigned short *pixel; int irow, row, col; @@ -684,79 +693,91 @@ static int radc_token (int tree) : (buf[c][y-1][x+1] + 2*buf[c][y-1][x] + buf[c][y][x+1]) / 4) void -kodak_radc_load_raw() -{ - int row, col, tree, nreps, rep, step, i, c, s, r, x, y, val; - short last[3] = { 16,16,16 }, mul[3], buf[3][3][386]; +kodak_radc_load_raw(Image const image) { + int row, col, tree, nreps, rep, step, c, s, r, x, y, val; + unsigned int i; + short last[3] = { 16,16,16 }, mul[3], buf[3][3][386]; - init_decoder(); - getbits(ifp, -1); - for (i=0; i < sizeof(buf)/sizeof(short); i++) - buf[0][0][i] = 2048; - for (row=0; row < height; row+=4) { - for (i=0; i < 3; i++) - mul[i] = getbits(ifp, 6); - FORC3 { - val = ((0x1000000/last[c] + 0x7ff) >> 12) * mul[c]; - s = val > 65564 ? 10:12; - x = ~(-1 << (s-1)); - val <<= 12-s; - for (i=0; i < sizeof(buf[0])/sizeof(short); i++) - buf[c][0][i] = (buf[c][0][i] * val + x) >> s; - last[c] = mul[c]; - for (r=0; r <= !c; r++) { - buf[c][1][width/2] = buf[c][2][width/2] = mul[c] << 7; - for (tree=1, col=width/2; col > 0; ) { - if ((tree = radc_token(tree))) { - col -= 2; - if (tree == 8) - FORYX buf[c][y][x] = radc_token(tree+10) * mul[c]; - else - FORYX buf[c][y][x] = radc_token(tree+10) * 16 + PREDICTOR; - } else - do { - nreps = (col > 2) ? radc_token(9) + 1 : 1; - for (rep=0; rep < 8 && rep < nreps && col > 0; rep++) { - col -= 2; - FORYX buf[c][y][x] = PREDICTOR; - if (rep & 1) { - step = radc_token(10) << 4; - FORYX buf[c][y][x] += step; + init_decoder(); + getbits(ifp, -1); + for (i = 0; i < ARRAY_SIZE(buf); ++i) { + unsigned int j; + for (j = 0; j < ARRAY_SIZE(buf[0]); ++j) { + unsigned int k; + for (k = 0; k < ARRAY_SIZE(buf[0][0]); ++k) + buf[i][j][k] = 2048; } - } - } while (nreps == 9); - } - for (y=0; y < 2; y++) - for (x=0; x < width/2; x++) { - val = (buf[c][y+1][x] << 4) / mul[c]; - if (val < 0) val = 0; - if (c) - BAYER(row+y*2+c-1,x*2+2-c) = val; - else - BAYER(row+r*2+y,x*2+y) = val; - } - memcpy (buf[c][0]+!c, buf[c][2], sizeof buf[c][0]-2*!c); - } - } - for (y=row; y < row+4; y++) - for (x=0; x < width; x++) - if ((x+y) & 1) { - val = (BAYER(y,x)-2048)*2 + (BAYER(y,x-1)+BAYER(y,x+1))/2; - if (val < 0) val = 0; - BAYER(y,x) = val; } - } - maximum = 0x1fff; /* wild guess */ + for (row=0; row < height; row+=4) { + unsigned int i; + for (i = 0; i < 3; ++i) + mul[i] = getbits(ifp, 6); + FORC3 { + val = ((0x1000000/last[c] + 0x7ff) >> 12) * mul[c]; + s = val > 65564 ? 10:12; + x = ~(-1 << (s-1)); + val <<= 12-s; + for (i=0; i < ARRAY_SIZE(buf[c][0]); i++) + buf[c][0][i] = (buf[c][0][i] * val + x) >> s; + last[c] = mul[c]; + for (r=0; r <= !c; r++) { + buf[c][1][width/2] = buf[c][2][width/2] = mul[c] << 7; + for (tree=1, col=width/2; col > 0; ) { + if ((tree = radc_token(tree))) { + col -= 2; + if (tree == 8) + FORYX buf[c][y][x] = + radc_token(tree+10) * mul[c]; + else + FORYX buf[c][y][x] = + radc_token(tree+10) * 16 + PREDICTOR; + } else + do { + nreps = (col > 2) ? radc_token(9) + 1 : 1; + for (rep=0; + rep < 8 && rep < nreps && col > 0; + rep++) { + col -= 2; + FORYX buf[c][y][x] = PREDICTOR; + if (rep & 1) { + step = radc_token(10) << 4; + FORYX buf[c][y][x] += step; + } + } + } while (nreps == 9); + } + for (y=0; y < 2; y++) + for (x=0; x < width/2; x++) { + val = (buf[c][y+1][x] << 4) / mul[c]; + if (val < 0) val = 0; + if (c) + BAYER(row+y*2+c-1,x*2+2-c) = val; + else + BAYER(row+r*2+y,x*2+y) = val; + } + memcpy (buf[c][0]+!c, buf[c][2], sizeof buf[c][0]-2*!c); + } + } + for (y=row; y < row+4; y++) + for (x=0; x < width; x++) + if ((x+y) & 1) { + val = (BAYER(y,x)-2048)*2 + (BAYER(y,x-1)+BAYER(y,x+1))/2; + if (val < 0) val = 0; + BAYER(y,x) = val; + } + } + maximum = 0x1fff; /* wild guess */ } #undef FORYX #undef PREDICTOR #ifndef HAVE_JPEG -void kodak_jpeg_load_raw() {} +void +kodak_jpeg_load_raw(Image const Image) {} #else -static boolean +static bool fill_input_buffer (j_decompress_ptr cinfo) { static char jpeg_buffer[4096]; @@ -770,7 +791,7 @@ fill_input_buffer (j_decompress_ptr cinfo) } void -kodak_jpeg_load_raw() +kodak_jpeg_load_raw(Image const image) { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; @@ -811,7 +832,7 @@ kodak_jpeg_load_raw() #endif void -kodak_dc120_load_raw() +kodak_dc120_load_raw(Image const image) { static const int mul[4] = { 162, 192, 187, 92 }; static const int add[4] = { 0, 636, 424, 212 }; @@ -847,7 +868,7 @@ kodak_dc20_coeff (float const juice) } void -kodak_easy_load_raw() +kodak_easy_load_raw(Image const image) { unsigned char *pixel; unsigned row, col, icol; @@ -875,7 +896,7 @@ kodak_easy_load_raw() } void -kodak_compressed_load_raw() +kodak_compressed_load_raw(Image const image) { unsigned char c, blen[256]; unsigned short raw[6]; @@ -939,7 +960,7 @@ kodak_compressed_load_raw() } void -kodak_yuv_load_raw() +kodak_yuv_load_raw(Image const image) { unsigned char c, blen[384]; unsigned row, col, len, bits=0; @@ -1030,7 +1051,7 @@ static void sony_decrypt (unsigned *data, int len, int start, int key) } void -sony_load_raw() +sony_load_raw(Image const image) { unsigned char head[40]; struct pixel { @@ -1298,12 +1319,6 @@ parse_mos(FILE * const ifp, fread (data, 1, 40, ifp); skip = get4(ifp); from = ftell(ifp); -#ifdef USE_LCMS - if (!strcmp(data,"icc_camera_profile")) { - profile_length = skip; - profile_offset = from; - } -#endif if (!strcmp(data,"NeutObj_neutrals")) { for (i=0; i < 4; i++) fscanf (ifp, "%d", neut+i); diff --git a/converter/other/cameratopam/camera.h b/converter/other/cameratopam/camera.h index a1e884cf..02c3f2af 100644 --- a/converter/other/cameratopam/camera.h +++ b/converter/other/cameratopam/camera.h @@ -1,5 +1,10 @@ +#ifndef CAMERA_H_INCLUDED +#define CAMERA_H_INCLUDED + #include +#include "cameratopam.h" + void parse_ciff(FILE * const ifp, int const offset, @@ -21,20 +26,18 @@ void parse_mos(FILE * const ifp, int const offset); -void -adobe_dng_load_raw_lj(void); +typedef void LoadRawFn(Image const image); -void -adobe_dng_load_raw_nc(void); +LoadRawFn adobe_dng_load_raw_lj; + +LoadRawFn adobe_dng_load_raw_nc; int nikon_is_compressed(void); -void -nikon_compressed_load_raw(void); +LoadRawFn nikon_compressed_load_raw; -void -nikon_e950_load_raw(void); +LoadRawFn nikon_e950_load_raw; void nikon_e950_coeff(void); @@ -45,87 +48,63 @@ nikon_e990(void); int nikon_e2100(void); -void -nikon_e2100_load_raw(void); +LoadRawFn nikon_e2100_load_raw; int minolta_z2(void); -void -fuji_s2_load_raw(void); +LoadRawFn fuji_s2_load_raw; -void -fuji_s3_load_raw(void); +LoadRawFn fuji_s3_load_raw; -void -fuji_s5000_load_raw(void); +LoadRawFn fuji_s5000_load_raw; -void -unpacked_load_raw(void); +LoadRawFn unpacked_load_raw; -void -fuji_s7000_load_raw(void); +LoadRawFn fuji_s7000_load_raw; -void -fuji_f700_load_raw(void); +LoadRawFn fuji_f700_load_raw; -void -packed_12_load_raw(void); +LoadRawFn packed_12_load_raw; -void -eight_bit_load_raw(void); +LoadRawFn eight_bit_load_raw; -void -phase_one_load_raw(void); +LoadRawFn phase_one_load_raw; -void -ixpress_load_raw(void); +LoadRawFn ixpress_load_raw; -void -leaf_load_raw(void); +LoadRawFn leaf_load_raw; -void -olympus_e300_load_raw(void); +LoadRawFn olympus_e300_load_raw; -void -olympus_cseries_load_raw(void); +LoadRawFn olympus_cseries_load_raw; -void -sony_load_raw(void); +LoadRawFn sony_load_raw; -void -kodak_easy_load_raw(void); +LoadRawFn kodak_easy_load_raw; -void -kodak_compressed_load_raw(void); +LoadRawFn kodak_compressed_load_raw; -void -kodak_yuv_load_raw(void); +LoadRawFn kodak_yuv_load_raw; void kodak_dc20_coeff (float const juice); -void -kodak_radc_load_raw(void); +LoadRawFn kodak_radc_load_raw; -void -kodak_jpeg_load_raw(void); +LoadRawFn kodak_jpeg_load_raw; -void -kodak_dc120_load_raw(void); +LoadRawFn kodak_dc120_load_raw; -void -rollei_load_raw(void); +LoadRawFn rollei_load_raw; -void -casio_qv5700_load_raw(void); +LoadRawFn casio_qv5700_load_raw; -void -nucore_load_raw(void); +LoadRawFn nucore_load_raw; -void -nikon_load_raw(void); +LoadRawFn nikon_load_raw; int pentax_optio33(void); +#endif diff --git a/converter/other/cameratopam/cameratopam.c b/converter/other/cameratopam/cameratopam.c index b2d6da9b..ec33dd31 100644 --- a/converter/other/cameratopam/cameratopam.c +++ b/converter/other/cameratopam/cameratopam.c @@ -7,8 +7,11 @@ */ -#define _BSD_SOURCE 1 /* Make sure string.h contains strcasecmp() */ -#define _XOPEN_SOURCE /* Make sure unistd.h contains swab() */ +#define _BSD_SOURCE 1 /* Make sure string.h contains strdup() */ +#define _XOPEN_SOURCE 500 + /* Make sure unistd.h contains swab(), string.h constains strdup() */ + +#include "pm_config.h" #include #include @@ -23,10 +26,10 @@ #include #include -#ifdef __CYGWIN__ +#ifdef HAVE_IO_H #include #endif -#if !defined(WIN32) || defined(__CYGWIN__) +#if !MSVCRT #include #endif @@ -36,6 +39,7 @@ #include "pam.h" #include "global_variables.h" +#include "cameratopam.h" #include "util.h" #include "decode.h" #include "identify.h" @@ -59,22 +63,19 @@ int height, width, fuji_width, colors, tiff_samples; int black, maximum, clip_max; int iheight, iwidth, shrink; int is_dng, is_canon, is_foveon, use_coeff, use_gamma; -int trim, flip, xmag, ymag; +int flip, xmag, ymag; int zero_after_ff; unsigned filters; -unsigned short (*image)[4], white[8][8], curve[0x1000]; +unsigned short white[8][8]; +unsigned short curve[0x1000]; int fuji_secondary; -float cam_mul[4], pre_mul[4], coeff[3][4]; +float cam_mul[4], coeff[3][4]; +float pre_mul[4]; int histogram[3][0x2000]; jmp_buf failure; -bool use_secondary; +int use_secondary; bool verbose; -#ifdef USE_LCMS -#include -int profile_offset, profile_length; -#endif - #define CLASS #define FORC3 for (c=0; c < 3; c++) @@ -86,7 +87,7 @@ static void CLASS merror (const void *ptr, const char *where) pm_error ("Out of memory in %s", where); } -struct cmdlineInfo { +struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ @@ -110,11 +111,11 @@ struct cmdlineInfo { }; -static struct cmdlineInfo cmdline; +static struct CmdlineInfo cmdline; static void parseCommandLine(int argc, char ** argv, - struct cmdlineInfo *cmdlineP) { + struct CmdlineInfo *cmdlineP) { /*---------------------------------------------------------------------------- Note that many of the strings that this function returns in the *cmdlineP structure are actually in the supplied argv array. And @@ -167,7 +168,7 @@ parseCommandLine(int argc, char ** argv, OPTENT3(0, "linear", OPT_FLAG, NULL, &cmdlineP->linear, 0); - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); if (!brightSpec) cmdlineP->bright = 1.0; @@ -189,615 +190,694 @@ parseCommandLine(int argc, char ** argv, } -/* - Seach from the current directory up to the root looking for - a ".badpixels" file, and fix those pixels now. - */ -static void CLASS bad_pixels() -{ - FILE *fp=NULL; - char *fname, *cp, line[128]; - int len, time, row, col, r, c, rad, tot, n, fixed=0; - - if (!filters) return; - for (len=16 ; ; len *= 2) { - fname = malloc (len); - if (!fname) return; - if (getcwd (fname, len-12)) break; - free (fname); - if (errno != ERANGE) return; - } -#ifdef WIN32 - if (fname[1] == ':') - memmove (fname, fname+2, len-2); - for (cp=fname; *cp; cp++) - if (*cp == '\\') *cp = '/'; + +static void CLASS +fixBadPixels(Image const image) { +/*---------------------------------------------------------------------------- + Search from the current directory up to the root looking for + a ".badpixels" file, and fix those pixels now. +-----------------------------------------------------------------------------*/ + if (filters) { + FILE *fp; + char *fname, *cp, line[128]; + int len, time, row, col, rad, tot, n, fixed=0; + + for (len=16 ; ; len *= 2) { + fname = malloc (len); + if (!fname) return; + if (getcwd (fname, len-12)) + break; + free (fname); + if (errno != ERANGE) + return; + } +#if MSVCRT + if (fname[1] == ':') + memmove (fname, fname+2, len-2); + for (cp=fname; *cp; cp++) + if (*cp == '\\') *cp = '/'; #endif - cp = fname + strlen(fname); - if (cp[-1] == '/') cp--; - while (*fname == '/') { - strcpy (cp, "/.badpixels"); - if ((fp = fopen (fname, "r"))) break; - if (cp == fname) break; - while (*--cp != '/'); - } - free (fname); - if (!fp) return; - while (fgets (line, 128, fp)) { - cp = strchr (line, '#'); - if (cp) *cp = 0; - if (sscanf (line, "%d %d %d", &col, &row, &time) != 3) continue; - if ((unsigned) col >= width || (unsigned) row >= height) continue; - if (time > timestamp) continue; - for (tot=n=0, rad=1; rad < 3 && n==0; rad++) - for (r = row-rad; r <= row+rad; r++) - for (c = col-rad; c <= col+rad; c++) - if ((unsigned) r < height && (unsigned) c < width && - (r != row || c != col) && FC(r,c) == FC(row,col)) { - tot += BAYER(r,c); - n++; - } - BAYER(row,col) = tot/n; - if (cmdline.verbose) { - if (!fixed++) - pm_message ("Fixed bad pixels at: %d,%d", col, row); + cp = fname + strlen(fname); + if (cp[-1] == '/') + --cp; + fp = NULL; /* initial value */ + while (*fname == '/') { + strcpy (cp, "/.badpixels"); + fp = fopen (fname, "r"); + if (fp) + break; + if (cp == fname) + break; + while (*--cp != '/'); + } + free (fname); + if (fp) { + while (fgets (line, 128, fp)) { + char * cp; + cp = strchr (line, '#'); + if (cp) *cp = 0; + if (sscanf (line, "%d %d %d", &col, &row, &time) != 3) + continue; + if ((unsigned) col >= width || (unsigned) row >= height) + continue; + if (time > timestamp) continue; + for (tot=n=0, rad=1; rad < 3 && n==0; rad++) { + unsigned int r; + for (r = row-rad; r <= row+rad; ++r) { + unsigned int c; + for (c = col-rad; c <= col+rad; ++c) { + if ((unsigned) r < height && + (unsigned) c < width && + (r != row || c != col) && + FC(r,c) == FC(row,col)) { + tot += BAYER(r,c); + ++n; + } + } + } + } + BAYER(row,col) = tot/n; + if (cmdline.verbose) { + if (!fixed++) + pm_message ("Fixed bad pixels at: %d,%d", col, row); + } + } + fclose (fp); + } } - } - fclose (fp); } -static void CLASS scale_colors() -{ - int row, col, c, val, shift=0; - int min[4], max[4], count[4]; - double sum[4], dmin; - - maximum -= black; - if (cmdline.use_auto_wb || (cmdline.use_camera_wb && camera_red == -1)) { - FORC4 min[c] = INT_MAX; - FORC4 max[c] = count[c] = sum[c] = 0; - for (row=0; row < height; row++) - for (col=0; col < width; col++) - FORC4 { - val = image[row*width+col][c]; - if (!val) continue; - if (min[c] > val) min[c] = val; - if (max[c] < val) max[c] = val; - val -= black; - if (val > maximum-25) continue; - if (val < 0) val = 0; - sum[c] += val; - count[c]++; + + +static void CLASS +scaleColors(Image const image) { + + int row; + int c; + int val; + int shift; + int min[4], max[4], count[4]; + double sum[4], dmin; + int scaleMax; + + scaleMax = maximum - black; /* initial value */ + if (cmdline.use_auto_wb || (cmdline.use_camera_wb && camera_red == -1)) { + unsigned int row; + FORC4 min [c] = INT_MAX; + FORC4 max [c] = 0; + FORC4 count[c] = 0; + FORC4 sum [c] = 0; + for (row = 0; row < height; ++row) { + unsigned int col; + for (col = 0; col < width; ++col) { + FORC4 { + int val; + val = image[row*width+col][c]; + if (val != 0) { + if (min[c] > val) + min[c] = val; + if (max[c] < val) + max[c] = val; + val -= black; + if (val <= scaleMax-25) { + sum [c] += MAX(0, val); + count[c] += 1; + } + } + } + } + } + FORC4 pre_mul[c] = count[c] / sum[c]; } - FORC4 pre_mul[c] = count[c] / sum[c]; - } - if (cmdline.use_camera_wb && camera_red != -1) { - FORC4 count[c] = sum[c] = 0; - for (row=0; row < 8; row++) - for (col=0; col < 8; col++) { - c = FC(row,col); - if ((val = white[row][col] - black) > 0) - sum[c] += val; - count[c]++; - } - val = 1; - FORC4 if (sum[c] == 0) val = 0; - if (val) - FORC4 pre_mul[c] = count[c] / sum[c]; - else if (camera_red && camera_blue) - memcpy (pre_mul, cam_mul, sizeof pre_mul); - else - pm_message ("Cannot use camera white balance."); - } - if (!use_coeff) { - pre_mul[0] *= cmdline.red_scale; - pre_mul[2] *= cmdline.blue_scale; - } - dmin = DBL_MAX; - FORC4 if (dmin > pre_mul[c]) + if (cmdline.use_camera_wb && camera_red != -1) { + unsigned int row; + FORC4 count[c] = sum[c] = 0; + for (row = 0; row < 8; ++row) { + unsigned int col; + for (col = 0; col < 8; ++col) { + c = FC(row,col); + if ((val = white[row][col] - black) > 0) + sum[c] += val; + ++count[c]; + } + } + val = 1; + FORC4 if (sum[c] == 0) val = 0; + if (val) + FORC4 pre_mul[c] = count[c] / sum[c]; + else if (camera_red && camera_blue) + memcpy(pre_mul, cam_mul, sizeof pre_mul); + else + pm_message ("Cannot use camera white balance."); + } + if (!use_coeff) { + pre_mul[0] *= cmdline.red_scale; + pre_mul[2] *= cmdline.blue_scale; + } + dmin = DBL_MAX; + FORC4 if (dmin > pre_mul[c]) dmin = pre_mul[c]; - FORC4 pre_mul[c] /= dmin; - - while (maximum << shift < 0x8000) shift++; - FORC4 pre_mul[c] *= 1 << shift; - maximum <<= shift; - - if (cmdline.linear || cmdline.bright < 1) { - maximum *= cmdline.bright; - if (maximum > 0xffff) - maximum = 0xffff; - FORC4 pre_mul[c] *= cmdline.bright; - } - if (cmdline.verbose) { - fprintf (stderr, "Scaling with black=%d, pre_mul[] =", black); - FORC4 fprintf (stderr, " %f", pre_mul[c]); - fputc ('\n', stderr); - } - clip_max = cmdline.no_clip_color ? 0xffff : maximum; - for (row=0; row < height; row++) - for (col=0; col < width; col++) - FORC4 { - val = image[row*width+col][c]; - if (!val) continue; - val -= black; - val *= pre_mul[c]; - if (val < 0) val = 0; - if (val > clip_max) val = clip_max; - image[row*width+col][c] = val; - } -} - -/* - This algorithm is officially called: + FORC4 pre_mul[c] /= dmin; - "Interpolation using a Threshold-based variable number of gradients" + for (shift = 0; scaleMax << shift < 0x8000; ++shift); - described in http://www-ise.stanford.edu/~tingchen/algodep/vargra.html + FORC4 pre_mul[c] *= 1 << shift; + scaleMax <<= shift; - I've extended the basic idea to work with non-Bayer filter arrays. - Gradients are numbered clockwise from NW=0 to W=7. - */ -static void CLASS vng_interpolate() -{ - static const signed char *cp, terms[] = { - -2,-2,+0,-1,0,(char)0x01, -2,-2,+0,+0,1,(char)0x01, -2,-1,-1,+0,0,(char)0x01, - -2,-1,+0,-1,0,(char)0x02, -2,-1,+0,+0,0,(char)0x03, -2,-1,+0,+1,1,(char)0x01, - -2,+0,+0,-1,0,(char)0x06, -2,+0,+0,+0,1,(char)0x02, -2,+0,+0,+1,0,(char)0x03, - -2,+1,-1,+0,0,(char)0x04, -2,+1,+0,-1,1,(char)0x04, -2,+1,+0,+0,0,(char)0x06, - -2,+1,+0,+1,0,(char)0x02, -2,+2,+0,+0,1,(char)0x04, -2,+2,+0,+1,0,(char)0x04, - -1,-2,-1,+0,0,(char)0x80, -1,-2,+0,-1,0,(char)0x01, -1,-2,+1,-1,0,(char)0x01, - -1,-2,+1,+0,1,(char)0x01, -1,-1,-1,+1,0,(char)0x88, -1,-1,+1,-2,0,(char)0x40, - -1,-1,+1,-1,0,(char)0x22, -1,-1,+1,+0,0,(char)0x33, -1,-1,+1,+1,1,(char)0x11, - -1,+0,-1,+2,0,(char)0x08, -1,+0,+0,-1,0,(char)0x44, -1,+0,+0,+1,0,(char)0x11, - -1,+0,+1,-2,1,(char)0x40, -1,+0,+1,-1,0,(char)0x66, -1,+0,+1,+0,1,(char)0x22, - -1,+0,+1,+1,0,(char)0x33, -1,+0,+1,+2,1,(char)0x10, -1,+1,+1,-1,1,(char)0x44, - -1,+1,+1,+0,0,(char)0x66, -1,+1,+1,+1,0,(char)0x22, -1,+1,+1,+2,0,(char)0x10, - -1,+2,+0,+1,0,(char)0x04, -1,+2,+1,+0,1,(char)0x04, -1,+2,+1,+1,0,(char)0x04, - +0,-2,+0,+0,1,(char)0x80, +0,-1,+0,+1,1,(char)0x88, +0,-1,+1,-2,0,(char)0x40, - +0,-1,+1,+0,0,(char)0x11, +0,-1,+2,-2,0,(char)0x40, +0,-1,+2,-1,0,(char)0x20, - +0,-1,+2,+0,0,(char)0x30, +0,-1,+2,+1,1,(char)0x10, +0,+0,+0,+2,1,(char)0x08, - +0,+0,+2,-2,1,(char)0x40, +0,+0,+2,-1,0,(char)0x60, +0,+0,+2,+0,1,(char)0x20, - +0,+0,+2,+1,0,(char)0x30, +0,+0,+2,+2,1,(char)0x10, +0,+1,+1,+0,0,(char)0x44, - +0,+1,+1,+2,0,(char)0x10, +0,+1,+2,-1,1,(char)0x40, +0,+1,+2,+0,0,(char)0x60, - +0,+1,+2,+1,0,(char)0x20, +0,+1,+2,+2,0,(char)0x10, +1,-2,+1,+0,0,(char)0x80, - +1,-1,+1,+1,0,(char)0x88, +1,+0,+1,+2,0,(char)0x08, +1,+0,+2,-1,0,(char)0x40, - +1,+0,+2,+1,0,(char)0x10 - }, chood[] = { -1,-1, -1,0, -1,+1, 0,+1, +1,+1, +1,0, +1,-1, 0,-1 }; - unsigned short (*brow[5])[4], *pix; - int code[8][2][320], *ip, gval[8], gmin, gmax, sum[4]; - int row, col, shift, x, y, x1, x2, y1, y2, t, weight, grads, color, diag; - int g, diff, thold, num, c; - - for (row=0; row < 8; row++) { /* Precalculate for bilinear */ - for (col=1; col < 3; col++) { - ip = code[row][col & 1]; - memset (sum, 0, sizeof sum); - for (y=-1; y <= 1; y++) - for (x=-1; x <= 1; x++) { - shift = (y==0) + (x==0); - if (shift == 2) continue; - color = FC(row+y,col+x); - *ip++ = (width*y + x)*4 + color; - *ip++ = shift; - *ip++ = color; - sum[color] += 1 << shift; - } - FORC4 - if (c != FC(row,col)) { - *ip++ = c; - *ip++ = sum[c]; + if (cmdline.linear || cmdline.bright < 1) { + scaleMax = MIN(0xffff, scaleMax * cmdline.bright); + FORC4 pre_mul[c] *= cmdline.bright; } + if (cmdline.verbose) { + fprintf(stderr, "Scaling with black=%d, ", black); + fprintf(stderr, "pre_mul[] = "); + FORC4 fprintf (stderr, " %f", pre_mul[c]); + fprintf(stderr, "\n"); } - } - for (row=1; row < height-1; row++) { /* Do bilinear interpolation */ - for (col=1; col < width-1; col++) { - pix = image[row*width+col]; - ip = code[row & 7][col & 1]; - memset (sum, 0, sizeof sum); - for (g=8; g--; ) { - diff = pix[*ip++]; - diff <<= *ip++; - sum[*ip++] += diff; - } - for (g=colors; --g; ) { - c = *ip++; - pix[c] = sum[c] / *ip++; - } + clip_max = cmdline.no_clip_color ? 0xffff : scaleMax; + for (row = 0; row < height; ++row) { + unsigned int col; + for (col = 0; col < width; ++col) { + unsigned int c; + for (c = 0; c < colors; ++c) { + int val; + val = image[row*width+col][c]; + if (val != 0) { + val -= black; + val *= pre_mul[c]; + image[row*width+col][c] = MAX(0, MIN(clip_max, val)); + } + } + } } - } - if (cmdline.quick_interpolate) - return; - - for (row=0; row < 8; row++) { /* Precalculate for VNG */ - for (col=0; col < 2; col++) { - ip = code[row][col]; - for (cp=terms, t=0; t < 64; t++) { - y1 = *cp++; x1 = *cp++; - y2 = *cp++; x2 = *cp++; - weight = *cp++; - grads = *cp++; - color = FC(row+y1,col+x1); - if (FC(row+y2,col+x2) != color) continue; - diag = (FC(row,col+1) == color && FC(row+1,col) == color) ? 2:1; - if (abs(y1-y2) == diag && abs(x1-x2) == diag) continue; - *ip++ = (y1*width + x1)*4 + color; - *ip++ = (y2*width + x2)*4 + color; - *ip++ = weight; - for (g=0; g < 8; g++) - if (grads & 1<> 31; - gval[ip[3]] += (diff = ((diff ^ num) - num) << ip[2]); - ip += 5; - if ((g = ip[-1]) == -1) continue; - gval[g] += diff; - while ((g = *ip++) != -1) - gval[g] += diff; - } - ip++; - gmin = gmax = gval[0]; /* Choose a threshold */ - for (g=1; g < 8; g++) { - if (gmin > gval[g]) gmin = gval[g]; - if (gmax < gval[g]) gmax = gval[g]; - } - if (gmax == 0) { - memcpy (brow[2][col], pix, sizeof *image); - continue; - } - thold = gmin + (gmax >> 1); - memset (sum, 0, sizeof sum); - color = FC(row,col); - for (num=g=0; g < 8; g++,ip+=2) { /* Average the neighbors */ - if (gval[g] <= thold) { - FORC4 - if (c == color && ip[1]) - sum[c] += (pix[c] + pix[ip[1]]) >> 1; - else - sum[c] += pix[ip[0] + c]; - num++; + for (row=1; row < height-1; row++) { /* Do bilinear interpolation */ + for (col=1; col < width-1; col++) { + pix = image[row*width+col]; + ip = code[row & 7][col & 1]; + memset (sum, 0, sizeof sum); + for (g=8; g--; ) { + diff = pix[*ip++]; + diff <<= *ip++; + sum[*ip++] += diff; + } + for (g=colors; --g; ) { + c = *ip++; + pix[c] = sum[c] / *ip++; + } + } } - } - FORC4 { /* Save to buffer */ - t = pix[color]; - if (c != color) { - t += (sum[c] - sum[color])/num; - if (t < 0) t = 0; - if (t > clip_max) t = clip_max; + if (cmdline.quick_interpolate) + return; + + for (row=0; row < 8; row++) { /* Precalculate for VNG */ + for (col=0; col < 2; col++) { + ip = code[row][col]; + for (cp=terms, t=0; t < 64; t++) { + y1 = *cp++; x1 = *cp++; + y2 = *cp++; x2 = *cp++; + weight = *cp++; + grads = *cp++; + color = FC(row+y1,col+x1); + if (FC(row+y2,col+x2) != color) continue; + diag = + (FC(row,col+1) == color && FC(row+1,col) == color) ? 2:1; + if (abs(y1-y2) == diag && abs(x1-x2) == diag) continue; + *ip++ = (y1*width + x1)*4 + color; + *ip++ = (y2*width + x2)*4 + color; + *ip++ = weight; + for (g=0; g < 8; g++) + if (grads & 1<> 31; + gval[ip[3]] += (diff = ((diff ^ num) - num) << ip[2]); + ip += 5; + if ((g = ip[-1]) == -1) continue; + gval[g] += diff; + while ((g = *ip++) != -1) + gval[g] += diff; + } + ip++; + gmin = gmax = gval[0]; /* Choose a threshold */ + for (g=1; g < 8; g++) { + if (gmin > gval[g]) gmin = gval[g]; + if (gmax < gval[g]) gmax = gval[g]; + } + if (gmax == 0) { + memcpy (brow[2][col], pix, sizeof *image); + continue; + } + thold = gmin + (gmax >> 1); + memset (sum, 0, sizeof sum); + color = FC(row,col); + for (num=g=0; g < 8; g++,ip+=2) { /* Average the neighbors */ + if (gval[g] <= thold) { + FORC4 + if (c == color && ip[1]) + sum[c] += (pix[c] + pix[ip[1]]) >> 1; + else + sum[c] += pix[ip[0] + c]; + num++; + } + } + FORC4 { /* Save to buffer */ + t = pix[color]; + if (c != color) { + t += (sum[c] - sum[color])/num; + if (t < 0) t = 0; + if (t > clip_max) t = clip_max; + } + brow[2][col][c] = t; + } + } + if (row > 3) /* Write buffer to image */ + memcpy(image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image); + for (g=0; g < 4; g++) + brow[(g-1) & 3] = brow[g]; } - if (row > 3) /* Write buffer to image */ - memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image); - for (g=0; g < 4; g++) - brow[(g-1) & 3] = brow[g]; - } - memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image); - memcpy (image[(row-1)*width+2], brow[1]+2, (width-4)*sizeof *image); - free (brow[4]); + memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image); + memcpy (image[(row-1)*width+2], brow[1]+2, (width-4)*sizeof *image); + free (brow[4]); } -#ifdef USE_LCMS -static void -apply_profile(FILE * const ifP, - const char * const pfname) -{ - char *prof; - cmsHPROFILE hInProfile=NULL, hOutProfile; - cmsHTRANSFORM hTransform; - - if (pfname) - hInProfile = cmsOpenProfileFromFile (pfname, "r"); - else if (profile_length) { - prof = malloc (profile_length); - merror (prof, "apply_profile()"); - fseek (ifP, profile_offset, SEEK_SET); - fread (prof, 1, profile_length, ifP); - hInProfile = cmsOpenProfileFromMem (prof, profile_length); - free (prof); - } - if (!hInProfile) return; - if (cmdline.verbose) - pm_message( "Applying color profile..."); - maximum = 0xffff; - use_gamma = use_coeff = 0; - - hOutProfile = cmsCreate_sRGBProfile(); - hTransform = cmsCreateTransform (hInProfile, TYPE_RGBA_16, - hOutProfile, TYPE_RGBA_16, INTENT_PERCEPTUAL, 0); - cmsDoTransform (hTransform, image, image, width*height); - - cmsDeleteTransform (hTransform); - cmsCloseProfile (hInProfile); - cmsCloseProfile (hOutProfile); -} -#else -static void -apply_profile(FILE * const ifP, - const char * const pfname) -{ -} -#endif -/* + +static void CLASS +convertToRgb(Image const image, + unsigned int const trim) { +/*---------------------------------------------------------------------------- Convert the entire image to RGB colorspace and build a histogram. - */ -static void CLASS convert_to_rgb() -{ - int row, col, r, g, c=0; - unsigned short *img; - float rgb[3]; - - if (cmdline.document_mode) - colors = 1; - memset (histogram, 0, sizeof histogram); - for (row = trim; row < height-trim; row++) - for (col = trim; col < width-trim; col++) { - img = image[row*width+col]; - if (cmdline.document_mode) - c = FC(row,col); - if (colors == 4 && !use_coeff) /* Recombine the greens */ - img[1] = (img[1] + img[3]) >> 1; - if (colors == 1) /* RGB from grayscale */ - for (r=0; r < 3; r++) - rgb[r] = img[c]; - else if (use_coeff) { /* RGB via coeff[][] */ - for (r=0; r < 3; r++) - for (rgb[r]=g=0; g < colors; g++) - rgb[r] += img[g] * coeff[r][g]; - } else /* RGB from RGB (easy) */ - goto norgb; - for (r=0; r < 3; r++) { - if (rgb[r] < 0) rgb[r] = 0; - if (rgb[r] > clip_max) rgb[r] = clip_max; - img[r] = rgb[r]; - } -norgb: - for (r=0; r < 3; r++) - histogram[r][img[r] >> 3]++; + + We modify 'image' to change it from whatever it is now to RGB. +-----------------------------------------------------------------------------*/ + unsigned int row; + unsigned int c; + float rgb[3]; /* { red, green, blue } */ + + c = 0; /* initial value */ + + if (cmdline.document_mode) + colors = 1; + + memset(histogram, 0, sizeof histogram); + + for (row = 0 + trim; row < height - trim; ++row) { + unsigned int col; + for (col = 0 + trim; col < width - trim; ++col) { + unsigned short * const img = image[row*width+col]; + + if (cmdline.document_mode) + c = FC(row,col); + + if (colors == 4 && !use_coeff) + /* Recombine the greens */ + img[1] = (img[1] + img[3]) / 2; + + if (colors == 1) { + /* RGB from grayscale */ + unsigned int i; + for (i = 0; i < 3; ++i) + rgb[i] = img[c]; + } else if (use_coeff) { + /* RGB via coeff[][] */ + unsigned int i; + for (i = 0; i < 3; ++i) { + unsigned int j; + for (j = 0, rgb[i]= 0; j < colors; ++j) + rgb[i] += img[j] * coeff[i][j]; + } + } else { + /* RGB from RGB (easy) */ + unsigned int i; + for (i = 0; i < 3; ++i) + rgb[i] = img[i]; + } + { + unsigned int i; + for (i = 0; i < 3; ++i) + img[i] = MIN(clip_max, MAX(0, rgb[i])); + } + { + unsigned int i; + for (i = 0; i < 3; ++i) + ++histogram[i][img[i] >> 3]; + } + } } } -static void CLASS fuji_rotate() -{ - int i, wide, high, row, col; - double step; - float r, c, fr, fc; - unsigned ur, uc; - unsigned short (*img)[4], (*pix)[4]; - - if (!fuji_width) return; - if (cmdline.verbose) - pm_message ("Rotating image 45 degrees..."); - fuji_width = (fuji_width + shrink) >> shrink; - step = sqrt(0.5); - wide = fuji_width / step; - high = (height - fuji_width) / step; - img = calloc (wide*high, sizeof *img); - merror (img, "fuji_rotate()"); - - for (row=0; row < high; row++) - for (col=0; col < wide; col++) { - ur = r = fuji_width + (row-col)*step; - uc = c = (row+col)*step; - if (ur > height-2 || uc > width-2) continue; - fr = r - ur; - fc = c - uc; - pix = image + ur*width + uc; - for (i=0; i < colors; i++) - img[row*wide+col][i] = - (pix[ 0][i]*(1-fc) + pix[ 1][i]*fc) * (1-fr) + - (pix[width][i]*(1-fc) + pix[width+1][i]*fc) * fr; + + +static void CLASS +fujiRotate(Image * const imageP) { + + int wide; + int high; + unsigned int row; + double step; + float r, c, fr, fc; + unsigned short (*newImage)[4]; + unsigned short (*pix)[4]; + + if (fuji_width > 0) { + if (cmdline.verbose) + pm_message ("Rotating image 45 degrees..."); + + fuji_width = (fuji_width + shrink) >> shrink; + step = sqrt(0.5); + wide = fuji_width / step; + high = (height - fuji_width) / step; + newImage = calloc (wide*high, sizeof *newImage); + merror (newImage, "fujiRotate()"); + + for (row = 0; row < high; ++row) { + unsigned int col; + for (col = 0; col < wide; ++col) { + unsigned int ur = r = fuji_width + (row-col)*step; + unsigned int uc = c = (row+col)*step; + + unsigned int i; + + if (ur > height-2 || uc > width-2) + continue; + + fr = r - ur; + fc = c - uc; + pix = (*imageP) + ur * width + uc; + + for (i = 0; i < colors; ++i) { + newImage[row*wide+col][i] = + (pix[ 0][i]*(1-fc) + pix[ 1][i]*fc) * (1-fr) + + (pix[width][i]*(1-fc) + pix[width+1][i]*fc) * fr; + } + } + } + free(*imageP); + width = wide; + height = high; + *imageP = newImage; + fuji_width = 0; } - free (image); - width = wide; - height = high; - image = img; - fuji_width = 0; } -static void CLASS flip_image() -{ + + +static void CLASS +flipImage(Image const image) { + unsigned *flag; - int size, base, dest, next, row, col, temp; + int size, base, dest; struct imageCell { unsigned char contents[8]; }; struct imageCell * img; - struct imageCell hold; switch ((flip+3600) % 360) { - case 270: flip = 5; break; - case 180: flip = 3; break; - case 90: flip = 6; + case 270: flip = 0x5; break; + case 180: flip = 0x3; break; + case 90: flip = 0x6; } img = (struct imageCell *) image; size = height * width; flag = calloc ((size+31) >> 5, sizeof *flag); - merror (flag, "flip_image()"); - for (base = 0; base < size; base++) { - if (flag[base >> 5] & (1 << (base & 31))) - continue; - dest = base; - hold = img[base]; - while (1) { - if (flip & 4) { - row = dest % height; - col = dest / height; - } else { - row = dest / width; - col = dest % width; + merror (flag, "flipImage()"); + for (base = 0; base < size; ++base) { + if (flag[base >> 5] & (1 << (base & 31))) { + /* nothing */ + } else { + struct imageCell const hold = img[base]; + dest = base; + while (true) { + unsigned int col; + unsigned int row; + int next; + if (flip & 0x4) { + row = dest % height; + col = dest / height; + } else { + row = dest / width; + col = dest % width; + } + if (flip & 0x2) + row = height - 1 - row; + if (flip & 1) + col = width - 1 - col; + next = row * width + col; + if (next == base) + break; + flag[next >> 5] |= 1 << (next & 31); + img[dest] = img[next]; + dest = next; } - if (flip & 2) - row = height - 1 - row; - if (flip & 1) - col = width - 1 - col; - next = row * width + col; - if (next == base) break; - flag[next >> 5] |= 1 << (next & 31); - img[dest] = img[next]; - dest = next; + img[dest] = hold; } - img[dest] = hold; } free (flag); - if (flip & 4) { - temp = height; + if (flip & 0x4) { + int const oldHeight = height; + int const oldYmag = ymag; + height = width; - width = temp; - temp = ymag; + width = oldHeight; ymag = xmag; - xmag = temp; + xmag = oldYmag; } } -/* - Write the image as an RGB PAM image - */ -static void CLASS write_pam_nonlinear (FILE *ofp) -{ - unsigned char lut[0x10000]; - int perc, c, val, total, i, row, col; - float white=0, r; - struct pam pam; - tuple * tuplerow; - - pam.size = sizeof(pam); - pam.len = PAM_STRUCT_SIZE(tuple_type); - pam.file = ofp; - pam.width = xmag*(width-trim*2); - pam.height = ymag*(height-trim*2); - pam.depth = 3; - pam.format = PAM_FORMAT; - pam.maxval = 255; - strcpy(pam.tuple_type, "RGB"); - - pnm_writepaminit(&pam); - - tuplerow = pnm_allocpamrow(&pam); - - perc = width * height * 0.01; /* 99th percentile white point */ - if (fuji_width) perc /= 2; - FORC3 { - for (val=0x2000, total=0; --val > 32; ) - if ((total += histogram[c][val]) > perc) break; - if (white < val) white = val; - } - white *= 8 / cmdline.bright; - for (i=0; i < 0x10000; i++) { - r = i / white; - val = 256 * ( !use_gamma ? r : - r <= 0.018 ? r*4.5 : pow(r,0.45)*1.099-0.099 ); - if (val > 255) val = 255; - lut[i] = val; - } - for (row=trim; row < height-trim; row++) { - for (col=trim; col < width-trim; col++) { - unsigned int plane; - for (plane=0; plane < pam.depth; ++plane) { - unsigned int copy; - for (copy=0; copy < xmag; ++copy) { - unsigned int const pamcol = xmag*(col-trim)+copy; - tuplerow[pamcol][plane] = lut[image[row*width+col][plane]]; - } - } - } - { - unsigned int copy; - for (copy=0; copy < ymag; ++copy) - pnm_writepamrow(&pam, tuplerow); - } - } - pnm_freepamrow(tuplerow); + + +static void CLASS +writePamLinear(FILE * const ofP, + Image const image, + unsigned int const trim) { +/*---------------------------------------------------------------------------- + Write the image 'image' to a 16-bit PAM file with linear color space +-----------------------------------------------------------------------------*/ + unsigned int row; + + struct pam pam; + tuple * tuplerow; + + pam.size = sizeof(pam); + pam.len = PAM_STRUCT_SIZE(tuple_type); + pam.file = ofP; + pam.width = width - trim - trim; + pam.height = height - trim - trim; + pam.depth = 3; + pam.format = PAM_FORMAT; + pam.maxval = MAX(maximum, 256); + strcpy(pam.tuple_type, "RGB"); + + pnm_writepaminit(&pam); + + tuplerow = pnm_allocpamrow(&pam); + + for (row = 0 + trim; row < height - trim; ++row) { + unsigned int col; + for (col = 0 + trim; col < width - trim; ++col) { + unsigned int const pamCol = col - trim; + unsigned int plane; + for (plane = 0; plane < 3; ++plane) + tuplerow[pamCol][plane] = image[row*width+col][plane]; + } + pnm_writepamrow(&pam, tuplerow); + } + pnm_freepamrow(tuplerow); } -/* - Write the image to a 16-bit PAM file with linear color space - */ -static void CLASS write_pam_linear (FILE *ofp) -{ - int row; - - struct pam pam; - tuple * tuplerow; - - if (maximum < 256) maximum = 256; - - pam.size = sizeof(pam); - pam.len = PAM_STRUCT_SIZE(tuple_type); - pam.file = ofp; - pam.width = width-trim*2; - pam.height = height-trim*2; - pam.depth = 3; - pam.format = PAM_FORMAT; - pam.maxval = MAX(maximum, 256); - strcpy(pam.tuple_type, "RGB"); - - pnm_writepaminit(&pam); - - tuplerow = pnm_allocpamrow(&pam); - - for (row = trim; row < height-trim; row++) { - unsigned int col; - for (col = trim; col < width-trim; col++) { - unsigned int const pamCol = col - trim; - unsigned int plane; - for (plane = 0; plane < 3; ++plane) - tuplerow[pamCol][plane] = image[row*width+col][plane]; - } - pnm_writepamrow(&pam, tuplerow); - } - pnm_freepamrow(tuplerow); + + +static void CLASS +writePamNonlinear(FILE * const ofP, + Image const image, + unsigned int const trim) { +/*---------------------------------------------------------------------------- + Write the image 'image' as an RGB PAM image +-----------------------------------------------------------------------------*/ + unsigned char lut[0x10000]; + int perc; + int c; + int total; + int i; + unsigned int row; + float white; + float r; + struct pam pam; + tuple * tuplerow; + + white = 0; /* initial value */ + + pam.size = sizeof(pam); + pam.len = PAM_STRUCT_SIZE(tuple_type); + pam.file = ofP; + pam.width = xmag*(width-trim*2); + pam.height = ymag*(height-trim*2); + pam.depth = 3; + pam.format = PAM_FORMAT; + pam.maxval = 255; + strcpy(pam.tuple_type, "RGB"); + + pnm_writepaminit(&pam); + + tuplerow = pnm_allocpamrow(&pam); + + perc = width * height * 0.01; /* 99th percentile white point */ + if (fuji_width) perc /= 2; + FORC3 { + int val; + for (val=0x2000, total=0; --val > 32; ) + if ((total += histogram[c][val]) > perc) break; + if (white < val) + white = val; + } + white *= 8 / cmdline.bright; + for (i=0; i < 0x10000; ++i) { + int val; + r = i / white; + val = 256 * ( !use_gamma ? r : + r <= 0.018 ? r*4.5 : pow(r,0.45)*1.099-0.099 ); + lut[i] = MIN(255, val); + } + + for (row = 0 + trim; row < height - trim; ++row) { + unsigned int col; + for (col = 0 + trim; col < width - trim; ++col) { + unsigned int plane; + for (plane = 0; plane < pam.depth; ++plane) { + sample const value = lut[image[row*width+col][plane]]; + unsigned int copy; + for (copy = 0; copy < xmag; ++copy) { + unsigned int const pamcol = xmag*(col-trim)+copy; + tuplerow[pamcol][plane] = value; + } + } + } + { + unsigned int copy; + for (copy = 0; copy < ymag; ++copy) + pnm_writepamrow(&pam, tuplerow); + } + } + pnm_freepamrow(tuplerow); } static void CLASS -writePam(FILE * const ofP, - bool const linear) { +writePam(FILE * const ofP, + Image const image, + bool const linear, + unsigned int const trim) { if (linear) - write_pam_linear(ofP); + writePamLinear(ofP, image, trim); else - write_pam_nonlinear(ofP); + writePamNonlinear(ofP, image, trim); } - static void CLASS -convertIt(FILE * const ifP, - FILE * const ofP, - loadRawFn const load_raw) { +convertIt(FILE * const ifP, + FILE * const ofP, + LoadRawFn * const load_raw) { + + Image image; + unsigned int trim; shrink = cmdline.half_size && filters; iheight = (height + shrink) >> shrink; iwidth = (width + shrink) >> shrink; - image = calloc (iheight*iwidth*sizeof *image + meta_length, 1); + image = calloc (iheight*iwidth*sizeof(*image) + meta_length, 1); merror (image, "main()"); meta_data = (char *) (image + iheight*iwidth); if (cmdline.verbose) @@ -807,43 +887,49 @@ convertIt(FILE * const ifP, ifp = ifP; /* Set global variable for (*load_raw)() */ - load_raw(); - bad_pixels(); + load_raw(image); + fixBadPixels(image); height = iheight; width = iwidth; if (is_foveon) { if (cmdline.verbose) pm_message ("Foveon interpolation..."); - foveon_interpolate(coeff); + foveon_interpolate(image, coeff); } else { - scale_colors(); + scaleColors(image); } - if (shrink) filters = 0; - trim = 0; + if (shrink) + filters = 0; + if (filters && !cmdline.document_mode) { trim = 1; if (cmdline.verbose) pm_message ("%s interpolation...", cmdline.quick_interpolate ? "Bilinear":"VNG"); - vng_interpolate(); - } - fuji_rotate(); - apply_profile(ifP, cmdline.profile); + vngInterpolate(image); + } else + trim = 0; + + fujiRotate(&image); + if (cmdline.verbose) pm_message ("Converting to RGB colorspace..."); - convert_to_rgb(); + convertToRgb(image, trim); if (flip) { if (cmdline.verbose) pm_message ("Flipping image %c:%c:%c...", flip & 1 ? 'H':'0', flip & 2 ? 'V':'0', flip & 4 ? 'T':'0'); - flip_image(); + flipImage(image); } - writePam(ofP, cmdline.linear); + writePam(ofP, image, cmdline.linear, trim); + + free(image); } + int main (int argc, char **argv) { @@ -851,7 +937,7 @@ main (int argc, char **argv) { FILE * ifP; int rc; - loadRawFn load_raw; + LoadRawFn * load_raw; pnm_init(&argc, argv); @@ -861,8 +947,6 @@ main (int argc, char **argv) { ifP = pm_openr(cmdline.inputFileName); - image = NULL; - rc = identify(ifP, cmdline.use_secondary, cmdline.use_camera_rgb, cmdline.red_scale, cmdline.blue_scale, @@ -881,7 +965,6 @@ main (int argc, char **argv) { } pm_close(ifP); pm_close(ofP); - free(image); return 0; } diff --git a/converter/other/cameratopam/cameratopam.h b/converter/other/cameratopam/cameratopam.h new file mode 100644 index 00000000..9ff33cb3 --- /dev/null +++ b/converter/other/cameratopam/cameratopam.h @@ -0,0 +1,6 @@ +#ifndef CAMERATOPAM_H_INCLUDED +#define CAMERATOPAM_H_INCLUDED + +typedef unsigned short (*Image)[4]; + +#endif diff --git a/converter/other/cameratopam/canon.c b/converter/other/cameratopam/canon.c index a34771d0..96a6210b 100644 --- a/converter/other/cameratopam/canon.c +++ b/converter/other/cameratopam/canon.c @@ -9,7 +9,7 @@ void -canon_600_load_raw(void) { +canon_600_load_raw(Image const image) { unsigned char data[1120], *dp; unsigned short pixel[896], *pix; int irow, orow, col; @@ -42,7 +42,7 @@ canon_600_load_raw(void) { void -canon_a5_load_raw(void) { +canon_a5_load_raw(Image const image) { unsigned char data[1940], *dp; unsigned short pixel[1552], *pix; int row, col; @@ -97,7 +97,7 @@ canon_has_lowbits() void -canon_compressed_load_raw(void) { +canon_compressed_load_raw(Image const image) { unsigned short *pixel, *prow; int lowbits, i, row, r, col, save, val; unsigned irow, icol; diff --git a/converter/other/cameratopam/canon.h b/converter/other/cameratopam/canon.h index 041cdc4d..fe6a5a08 100644 --- a/converter/other/cameratopam/canon.h +++ b/converter/other/cameratopam/canon.h @@ -1,13 +1,12 @@ #ifndef CANON_H_INCLUDED #define CANON_H_INCLUDED -void -canon_600_load_raw(void); +#include "camera.h" -void -canon_a5_load_raw(void); +LoadRawFn canon_600_load_raw; -void -canon_compressed_load_raw(void); +LoadRawFn canon_a5_load_raw; + +LoadRawFn canon_compressed_load_raw; #endif diff --git a/converter/other/cameratopam/dng.c b/converter/other/cameratopam/dng.c index 44d45b02..bddfd9f4 100644 --- a/converter/other/cameratopam/dng.c +++ b/converter/other/cameratopam/dng.c @@ -4,70 +4,105 @@ #include "dng.h" void -dng_coeff (double cc[4][4], double cm[4][3], double xyz[3]) -{ - static const double rgb_xyz[3][3] = { /* RGB from XYZ */ - { 3.240479, -1.537150, -0.498535 }, - { -0.969256, 1.875992, 0.041556 }, - { 0.055648, -0.204043, 1.057311 } }; +dng_coeff (double cc[4][4], + double cm[4][3], + double xyz[3]) { + static const double rgb_xyz[3][3] = { /* RGB from XYZ */ + { 3.240479, -1.537150, -0.498535 }, + { -0.969256, 1.875992, 0.041556 }, + { 0.055648, -0.204043, 1.057311 } }; #if 0 - static const double xyz_rgb[3][3] = { /* XYZ from RGB */ - { 0.412453, 0.357580, 0.180423 }, - { 0.212671, 0.715160, 0.072169 }, - { 0.019334, 0.119193, 0.950227 } }; + static const double xyz_rgb[3][3] = { /* XYZ from RGB */ + { 0.412453, 0.357580, 0.180423 }, + { 0.212671, 0.715160, 0.072169 }, + { 0.019334, 0.119193, 0.950227 } }; #endif - double cam_xyz[4][3], xyz_cam[3][4], invert[3][6], num; - int i, j, k; + double cam_xyz[4][3], xyz_cam[3][4], invert[3][6]; + unsigned int i; - memset (cam_xyz, 0, sizeof cam_xyz); - for (i=0; i < colors; i++) - for (j=0; j < 3; j++) - for (k=0; k < colors; k++) - cam_xyz[i][j] += cc[i][k] * cm[k][j] * xyz[j]; + for (i = 0; i < colors; ++i) { + unsigned int j; + for (j = 0; j < 3; ++j) { + unsigned int k; + for (k = 0, cam_xyz[i][j] = 0.0; k < colors; ++k) { + cam_xyz[i][j] += cc[i][k] * cm[k][j] * xyz[j]; + } + } + } + for (i = 0; i < colors; ++i) { + unsigned int j; + double camXyzSum; + + for (j = 0, camXyzSum = 0.0; j < 3; ++j) + camXyzSum += cam_xyz[i][j]; - for (i=0; i < colors; i++) { - for (num=j=0; j < 3; j++) - num += cam_xyz[i][j]; - for (j=0; j < 3; j++) - cam_xyz[i][j] /= num; - pre_mul[i] = 1 / num; - } - for (i=0; i < 3; i++) { - for (j=0; j < 6; j++) - invert[i][j] = j == i+3; - for (j=0; j < 3; j++) - for (k=0; k < colors; k++) - invert[i][j] += cam_xyz[k][i] * cam_xyz[k][j]; - } - for (i=0; i < 3; i++) { - num = invert[i][i]; - for (j=0; j < 6; j++) /* Normalize row i */ - invert[i][j] /= num; - for (k=0; k < 3; k++) { /* Subtract it from other rows */ - if (k==i) continue; - num = invert[k][i]; - for (j=0; j < 6; j++) - invert[k][j] -= invert[i][j] * num; + for (j = 0; j < 3; ++j) + cam_xyz[i][j] /= camXyzSum; + + pre_mul[i] = 1 / camXyzSum; + } + for (i = 0; i < 3; ++i) { + unsigned int j; + for (j = 0; j < 6; ++j) + invert[i][j] = j == i+3; + for (j = 0; j < 3; ++j) { + unsigned int k; + for (k = 0; k < colors; ++k) + invert[i][j] += cam_xyz[k][i] * cam_xyz[k][j]; + } } - } - memset (xyz_cam, 0, sizeof xyz_cam); - for (i=0; i < 3; i++) - for (j=0; j < colors; j++) - for (k=0; k < 3; k++) - xyz_cam[i][j] += invert[i][k+3] * cam_xyz[j][k]; + for (i = 0; i < 3; ++i) { + double const num = invert[i][i]; + unsigned int j; + unsigned int k; + for (j = 0; j < 6; ++j) /* Normalize row i */ + invert[i][j] /= num; + for (k = 0; k < 3; ++k) { /* Subtract it from other rows */ + if (k != i) { + double const num = invert[k][i]; + unsigned int j; + for (j = 0; j < 6; ++j) + invert[k][j] -= invert[i][j] * num; + } + } + } + + memset(xyz_cam, 0, sizeof xyz_cam); - memset (coeff, 0, sizeof coeff); - for (i=0; i < 3; i++) - for (j=0; j < colors; j++) - for (k=0; k < 3; k++) - coeff[i][j] += rgb_xyz[i][k] * xyz_cam[k][j]; + for (i = 0; i < 3; ++i) { + unsigned int j; + for (j = 0; j < colors; ++j) { + unsigned int k; + for (k = 0; k < 3; ++k) + xyz_cam[i][j] += invert[i][k+3] * cam_xyz[j][k]; + } + } + memset (coeff, 0, sizeof coeff); - for (num=j=0; j < colors; j++) - num += coeff[1][j]; - for (i=0; i < 3; i++) { - for (j=0; j < colors; j++) - coeff[i][j] /= num; - } - use_coeff = 1; + for (i = 0; i < 3; ++i) { + unsigned int j; + for (j = 0; j < colors; ++j) { + unsigned int k; + for (k = 0; k < 3; ++k) + coeff[i][j] += rgb_xyz[i][k] * xyz_cam[k][j]; + } + } + { + double greenSum; + unsigned int j; + unsigned int i; + + for (j = 0, greenSum = 0.0; j < colors; ++j) + greenSum += coeff[1][j]; + + for (i = 0; i < 3; ++i) { + unsigned int j; + for (j = 0; j < colors; ++j) + coeff[i][j] /= greenSum; + } + } + use_coeff = 1; } + + diff --git a/converter/other/cameratopam/dng.h b/converter/other/cameratopam/dng.h index 01e7e0a5..56293563 100644 --- a/converter/other/cameratopam/dng.h +++ b/converter/other/cameratopam/dng.h @@ -1,2 +1,4 @@ void -dng_coeff (double cc[4][4], double cm[4][3], double xyz[3]); +dng_coeff(double cc[4][4], + double cm[4][3], + double xyz[3]); diff --git a/converter/other/cameratopam/foveon.c b/converter/other/cameratopam/foveon.c index a8d62bee..a3e5449a 100644 --- a/converter/other/cameratopam/foveon.c +++ b/converter/other/cameratopam/foveon.c @@ -141,8 +141,8 @@ parse_foveon(FILE * const ifp) { void -foveon_coeff(bool * const useCoeffP, - float coeff[3][4]) { +foveon_coeff(int * const useCoeffP, + float coeff[3][4]) { static const float foveon[3][3] = { { 1.4032, -0.2231, -0.1016 }, @@ -211,7 +211,7 @@ foveon_load_camf() { void -foveon_load_raw() { +foveon_load_raw(Image const image) { struct decode *dindex; short diff[1024], pred[3]; @@ -391,7 +391,8 @@ static int foveon_apply_curve (short *curve, int i) } void -foveon_interpolate(float coeff[3][4]) { +foveon_interpolate(Image const image, + float coeff[3][4]) { static const short hood[] = { -1,-1, -1,0, -1,1, 0,-1, 0,1, 1,-1, 1,0, 1,1 }; @@ -472,18 +473,22 @@ foveon_interpolate(float coeff[3][4]) { sgrow = calloc (dim[1], sizeof *sgrow); sgx = (width + dim[1]-2) / (dim[1]-1); - black = calloc (height, sizeof *black); - for (row=0; row < height; row++) { - for (i=0; i < 6; i++) - ddft[0][0][i] = ddft[1][0][i] + - row / (height-1.0) * (ddft[2][0][i] - ddft[1][0][i]); + black = calloc (height, sizeof(black[0])); + for (row=0; row < height; ++row) { + unsigned int i; + for (i=0; i < 3; ++i) { + unsigned int j; + for (j = 0; j < 2; ++j) + ddft[0][i][j] = ddft[1][i][j] + + row / (height-1.0) * (ddft[2][i][j] - ddft[1][i][j]); + } FORC3 black[row][c] = ( foveon_avg (image[row*width]+c, dscr[0], cfilt) + foveon_avg (image[row*width]+c, dscr[1], cfilt) * 3 - ddft[0][c][0] ) / 4 - ddft[0][c][1]; } - memcpy (black, black+8, sizeof (*black)*8); - memcpy (black+height-11, black+height-22, 11*sizeof *black); + memcpy (black, black+8, 8 * sizeof(black[0])); + memcpy (black+height-11, black+height-22, 11*(sizeof black[0])); memcpy (last, black, sizeof last); for (row=1; row < height-1; row++) { @@ -522,9 +527,13 @@ foveon_interpolate(float coeff[3][4]) { FORC3 black[row][c] += fsum[c]/2 + total[c]/(total[3]*100.0); for (row=0; row < height; row++) { - for (i=0; i < 6; i++) - ddft[0][0][i] = ddft[1][0][i] + - row / (height-1.0) * (ddft[2][0][i] - ddft[1][0][i]); + unsigned int i; + for (i = 0; i < 3; ++i) { + unsigned int j; + for (j = 0; j < 2; ++j) + ddft[0][i][j] = ddft[1][i][j] + + row / (height-1.0) * (ddft[2][i][j] - ddft[1][i][j]); + } pix = (short*)image[row*width]; memcpy (prev, pix, sizeof prev); frow = row / (height-1.0) * (dim[2]-1); diff --git a/converter/other/cameratopam/foveon.h b/converter/other/cameratopam/foveon.h index 57be2244..c9bf48a8 100644 --- a/converter/other/cameratopam/foveon.h +++ b/converter/other/cameratopam/foveon.h @@ -1,14 +1,17 @@ #include "pm.h" +#include "cameratopam.h" +#include "camera.h" + void parse_foveon(FILE * const ifp); void -foveon_interpolate(float coeff[3][4]); +foveon_interpolate(Image const image, + float coeff[3][4]); -void -foveon_load_raw(void); +LoadRawFn foveon_load_raw; void -foveon_coeff(bool * const useCoeffP, - float coeff[3][4]); +foveon_coeff(int * const useCoeffP, + float coeff[3][4]); diff --git a/converter/other/cameratopam/global_variables.h b/converter/other/cameratopam/global_variables.h index c8732d5a..2bfc08c9 100644 --- a/converter/other/cameratopam/global_variables.h +++ b/converter/other/cameratopam/global_variables.h @@ -23,7 +23,6 @@ extern time_t timestamp; extern int is_foveon; extern int is_dng; extern int is_canon; -extern unsigned short (*image)[4]; extern int maximum; extern int clip_max; extern short order; diff --git a/converter/other/cameratopam/identify.c b/converter/other/cameratopam/identify.c index a101c8ad..394ba0a7 100644 --- a/converter/other/cameratopam/identify.c +++ b/converter/other/cameratopam/identify.c @@ -2,6 +2,8 @@ #include #include "pm.h" +#include "pm_c_util.h" +#include "nstring.h" #include "global_variables.h" #include "util.h" @@ -15,235 +17,250 @@ #if HAVE_INT64 - static bool const have64BitArithmetic = true; +static bool const have64BitArithmetic = true; #else - static bool const have64BitArithmetic = false; +static bool const have64BitArithmetic = false; #endif -static loadRawFn load_raw; /* This does the same as the function of the same name in the GNU C library */ static const char *memmem_internal (const char *haystack, size_t haystacklen, - const char *needle, size_t needlelen) + const char *needle, size_t needlelen) { - const char *c; - for (c = haystack; c <= haystack + haystacklen - needlelen; c++) - if (!memcmp (c, needle, needlelen)) - return c; - return NULL; + const char *c; + for (c = haystack; c <= haystack + haystacklen - needlelen; c++) + if (!memcmp (c, needle, needlelen)) + return c; + return NULL; } -/* - Thanks to Adobe for providing these excellent CAM -> XYZ matrices! - */ + + static void -adobe_coeff() -{ - static const struct { - const char *prefix; - short trans[12]; - } table[] = { - { "Canon EOS D2000C", - { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } }, - { "Canon EOS D30", - { 9805,-2689,-1312,-5803,13064,3068,-2438,3075,8775 } }, - { "Canon EOS D60", - { 6188,-1341,-890,-7168,14489,2937,-2640,3228,8483 } }, - { "Canon EOS 10D", - { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } }, - { "Canon EOS 20D", - { 6599,-537,-891,-8071,15783,2424,-1983,2234,7462 } }, - { "Canon EOS-1Ds Mark II", - { 6517,-602,-867,-8180,15926,2378,-1618,1771,7633 } }, - { "Canon EOS-1D Mark II", - { 6264,-582,-724,-8312,15948,2504,-1744,1919,8664 } }, - { "Canon EOS-1DS", - { 4374,3631,-1743,-7520,15212,2472,-2892,3632,8161 } }, - { "Canon EOS-1D", - { 6906,-278,-1017,-6649,15074,1621,-2848,3897,7611 } }, - { "Canon EOS", - { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } }, - { "Canon PowerShot 600", - { -3822,10019,1311,4085,-157,3386,-5341,10829,4812,-1969,10969,1126 } }, - { "Canon PowerShot A50", - { -5300,9846,1776,3436,684,3939,-5540,9879,6200,-1404,11175,217 } }, - { "Canon PowerShot A5", - { -4801,9475,1952,2926,1611,4094,-5259,10164,5947,-1554,10883,547 } }, - { "Canon PowerShot G1", - { -4778,9467,2172,4743,-1141,4344,-5146,9908,6077,-1566,11051,557 } }, - { "Canon PowerShot G2", - { 9087,-2693,-1049,-6715,14382,2537,-2291,2819,7790 } }, - { "Canon PowerShot G3", - { 9212,-2781,-1073,-6573,14189,2605,-2300,2844,7664 } }, - { "Canon PowerShot G5", - { 9757,-2872,-933,-5972,13861,2301,-1622,2328,7212 } }, - { "Canon PowerShot G6", - { 9877,-3775,-871,-7613,14807,3072,-1448,1305,7485 } }, - { "Canon PowerShot Pro1", - { 10062,-3522,-999,-7643,15117,2730,-765,817,7323 } }, - { "Canon PowerShot Pro70", - { -4155,9818,1529,3939,-25,4522,-5521,9870,6610,-2238,10873,1342 } }, - { "Canon PowerShot Pro90", - { -4963,9896,2235,4642,-987,4294,-5162,10011,5859,-1770,11230,577 } }, - { "Canon PowerShot S30", - { 10566,-3652,-1129,-6552,14662,2006,-2197,2581,7670 } }, - { "Canon PowerShot S40", - { 8510,-2487,-940,-6869,14231,2900,-2318,2829,9013 } }, - { "Canon PowerShot S45", - { 8163,-2333,-955,-6682,14174,2751,-2077,2597,8041 } }, - { "Canon PowerShot S50", - { 8882,-2571,-863,-6348,14234,2288,-1516,2172,6569 } }, - { "Canon PowerShot S70", - { 9976,-3810,-832,-7115,14463,2906,-901,989,7889 } }, - { "Contax N Digital", - { 7777,1285,-1053,-9280,16543,2916,-3677,5679,7060 } }, - { "EPSON R-D1", - { 6827,-1878,-732,-8429,16012,2564,-704,592,7145 } }, - { "FUJIFILM FinePix E550", - { 11044,-3888,-1120,-7248,15168,2208,-1531,2277,8069 } }, - { "FUJIFILM FinePix F700", - { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } }, - { "FUJIFILM FinePix S20Pro", - { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } }, - { "FUJIFILM FinePix S2Pro", - { 12492,-4690,-1402,-7033,15423,1647,-1507,2111,7697 } }, - { "FUJIFILM FinePix S3Pro", - { 11807,-4612,-1294,-8927,16968,1988,-2120,2741,8006 } }, - { "FUJIFILM FinePix S5000", - { 8754,-2732,-1019,-7204,15069,2276,-1702,2334,6982 } }, - { "FUJIFILM FinePix S5100", - { 11940,-4431,-1255,-6766,14428,2542,-993,1165,7421 } }, - { "FUJIFILM FinePix S7000", - { 10190,-3506,-1312,-7153,15051,2238,-2003,2399,7505 } }, - { "Kodak DCS315C", - { 17523,-4827,-2510,756,8546,-137,6113,1649,2250 } }, - { "Kodak DCS330C", - { 20620,-7572,-2801,-103,10073,-396,3551,-233,2220 } }, - { "KODAK DCS420", - { 10868,-1852,-644,-1537,11083,484,2343,628,2216 } }, - { "KODAK DCS460", - { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } }, - { "KODAK EOSDCS1", - { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } }, - { "KODAK EOSDCS3B", - { 9898,-2700,-940,-2478,12219,206,1985,634,1031 } }, - { "Kodak DCS520C", - { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } }, - { "Kodak DCS560C", - { 20482,-7172,-3125,-1033,10410,-285,2542,226,3136 } }, - { "Kodak DCS620C", - { 23617,-10175,-3149,-2054,11749,-272,2586,-489,3453 } }, - { "Kodak DCS620X", - { 13095,-6231,154,12221,-21,-2137,895,4602,2258 } }, - { "Kodak DCS660C", - { 18244,-6351,-2739,-791,11193,-521,3711,-129,2802 } }, - { "Kodak DCS720X", - { 11775,-5884,950,9556,1846,-1286,-1019,6221,2728 } }, - { "Kodak DCS760C", - { 16623,-6309,-1411,-4344,13923,323,2285,274,2926 } }, - { "Kodak DCS Pro SLR", - { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } }, - { "Kodak DCS Pro 14nx", - { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } }, - { "Kodak DCS Pro 14", - { 7791,3128,-776,-8588,16458,2039,-2455,4006,6198 } }, - { "Kodak ProBack645", - { 16414,-6060,-1470,-3555,13037,473,2545,122,4948 } }, - { "Kodak ProBack", - { 21179,-8316,-2918,-915,11019,-165,3477,-180,4210 } }, - { "LEICA DIGILUX 2", - { 11340,-4069,-1275,-7555,15266,2448,-2960,3426,7685 } }, - { "Leaf Valeo", - { 8236,1746,-1314,-8251,15953,2428,-3673,5786,5771 } }, - { "Minolta DiMAGE 5", - { 8983,-2942,-963,-6556,14476,2237,-2426,2887,8014 } }, - { "Minolta DiMAGE 7", - { 9144,-2777,-998,-6676,14556,2281,-2470,3019,7744 } }, - { "Minolta DiMAGE A1", - { 9274,-2547,-1167,-8220,16323,1943,-2273,2720,8340 } }, - { "MINOLTA DiMAGE A200", - { 8560,-2487,-986,-8112,15535,2771,-1209,1324,7743 } }, - { "Minolta DiMAGE A2", - { 9097,-2726,-1053,-8073,15506,2762,-966,981,7763 } }, - { "MINOLTA DYNAX 7D", - { 10239,-3104,-1099,-8037,15727,2451,-927,925,6871 } }, - { "NIKON D100", - { 5915,-949,-778,-7516,15364,2282,-1228,1337,6404 } }, - { "NIKON D1H", - { 7577,-2166,-926,-7454,15592,1934,-2377,2808,8606 } }, - { "NIKON D1X", - { 7620,-2173,-966,-7604,15843,1805,-2356,2811,8439 } }, - { "NIKON D1", - { 7559,-2130,-965,-7611,15713,1972,-2478,3042,8290 } }, - { "NIKON D2H", - { 5710,-901,-615,-8594,16617,2024,-2975,4120,6830 } }, - { "NIKON D70", - { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } }, - { "NIKON E995", /* copied from E5000 */ - { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, - { "NIKON E2500", - { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, - { "NIKON E4500", - { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, - { "NIKON E5000", - { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, - { "NIKON E5400", - { 9349,-2987,-1001,-7919,15766,2266,-2098,2680,6839 } }, - { "NIKON E5700", - { -5368,11478,2368,5537,-113,3148,-4969,10021,5782,778,9028,211 } }, - { "NIKON E8400", - { 7842,-2320,-992,-8154,15718,2599,-1098,1342,7560 } }, - { "NIKON E8700", - { 8489,-2583,-1036,-8051,15583,2643,-1307,1407,7354 } }, - { "NIKON E8800", - { 7971,-2314,-913,-8451,15762,2894,-1442,1520,7610 } }, - { "OLYMPUS C5050", - { 10508,-3124,-1273,-6079,14294,1901,-1653,2306,6237 } }, - { "OLYMPUS C5060", - { 10445,-3362,-1307,-7662,15690,2058,-1135,1176,7602 } }, - { "OLYMPUS C70", - { 10793,-3791,-1146,-7498,15177,2488,-1390,1577,7321 } }, - { "OLYMPUS C80", - { 8606,-2509,-1014,-8238,15714,2703,-942,979,7760 } }, - { "OLYMPUS E-10", - { 12745,-4500,-1416,-6062,14542,1580,-1934,2256,6603 } }, - { "OLYMPUS E-1", - { 11846,-4767,-945,-7027,15878,1089,-2699,4122,8311 } }, - { "OLYMPUS E-20", - { 13173,-4732,-1499,-5807,14036,1895,-2045,2452,7142 } }, - { "OLYMPUS E-300", - { 7828,-1761,-348,-5788,14071,1830,-2853,4518,6557 } }, - { "PENTAX *ist D", - { 9651,-2059,-1189,-8881,16512,2487,-1460,1345,10687 } }, - { "Panasonic DMC-LC1", - { 11340,-4069,-1275,-7555,15266,2448,-2960,3426,7685 } }, - { "SONY DSC-F828", - { 7924,-1910,-777,-8226,15459,2998,-1517,2199,6818,-7242,11401,3481 } }, - { "SONY DSC-V3", - { 9877,-3775,-871,-7613,14807,3072,-1448,1305,7485 } } - }; - double cc[4][4], cm[4][3], xyz[] = { 1,1,1 }; - char name[130]; - int i, j; +adobeCoeff(const char * const make, + const char * const model) { + /* + Thanks to Adobe for providing these excellent CAM -> XYZ matrices! + */ + struct CoeffTableEntry { + const char * prefix; + short trans[12]; + }; + + static struct CoeffTableEntry const table[] = { + { "Canon EOS D2000C", + { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } }, + { "Canon EOS D30", + { 9805,-2689,-1312,-5803,13064,3068,-2438,3075,8775 } }, + { "Canon EOS D60", + { 6188,-1341,-890,-7168,14489,2937,-2640,3228,8483 } }, + { "Canon EOS 10D", + { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } }, + { "Canon EOS 20D", + { 6599,-537,-891,-8071,15783,2424,-1983,2234,7462 } }, + { "Canon EOS-1Ds Mark II", + { 6517,-602,-867,-8180,15926,2378,-1618,1771,7633 } }, + { "Canon EOS-1D Mark II", + { 6264,-582,-724,-8312,15948,2504,-1744,1919,8664 } }, + { "Canon EOS-1DS", + { 4374,3631,-1743,-7520,15212,2472,-2892,3632,8161 } }, + { "Canon EOS-1D", + { 6906,-278,-1017,-6649,15074,1621,-2848,3897,7611 } }, + { "Canon EOS", + { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } }, + { "Canon PowerShot 600", + { -3822,10019,1311,4085,-157,3386,-5341,10829,4812,-1969,10969, + 1126} }, + { "Canon PowerShot A50", + { -5300,9846,1776,3436,684,3939,-5540,9879,6200,-1404,11175,217 } }, + { "Canon PowerShot A5", + { -4801,9475,1952,2926,1611,4094,-5259,10164,5947,-1554,10883,547} }, + { "Canon PowerShot G1", + { -4778,9467,2172,4743,-1141,4344,-5146,9908,6077,-1566,11051,557} }, + { "Canon PowerShot G2", + { 9087,-2693,-1049,-6715,14382,2537,-2291,2819,7790 } }, + { "Canon PowerShot G3", + { 9212,-2781,-1073,-6573,14189,2605,-2300,2844,7664 } }, + { "Canon PowerShot G5", + { 9757,-2872,-933,-5972,13861,2301,-1622,2328,7212 } }, + { "Canon PowerShot G6", + { 9877,-3775,-871,-7613,14807,3072,-1448,1305,7485 } }, + { "Canon PowerShot Pro1", + { 10062,-3522,-999,-7643,15117,2730,-765,817,7323 } }, + { "Canon PowerShot Pro70", + { -4155,9818,1529,3939,-25,4522,-5521,9870,6610,-2238,10873,1342 } }, + { "Canon PowerShot Pro90", + { -4963,9896,2235,4642,-987,4294,-5162,10011,5859,-1770,11230,577} }, + { "Canon PowerShot S30", + { 10566,-3652,-1129,-6552,14662,2006,-2197,2581,7670 } }, + { "Canon PowerShot S40", + { 8510,-2487,-940,-6869,14231,2900,-2318,2829,9013 } }, + { "Canon PowerShot S45", + { 8163,-2333,-955,-6682,14174,2751,-2077,2597,8041 } }, + { "Canon PowerShot S50", + { 8882,-2571,-863,-6348,14234,2288,-1516,2172,6569 } }, + { "Canon PowerShot S70", + { 9976,-3810,-832,-7115,14463,2906,-901,989,7889 } }, + { "Contax N Digital", + { 7777,1285,-1053,-9280,16543,2916,-3677,5679,7060 } }, + { "EPSON R-D1", + { 6827,-1878,-732,-8429,16012,2564,-704,592,7145 } }, + { "FUJIFILM FinePix E550", + { 11044,-3888,-1120,-7248,15168,2208,-1531,2277,8069 } }, + { "FUJIFILM FinePix F700", + { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } }, + { "FUJIFILM FinePix S20Pro", + { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } }, + { "FUJIFILM FinePix S2Pro", + { 12492,-4690,-1402,-7033,15423,1647,-1507,2111,7697 } }, + { "FUJIFILM FinePix S3Pro", + { 11807,-4612,-1294,-8927,16968,1988,-2120,2741,8006 } }, + { "FUJIFILM FinePix S5000", + { 8754,-2732,-1019,-7204,15069,2276,-1702,2334,6982 } }, + { "FUJIFILM FinePix S5100", + { 11940,-4431,-1255,-6766,14428,2542,-993,1165,7421 } }, + { "FUJIFILM FinePix S7000", + { 10190,-3506,-1312,-7153,15051,2238,-2003,2399,7505 } }, + { "Kodak DCS315C", + { 17523,-4827,-2510,756,8546,-137,6113,1649,2250 } }, + { "Kodak DCS330C", + { 20620,-7572,-2801,-103,10073,-396,3551,-233,2220 } }, + { "KODAK DCS420", + { 10868,-1852,-644,-1537,11083,484,2343,628,2216 } }, + { "KODAK DCS460", + { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } }, + { "KODAK EOSDCS1", + { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } }, + { "KODAK EOSDCS3B", + { 9898,-2700,-940,-2478,12219,206,1985,634,1031 } }, + { "Kodak DCS520C", + { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } }, + { "Kodak DCS560C", + { 20482,-7172,-3125,-1033,10410,-285,2542,226,3136 } }, + { "Kodak DCS620C", + { 23617,-10175,-3149,-2054,11749,-272,2586,-489,3453 } }, + { "Kodak DCS620X", + { 13095,-6231,154,12221,-21,-2137,895,4602,2258 } }, + { "Kodak DCS660C", + { 18244,-6351,-2739,-791,11193,-521,3711,-129,2802 } }, + { "Kodak DCS720X", + { 11775,-5884,950,9556,1846,-1286,-1019,6221,2728 } }, + { "Kodak DCS760C", + { 16623,-6309,-1411,-4344,13923,323,2285,274,2926 } }, + { "Kodak DCS Pro SLR", + { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } }, + { "Kodak DCS Pro 14nx", + { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } }, + { "Kodak DCS Pro 14", + { 7791,3128,-776,-8588,16458,2039,-2455,4006,6198 } }, + { "Kodak ProBack645", + { 16414,-6060,-1470,-3555,13037,473,2545,122,4948 } }, + { "Kodak ProBack", + { 21179,-8316,-2918,-915,11019,-165,3477,-180,4210 } }, + { "LEICA DIGILUX 2", + { 11340,-4069,-1275,-7555,15266,2448,-2960,3426,7685 } }, + { "Leaf Valeo", + { 8236,1746,-1314,-8251,15953,2428,-3673,5786,5771 } }, + { "Minolta DiMAGE 5", + { 8983,-2942,-963,-6556,14476,2237,-2426,2887,8014 } }, + { "Minolta DiMAGE 7", + { 9144,-2777,-998,-6676,14556,2281,-2470,3019,7744 } }, + { "Minolta DiMAGE A1", + { 9274,-2547,-1167,-8220,16323,1943,-2273,2720,8340 } }, + { "MINOLTA DiMAGE A200", + { 8560,-2487,-986,-8112,15535,2771,-1209,1324,7743 } }, + { "Minolta DiMAGE A2", + { 9097,-2726,-1053,-8073,15506,2762,-966,981,7763 } }, + { "MINOLTA DYNAX 7D", + { 10239,-3104,-1099,-8037,15727,2451,-927,925,6871 } }, + { "NIKON D100", + { 5915,-949,-778,-7516,15364,2282,-1228,1337,6404 } }, + { "NIKON D1H", + { 7577,-2166,-926,-7454,15592,1934,-2377,2808,8606 } }, + { "NIKON D1X", + { 7620,-2173,-966,-7604,15843,1805,-2356,2811,8439 } }, + { "NIKON D1", + { 7559,-2130,-965,-7611,15713,1972,-2478,3042,8290 } }, + { "NIKON D2H", + { 5710,-901,-615,-8594,16617,2024,-2975,4120,6830 } }, + { "NIKON D70", + { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } }, + { "NIKON E995", /* copied from E5000 */ + { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, + { "NIKON E2500", + { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, + { "NIKON E4500", + { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, + { "NIKON E5000", + { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, + { "NIKON E5400", + { 9349,-2987,-1001,-7919,15766,2266,-2098,2680,6839 } }, + { "NIKON E5700", + { -5368,11478,2368,5537,-113,3148,-4969,10021,5782,778,9028,211 } }, + { "NIKON E8400", + { 7842,-2320,-992,-8154,15718,2599,-1098,1342,7560 } }, + { "NIKON E8700", + { 8489,-2583,-1036,-8051,15583,2643,-1307,1407,7354 } }, + { "NIKON E8800", + { 7971,-2314,-913,-8451,15762,2894,-1442,1520,7610 } }, + { "OLYMPUS C5050", + { 10508,-3124,-1273,-6079,14294,1901,-1653,2306,6237 } }, + { "OLYMPUS C5060", + { 10445,-3362,-1307,-7662,15690,2058,-1135,1176,7602 } }, + { "OLYMPUS C70", + { 10793,-3791,-1146,-7498,15177,2488,-1390,1577,7321 } }, + { "OLYMPUS C80", + { 8606,-2509,-1014,-8238,15714,2703,-942,979,7760 } }, + { "OLYMPUS E-10", + { 12745,-4500,-1416,-6062,14542,1580,-1934,2256,6603 } }, + { "OLYMPUS E-1", + { 11846,-4767,-945,-7027,15878,1089,-2699,4122,8311 } }, + { "OLYMPUS E-20", + { 13173,-4732,-1499,-5807,14036,1895,-2045,2452,7142 } }, + { "OLYMPUS E-300", + { 7828,-1761,-348,-5788,14071,1830,-2853,4518,6557 } }, + { "PENTAX *ist D", + { 9651,-2059,-1189,-8881,16512,2487,-1460,1345,10687 } }, + { "Panasonic DMC-LC1", + { 11340,-4069,-1275,-7555,15266,2448,-2960,3426,7685 } }, + { "SONY DSC-F828", + { 7924,-1910,-777,-8226,15459,2998,-1517,2199,6818,-7242,11401, + 3481} }, + { "SONY DSC-V3", + { 9877,-3775,-871,-7613,14807,3072,-1448,1305,7485 } } + }; + double cc[4][4]; + double cm[4][3]; + double xyz[] = { 1,1,1 }; + char name[130]; + unsigned int i; - for (i=0; i < 4; i++) - for (j=0; j < 4; j++) - cc[i][j] = i == j; - sprintf (name, "%s %s", make, model); - for (i=0; i < sizeof table / sizeof *table; i++) - if (!strncmp (name, table[i].prefix, strlen(table[i].prefix))) { - for (j=0; j < 12; j++) - cm[0][j] = table[i].trans[j]; - dng_coeff (cc, cm, xyz); - break; + /* Make an identity matrix (1's on the diagonal) */ + for (i = 0; i < 4; ++i) { + unsigned int j; + for (j = 0; j < 4; ++j) + cc[i][j] = (i == j); + } + sprintf (name, "%s %s", make, model); + + for (i = 0; i < ARRAY_SIZE(table); ++i) { + const struct CoeffTableEntry * const entryP = &table[i]; + + if (strneq(name, entryP->prefix, strlen(entryP->prefix))) { + unsigned int j; + for (j = 0; j < 12; ++j) + cm[j/4][j%4] = entryP->trans[j]; + dng_coeff(cc, cm, xyz); + + break; + } } } -/* - Identify which camera created this file, and set global variables - accordingly. Return nonzero if the file cannot be decoded. - */ + + + int identify(FILE * const ifp, bool const use_secondary, @@ -252,932 +269,937 @@ identify(FILE * const ifp, float const blue_scale, unsigned int const four_color_rgb, const char * const inputFileName, - loadRawFn * const loadRawFnP) -{ - char head[32]; - char * c; - unsigned hlen, fsize, i; - static const struct { - int fsize; - char make[12], model[15], withjpeg; - } table[] = { - { 62464, "Kodak", "DC20" ,0 }, - { 124928, "Kodak", "DC20" ,0 }, - { 311696, "ST Micro", "STV680 VGA" ,0 }, /* SPYz */ - { 787456, "Creative", "PC-CAM 600" ,0 }, - { 2465792, "NIKON", "E950" ,1 }, /* or E800,E700 */ - { 2940928, "NIKON", "E2100" ,1 }, /* or E2500 */ - { 4771840, "NIKON", "E990" ,1 }, /* or E995 */ - { 4775936, "NIKON", "E3700" ,1 }, /* or Optio 33WR */ - { 5869568, "NIKON", "E4300" ,1 }, /* or DiMAGE Z2 */ - { 5865472, "NIKON", "E4500" ,0 }, - { 1976352, "CASIO", "QV-2000UX" ,0 }, - { 3217760, "CASIO", "QV-3*00EX" ,0 }, - { 6218368, "CASIO", "QV-5700" ,0 }, - { 7530816, "CASIO", "QV-R51" ,1 }, - { 7684000, "CASIO", "QV-4000" ,0 }, - { 7753344, "CASIO", "EX-Z55" ,1 }, - { 9313536, "CASIO", "EX-P600" ,1 }, - { 10979200, "CASIO", "EX-P700" ,1 }, - { 3178560, "PENTAX", "Optio S" ,1 }, /* 8-bit */ - { 4841984, "PENTAX", "Optio S" ,1 }, /* 12-bit */ - { 6114240, "PENTAX", "Optio S4" ,1 }, /* or S4i */ - { 12582980, "Sinar", "" ,0 } }; - static const char *corp[] = - { "Canon", "NIKON", "EPSON", "Kodak", "OLYMPUS", "PENTAX", - "MINOLTA", "Minolta", "Konica", "CASIO" }; - float tmp; - - /* What format is this file? Set make[] if we recognize it. */ + LoadRawFn ** const loadRawFnP) { +/*---------------------------------------------------------------------------- + Identify which camera created this file, and set global variables + accordingly. Return nonzero if the file cannot be decoded. +-----------------------------------------------------------------------------*/ + char head[32]; + char * c; + unsigned hlen, fsize, i; + static const struct { + int fsize; + char make[12], model[15], withjpeg; + } table[] = { + { 62464, "Kodak", "DC20" ,0 }, + { 124928, "Kodak", "DC20" ,0 }, + { 311696, "ST Micro", "STV680 VGA" ,0 }, /* SPYz */ + { 787456, "Creative", "PC-CAM 600" ,0 }, + { 2465792, "NIKON", "E950" ,1 }, /* or E800,E700 */ + { 2940928, "NIKON", "E2100" ,1 }, /* or E2500 */ + { 4771840, "NIKON", "E990" ,1 }, /* or E995 */ + { 4775936, "NIKON", "E3700" ,1 }, /* or Optio 33WR */ + { 5869568, "NIKON", "E4300" ,1 }, /* or DiMAGE Z2 */ + { 5865472, "NIKON", "E4500" ,0 }, + { 1976352, "CASIO", "QV-2000UX" ,0 }, + { 3217760, "CASIO", "QV-3*00EX" ,0 }, + { 6218368, "CASIO", "QV-5700" ,0 }, + { 7530816, "CASIO", "QV-R51" ,1 }, + { 7684000, "CASIO", "QV-4000" ,0 }, + { 7753344, "CASIO", "EX-Z55" ,1 }, + { 9313536, "CASIO", "EX-P600" ,1 }, + { 10979200, "CASIO", "EX-P700" ,1 }, + { 3178560, "PENTAX", "Optio S" ,1 }, /* 8-bit */ + { 4841984, "PENTAX", "Optio S" ,1 }, /* 12-bit */ + { 6114240, "PENTAX", "Optio S4" ,1 }, /* or S4i */ + { 12582980, "Sinar", "" ,0 } }; + static const char *corp[] = + { "Canon", "NIKON", "EPSON", "Kodak", "OLYMPUS", "PENTAX", + "MINOLTA", "Minolta", "Konica", "CASIO" }; + float tmp; + LoadRawFn * load_raw; - raw_height = raw_width = fuji_width = flip = 0; - make[0] = model[0] = model2[0] = 0; - memset (white, 0, sizeof white); - timestamp = tiff_samples = 0; - data_offset = meta_length = tiff_data_compression = 0; - zero_after_ff = is_dng = fuji_secondary = filters = 0; - black = is_foveon = use_coeff = 0; - use_gamma = xmag = ymag = 1; - for (i=0; i < 4; i++) { - cam_mul[i] = 1 & i; - pre_mul[i] = 1; - } - colors = 3; - for (i=0; i < 0x1000; i++) curve[i] = i; - maximum = 0xfff; -#ifdef USE_LCMS - profile_length = 0; -#endif + /* What format is this file? Set make[] if we recognize it. */ - order = get2(ifp); - hlen = get4(ifp); - fseek (ifp, 0, SEEK_SET); - fread (head, 1, 32, ifp); - fseek (ifp, 0, SEEK_END); - fsize = ftell(ifp); - if ((c = (char*)memmem_internal(head, 32, "MMMMRawT", 8))) { - strcpy (make, "Phase One"); - data_offset = c - head; - fseek (ifp, data_offset + 8, SEEK_SET); - fseek (ifp, get4(ifp) + 136, SEEK_CUR); - raw_width = get4(ifp); - fseek (ifp, 12, SEEK_CUR); - raw_height = get4(ifp); - } else if (order == 0x4949 || order == 0x4d4d) { - if (!memcmp (head+6, "HEAPCCDR", 8)) { - data_offset = hlen; - parse_ciff(ifp, hlen, fsize - hlen); - } else { - parse_tiff(ifp, 0); - if (!strncmp(make,"NIKON",5) && filters == 0) - make[0] = 0; + raw_height = raw_width = fuji_width = flip = 0; + make[0] = model[0] = model2[0] = 0; + memset (white, 0, sizeof white); + timestamp = tiff_samples = 0; + data_offset = meta_length = tiff_data_compression = 0; + zero_after_ff = is_dng = fuji_secondary = filters = 0; + black = is_foveon = use_coeff = 0; + use_gamma = xmag = ymag = 1; + for (i=0; i < 4; i++) { + cam_mul[i] = 1 & i; + pre_mul[i] = 1; } - } else if (!memcmp (head, "\0MRM", 4)) - parse_minolta(ifp); + colors = 3; + for (i=0; i < 0x1000; i++) curve[i] = i; + maximum = 0xfff; + + order = get2(ifp); + hlen = get4(ifp); + fseek (ifp, 0, SEEK_SET); + fread (head, 1, 32, ifp); + fseek (ifp, 0, SEEK_END); + fsize = ftell(ifp); + if ((c = (char*)memmem_internal(head, 32, "MMMMRawT", 8))) { + strcpy (make, "Phase One"); + data_offset = c - head; + fseek (ifp, data_offset + 8, SEEK_SET); + fseek (ifp, get4(ifp) + 136, SEEK_CUR); + raw_width = get4(ifp); + fseek (ifp, 12, SEEK_CUR); + raw_height = get4(ifp); + } else if (order == 0x4949 || order == 0x4d4d) { + if (!memcmp (head+6, "HEAPCCDR", 8)) { + data_offset = hlen; + parse_ciff(ifp, hlen, fsize - hlen); + } else { + parse_tiff(ifp, 0); + if (!strncmp(make,"NIKON",5) && filters == 0) + make[0] = 0; + } + } else if (!memcmp (head, "\0MRM", 4)) + parse_minolta(ifp); else if (!memcmp (head, "\xff\xd8\xff\xe1", 4) && - !memcmp (head+6, "Exif", 4)) { - fseek (ifp, 4, SEEK_SET); - fseek (ifp, 4 + get2(ifp), SEEK_SET); - if (fgetc(ifp) != 0xff) - parse_tiff(ifp, 12); - } else if (!memcmp (head, "BM", 2)) { - data_offset = 0x1000; - order = 0x4949; - fseek (ifp, 38, SEEK_SET); - if (get4(ifp) == 2834 && get4(ifp) == 2834) { - strcpy (model, "BMQ"); - flip = 3; - goto nucore; - } - } else if (!memcmp (head, "BR", 2)) { - strcpy (model, "RAW"); -nucore: - strcpy (make, "Nucore"); - order = 0x4949; - fseek (ifp, 10, SEEK_SET); - data_offset += get4(ifp); - get4(ifp); - raw_width = get4(ifp); - raw_height = get4(ifp); - if (model[0] == 'B' && raw_width == 2597) { - raw_width++; - data_offset -= 0x1000; - } - } else if (!memcmp (head+25, "ARECOYK", 7)) { - strcpy (make, "Contax"); - strcpy (model,"N Digital"); - fseek (ifp, 60, SEEK_SET); - camera_red = get4(ifp); - camera_red /= get4(ifp); - camera_blue = get4(ifp); - camera_blue = get4(ifp) / camera_blue; - } else if (!memcmp (head, "FUJIFILM", 8)) { - long data_offset_long; - fseek (ifp, 84, SEEK_SET); - parse_tiff(ifp, get4(ifp)+12); - fseek (ifp, 100, SEEK_SET); - pm_readbiglong(ifp, &data_offset_long); - data_offset = data_offset_long; - } else if (!memcmp (head, "DSC-Image", 9)) - parse_rollei(ifp); - else if (!memcmp (head, "FOVb", 4)) - parse_foveon(ifp); - else - for (i=0; i < sizeof table / sizeof *table; i++) - if (fsize == table[i].fsize) { - strcpy (make, table[i].make ); - strcpy (model, table[i].model); - if (table[i].withjpeg) - parse_external_jpeg(inputFileName); - } - parse_mos(ifp, 8); - parse_mos(ifp, 3472); + !memcmp (head+6, "Exif", 4)) { + fseek (ifp, 4, SEEK_SET); + fseek (ifp, 4 + get2(ifp), SEEK_SET); + if (fgetc(ifp) != 0xff) + parse_tiff(ifp, 12); + } else if (!memcmp (head, "BM", 2)) { + data_offset = 0x1000; + order = 0x4949; + fseek (ifp, 38, SEEK_SET); + if (get4(ifp) == 2834 && get4(ifp) == 2834) { + strcpy (model, "BMQ"); + flip = 3; + goto nucore; + } + } else if (!memcmp (head, "BR", 2)) { + strcpy (model, "RAW"); + nucore: + strcpy (make, "Nucore"); + order = 0x4949; + fseek (ifp, 10, SEEK_SET); + data_offset += get4(ifp); + get4(ifp); + raw_width = get4(ifp); + raw_height = get4(ifp); + if (model[0] == 'B' && raw_width == 2597) { + raw_width++; + data_offset -= 0x1000; + } + } else if (!memcmp (head+25, "ARECOYK", 7)) { + strcpy (make, "Contax"); + strcpy (model,"N Digital"); + fseek (ifp, 60, SEEK_SET); + camera_red = get4(ifp); + camera_red /= get4(ifp); + camera_blue = get4(ifp); + camera_blue = get4(ifp) / camera_blue; + } else if (!memcmp (head, "FUJIFILM", 8)) { + long data_offset_long; + fseek (ifp, 84, SEEK_SET); + parse_tiff(ifp, get4(ifp)+12); + fseek (ifp, 100, SEEK_SET); + pm_readbiglong(ifp, &data_offset_long); + data_offset = data_offset_long; + } else if (!memcmp (head, "DSC-Image", 9)) + parse_rollei(ifp); + else if (!memcmp (head, "FOVb", 4)) + parse_foveon(ifp); + else + for (i=0; i < sizeof table / sizeof *table; i++) + if (fsize == table[i].fsize) { + strcpy (make, table[i].make ); + strcpy (model, table[i].model); + if (table[i].withjpeg) + parse_external_jpeg(inputFileName); + } + parse_mos(ifp, 8); + parse_mos(ifp, 3472); + + for (i=0; i < sizeof corp / sizeof *corp; i++) + if (strstr (make, corp[i])) /* Simplify company names */ + strcpy (make, corp[i]); + if (!strncmp (make, "KODAK", 5)) + make[16] = model[16] = 0; + c = make + strlen(make); /* Remove trailing spaces */ + while (*--c == ' ') *c = 0; + c = model + strlen(model); + while (*--c == ' ') *c = 0; + i = strlen(make); /* Remove make from model */ + if (!strncmp (model, make, i++)) + memmove (model, model+i, 64-i); + make[63] = model[63] = model2[63] = 0; - for (i=0; i < sizeof corp / sizeof *corp; i++) - if (strstr (make, corp[i])) /* Simplify company names */ - strcpy (make, corp[i]); - if (!strncmp (make, "KODAK", 5)) - make[16] = model[16] = 0; - c = make + strlen(make); /* Remove trailing spaces */ - while (*--c == ' ') *c = 0; - c = model + strlen(model); - while (*--c == ' ') *c = 0; - i = strlen(make); /* Remove make from model */ - if (!strncmp (model, make, i++)) - memmove (model, model+i, 64-i); - make[63] = model[63] = model2[63] = 0; + if (verbose) + fprintf(stderr, "Make = '%s', Model = '%s'\n", make, model); - if (make[0] == 0) { - pm_message ("unrecognized file format."); - return 1; - } + if (make[0] == 0) { + pm_message ("unrecognized file format."); + return 1; + } /* File format is OK. Do we know this camera? */ /* Start with some useful defaults: */ - top_margin = left_margin = 0; - if ((raw_height | raw_width) < 0) - raw_height = raw_width = 0; - height = raw_height; - width = raw_width; - if (fuji_width) { - width = height + fuji_width; - height = width - 1; - ymag = 1; - } - load_raw = NULL; - if (is_dng) { - strcat (model, " DNG"); - if (!filters) - colors = tiff_samples; - if (tiff_data_compression == 1) - load_raw = adobe_dng_load_raw_nc; - if (tiff_data_compression == 7) - load_raw = adobe_dng_load_raw_lj; - goto dng_skip; - } + top_margin = left_margin = 0; + if ((raw_height | raw_width) < 0) + raw_height = raw_width = 0; + height = raw_height; + width = raw_width; + if (fuji_width) { + width = height + fuji_width; + height = width - 1; + ymag = 1; + } + load_raw = NULL; + if (is_dng) { + strcat (model, " DNG"); + if (!filters) + colors = tiff_samples; + if (tiff_data_compression == 1) + load_raw = adobe_dng_load_raw_nc; + if (tiff_data_compression == 7) + load_raw = adobe_dng_load_raw_lj; + goto dng_skip; + } -/* We'll try to decode anything from Canon or Nikon. */ + /* We'll try to decode anything from Canon or Nikon. */ - if (!filters) filters = 0x94949494; - if ((is_canon = !strcmp(make,"Canon"))) - load_raw = memcmp (head+6,"HEAPCCDR",8) ? - lossless_jpeg_load_raw : canon_compressed_load_raw; - if (!strcmp(make,"NIKON")) - load_raw = nikon_is_compressed() ? - nikon_compressed_load_raw : nikon_load_raw; + if (!filters) filters = 0x94949494; + if ((is_canon = !strcmp(make,"Canon"))) + load_raw = memcmp (head+6,"HEAPCCDR",8) ? + lossless_jpeg_load_raw : canon_compressed_load_raw; + if (!strcmp(make,"NIKON")) + load_raw = nikon_is_compressed() ? + nikon_compressed_load_raw : nikon_load_raw; -/* Set parameters based on camera name (for non-DNG files). */ + /* Set parameters based on camera name (for non-DNG files). */ - if (is_foveon) { - if (!have64BitArithmetic) - pm_error("This program was built without 64 bit arithmetic " - "capability and the Foveon format requires it."); - if (height*2 < width) ymag = 2; - if (width < height) xmag = 2; - filters = 0; - load_raw = foveon_load_raw; - foveon_coeff(&use_coeff, coeff); - } else if (!strcmp(model,"PowerShot 600")) { - height = 613; - width = 854; - colors = 4; - filters = 0xe1e4e1e4; - load_raw = canon_600_load_raw; - } else if (!strcmp(model,"PowerShot A5") || - !strcmp(model,"PowerShot A5 Zoom")) { - height = 773; - width = 960; - raw_width = 992; - colors = 4; - filters = 0x1e4e1e4e; - load_raw = canon_a5_load_raw; - } else if (!strcmp(model,"PowerShot A50")) { - height = 968; - width = 1290; - raw_width = 1320; - colors = 4; - filters = 0x1b4e4b1e; - load_raw = canon_a5_load_raw; - } else if (!strcmp(model,"PowerShot Pro70")) { - height = 1024; - width = 1552; - colors = 4; - filters = 0x1e4b4e1b; - load_raw = canon_a5_load_raw; - black = 34; - } else if (!strcmp(model,"PowerShot Pro90 IS")) { - width = 1896; - colors = 4; - filters = 0xb4b4b4b4; - } else if (is_canon && raw_width == 2144) { - height = 1550; - width = 2088; - top_margin = 8; - left_margin = 4; - if (!strcmp(model,"PowerShot G1")) { - colors = 4; - filters = 0xb4b4b4b4; - } - } else if (is_canon && raw_width == 2224) { - height = 1448; - width = 2176; - top_margin = 6; - left_margin = 48; - } else if (is_canon && raw_width == 2376) { - height = 1720; - width = 2312; - top_margin = 6; - left_margin = 12; - } else if (is_canon && raw_width == 2672) { - height = 1960; - width = 2616; - top_margin = 6; - left_margin = 12; - } else if (is_canon && raw_width == 3152) { - height = 2056; - width = 3088; - top_margin = 12; - left_margin = 64; - maximum = 0xfa0; - } else if (is_canon && raw_width == 3160) { - height = 2328; - width = 3112; - top_margin = 12; - left_margin = 44; - } else if (is_canon && raw_width == 3344) { - height = 2472; - width = 3288; - top_margin = 6; - left_margin = 4; - } else if (!strcmp(model,"EOS D2000C")) { - filters = 0x61616161; - black = curve[200]; - } else if (!strcmp(model,"EOS-1D")) { - raw_height = height = 1662; - raw_width = width = 2496; - data_offset = 288912; - filters = 0x61616161; - } else if (!strcmp(model,"EOS-1DS")) { - raw_height = height = 2718; - raw_width = width = 4082; - data_offset = 289168; - filters = 0x61616161; - } else if (is_canon && raw_width == 3516) { - top_margin = 14; - left_margin = 42; - goto canon_cr2; - } else if (is_canon && raw_width == 3596) { - top_margin = 12; - left_margin = 74; - goto canon_cr2; - } else if (is_canon && raw_width == 5108) { - top_margin = 13; - left_margin = 98; - maximum = 0xe80; -canon_cr2: - height = raw_height - top_margin; - width = raw_width - left_margin; - } else if (!strcmp(model,"D1")) { - camera_red *= 256/527.0; - camera_blue *= 256/317.0; - } else if (!strcmp(model,"D1X")) { - width = 4024; - ymag = 2; - } else if (!strcmp(model,"D100")) { - if (tiff_data_compression == 34713 && load_raw == nikon_load_raw) - raw_width = (width += 3) + 3; - } else if (!strcmp(model,"D2H")) { - width = 2482; - left_margin = 6; - } else if (!strcmp(model,"D2X")) { - width = 4312; - pre_mul[0] = 1.514; - pre_mul[2] = 1.727; - } else if (fsize == 2465792) { - height = 1203; - width = 1616; - filters = 0x4b4b4b4b; - colors = 4; - load_raw = nikon_e950_load_raw; - nikon_e950_coeff(); - pre_mul[0] = 1.18193; - pre_mul[2] = 1.16452; - pre_mul[3] = 1.17250; - } else if (!strcmp(model,"E990")) { - if (!timestamp && !nikon_e990()) goto cp_e995; - height = 1540; - width = 2064; - colors = 4; - filters = 0xb4b4b4b4; - nikon_e950_coeff(); - pre_mul[0] = 1.196; - pre_mul[1] = 1.246; - pre_mul[2] = 1.018; - } else if (!strcmp(model,"E995")) { -cp_e995: - strcpy (model, "E995"); - height = 1540; - width = 2064; - colors = 4; - filters = 0xe1e1e1e1; - } else if (!strcmp(model,"E2100")) { - if (!timestamp && !nikon_e2100()) goto cp_e2500; - width = 1616; - height = 1206; - load_raw = nikon_e2100_load_raw; - pre_mul[0] = 1.945; - pre_mul[2] = 1.040; - } else if (!strcmp(model,"E2500")) { -cp_e2500: - strcpy (model, "E2500"); - width = 1616; - height = 1204; - colors = 4; - filters = 0x4b4b4b4b; - } else if (!strcmp(model,"E3700")) { - if (!timestamp && pentax_optio33()) goto optio_33wr; - height = 1542; - width = 2064; - load_raw = nikon_e2100_load_raw; - pre_mul[0] = 1.818; - pre_mul[2] = 1.618; - } else if (!strcmp(model,"Optio 33WR")) { -optio_33wr: - strcpy (make, "PENTAX"); - strcpy (model,"Optio 33WR"); - height = 1542; - width = 2064; - load_raw = nikon_e2100_load_raw; - flip = 1; - filters = 0x16161616; - pre_mul[0] = 1.331; - pre_mul[2] = 1.820; - } else if (!strcmp(model,"E4300")) { - if (!timestamp && minolta_z2()) goto dimage_z2; - height = 1710; - width = 2288; - filters = 0x16161616; - pre_mul[0] = 508; - pre_mul[1] = 256; - pre_mul[2] = 322; - } else if (!strcmp(model,"DiMAGE Z2")) { -dimage_z2: - strcpy (make, "MINOLTA"); - strcpy (model,"DiMAGE Z2"); - height = 1710; - width = 2288; - filters = 0x16161616; - load_raw = nikon_e2100_load_raw; - pre_mul[0] = 508; - pre_mul[1] = 256; - pre_mul[2] = 450; - } else if (!strcmp(model,"E4500")) { - height = 1708; - width = 2288; - colors = 4; - filters = 0xb4b4b4b4; - } else if (!strcmp(model,"R-D1")) { - tiff_data_compression = 34713; - load_raw = nikon_load_raw; - } else if (!strcmp(model,"FinePixS2Pro")) { - height = 3584; - width = 3583; - fuji_width = 2144; - filters = 0x61616161; - load_raw = fuji_s2_load_raw; - black = 128; - strcpy (model+7, " S2Pro"); - } else if (!strcmp(model,"FinePix S3Pro")) { - height = 3583; - width = 3584; - fuji_width = 2144; - if (fsize > 18000000 && use_secondary) - data_offset += 4352*2*1444; - filters = 0x49494949; - load_raw = fuji_s3_load_raw; - maximum = 0xffff; - } else if (!strcmp(model,"FinePix S5000")) { - height = 2499; - width = 2500; - fuji_width = 1423; - filters = 0x49494949; - load_raw = fuji_s5000_load_raw; - maximum = 0x3e00; - } else if (!strcmp(model,"FinePix S5100") || - !strcmp(model,"FinePix S5500")) { - height = 1735; - width = 2304; - data_offset += width*10; - filters = 0x49494949; - load_raw = unpacked_load_raw; - maximum = 0xffff; - } else if (!strcmp(model,"FinePix E550") || - !strcmp(model,"FinePix F810") || - !strcmp(model,"FinePix S7000")) { - height = 3587; - width = 3588; - fuji_width = 2047; - filters = 0x49494949; - load_raw = fuji_s7000_load_raw; - maximum = 0x3e00; - } else if (!strcmp(model,"FinePix F700") || - !strcmp(model,"FinePix S20Pro")) { - height = 2523; - width = 2524; - fuji_width = 1440; - filters = 0x49494949; - load_raw = fuji_f700_load_raw; - maximum = 0x3e00; - } else if (!strcmp(model,"Digital Camera KD-400Z")) { - height = 1712; - width = 2312; - raw_width = 2336; - data_offset = 4034; - fseek (ifp, 2032, SEEK_SET); - goto konica_400z; - } else if (!strcmp(model,"Digital Camera KD-510Z")) { - data_offset = 4032; - pre_mul[0] = 1.297; - pre_mul[2] = 1.438; - fseek (ifp, 2032, SEEK_SET); - goto konica_510z; - } else if (!strcasecmp(make,"MINOLTA")) { - load_raw = unpacked_load_raw; - maximum = 0xf7d; - if (!strncmp(model,"DiMAGE A",8)) { - if (!strcmp(model,"DiMAGE A200")) { - filters = 0x49494949; - tmp = camera_red; - camera_red = 1 / camera_blue; - camera_blue = 1 / tmp; - } - load_raw = packed_12_load_raw; - maximum = model[8] == '1' ? 0xf8b : 0xfff; - } else if (!strncmp(model,"ALPHA",5) || - !strncmp(model,"DYNAX",5) || - !strncmp(model,"MAXXUM",6)) { - load_raw = packed_12_load_raw; - maximum = 0xffb; - } else if (!strncmp(model,"DiMAGE G",8)) { - if (model[8] == '4') { - data_offset = 5056; - pre_mul[0] = 1.602; - pre_mul[2] = 1.441; - fseek (ifp, 2078, SEEK_SET); - height = 1716; - width = 2304; - } else if (model[8] == '5') { - data_offset = 4016; - fseek (ifp, 1936, SEEK_SET); -konica_510z: - height = 1956; - width = 2607; - raw_width = 2624; - } else if (model[8] == '6') { - data_offset = 4032; - fseek (ifp, 2030, SEEK_SET); - height = 2136; - width = 2848; - } - filters = 0x61616161; -konica_400z: - load_raw = unpacked_load_raw; - maximum = 0x3df; - order = 0x4d4d; - camera_red = get2(ifp); - camera_blue = get2(ifp); - camera_red /= get2(ifp); - camera_blue /= get2(ifp); - } - if (pre_mul[0] == 1 && pre_mul[2] == 1) { - pre_mul[0] = 1.42; - pre_mul[2] = 1.25; - } - } else if (!strcmp(model,"*ist D")) { - load_raw = unpacked_load_raw; - } else if (!strcmp(model,"*ist DS")) { - height--; - load_raw = packed_12_load_raw; - } else if (!strcmp(model,"Optio S")) { - if (fsize == 3178560) { - height = 1540; - width = 2064; - load_raw = eight_bit_load_raw; - camera_red *= 4; - camera_blue *= 4; - pre_mul[0] = 1.391; - pre_mul[2] = 1.188; - } else { - height = 1544; - width = 2068; - raw_width = 3136; - load_raw = packed_12_load_raw; - maximum = 0xf7c; - pre_mul[0] = 1.137; - pre_mul[2] = 1.453; - } - } else if (!strncmp(model,"Optio S4",8)) { - height = 1737; - width = 2324; - raw_width = 3520; - load_raw = packed_12_load_raw; - maximum = 0xf7a; - pre_mul[0] = 1.980; - pre_mul[2] = 1.570; - } else if (!strcmp(model,"STV680 VGA")) { - height = 484; - width = 644; - load_raw = eight_bit_load_raw; - flip = 2; - filters = 0x16161616; - black = 16; - pre_mul[0] = 1.097; - pre_mul[2] = 1.128; - } else if (!strcmp(make,"Phase One")) { - switch (raw_height) { - case 2060: - strcpy (model, "LightPhase"); - height = 2048; - width = 3080; - top_margin = 5; - left_margin = 22; - pre_mul[0] = 1.331; - pre_mul[2] = 1.154; - break; - case 2682: - strcpy (model, "H10"); - height = 2672; - width = 4012; - top_margin = 5; - left_margin = 26; - break; - case 4128: - strcpy (model, "H20"); - height = 4098; - width = 4098; - top_margin = 20; - left_margin = 26; - pre_mul[0] = 1.963; - pre_mul[2] = 1.430; - break; - case 5488: - strcpy (model, "H25"); - height = 5458; - width = 4098; - top_margin = 20; - left_margin = 26; - pre_mul[0] = 2.80; - pre_mul[2] = 1.20; - } - filters = top_margin & 1 ? 0x94949494 : 0x49494949; - load_raw = phase_one_load_raw; - maximum = 0xffff; - } else if (!strcmp(model,"Ixpress")) { - height = 4084; - width = 4080; - filters = 0x49494949; - load_raw = ixpress_load_raw; - maximum = 0xffff; - pre_mul[0] = 1.963; - pre_mul[2] = 1.430; - } else if (!strcmp(make,"Sinar") && !memcmp(head,"8BPS",4)) { - fseek (ifp, 14, SEEK_SET); - height = get4(ifp); - width = get4(ifp); - filters = 0x61616161; - data_offset = 68; - load_raw = unpacked_load_raw; - maximum = 0xffff; - } else if (!strcmp(make,"Leaf")) { - if (height > width) - filters = 0x16161616; - load_raw = unpacked_load_raw; - maximum = 0x3fff; - strcpy (model, "Valeo"); - if (raw_width == 2060) { - filters = 0; - load_raw = leaf_load_raw; - maximum = 0xffff; - strcpy (model, "Volare"); - } - } else if (!strcmp(model,"DIGILUX 2") || !strcmp(model,"DMC-LC1")) { - height = 1928; - width = 2568; - data_offset = 1024; - load_raw = unpacked_load_raw; - maximum = 0xfff0; - } else if (!strcmp(model,"E-1")) { - filters = 0x61616161; - load_raw = unpacked_load_raw; - maximum = 0xfff0; - black = 1024; - } else if (!strcmp(model,"E-10")) { - load_raw = unpacked_load_raw; - maximum = 0xfff0; - black = 2048; - } else if (!strncmp(model,"E-20",4)) { - load_raw = unpacked_load_raw; - maximum = 0xffc0; - black = 2560; - } else if (!strcmp(model,"E-300")) { - width -= 21; - load_raw = olympus_e300_load_raw; - if (fsize > 15728640) { - load_raw = unpacked_load_raw; - maximum = 0xfc30; - } else - black = 62; - } else if (!strcmp(make,"OLYMPUS")) { - load_raw = olympus_cseries_load_raw; - if (!strcmp(model,"C5050Z") || - !strcmp(model,"C8080WZ")) - filters = 0x16161616; - } else if (!strcmp(model,"N Digital")) { - height = 2047; - width = 3072; - filters = 0x61616161; - data_offset = 0x1a00; - load_raw = packed_12_load_raw; - maximum = 0xf1e; - } else if (!strcmp(model,"DSC-F828")) { - width = 3288; - left_margin = 5; - load_raw = sony_load_raw; - filters = 0x9c9c9c9c; - colors = 4; - black = 491; - } else if (!strcmp(model,"DSC-V3")) { - width = 3109; - left_margin = 59; - load_raw = sony_load_raw; - } else if (!strcasecmp(make,"KODAK")) { - filters = 0x61616161; - if (!strcmp(model,"NC2000F")) { - width -= 4; - left_margin = 1; - for (i=176; i < 0x1000; i++) - curve[i] = curve[i-1]; - pre_mul[0] = 1.509; - pre_mul[2] = 2.686; - } else if (!strcmp(model,"EOSDCS3B")) { - width -= 4; - left_margin = 2; - } else if (!strcmp(model,"EOSDCS1")) { - width -= 4; - left_margin = 2; - } else if (!strcmp(model,"DCS315C")) { - black = 8; - } else if (!strcmp(model,"DCS330C")) { - black = 8; - } else if (!strcmp(model,"DCS420")) { - width -= 4; - left_margin = 2; - } else if (!strcmp(model,"DCS460")) { - width -= 4; - left_margin = 2; - } else if (!strcmp(model,"DCS460A")) { - width -= 4; - left_margin = 2; - colors = 1; - filters = 0; - } else if (!strcmp(model,"DCS520C")) { - black = 180; - } else if (!strcmp(model,"DCS560C")) { - black = 188; - } else if (!strcmp(model,"DCS620C")) { - black = 180; - } else if (!strcmp(model,"DCS620X")) { - black = 185; - } else if (!strcmp(model,"DCS660C")) { - black = 214; - } else if (!strcmp(model,"DCS660M")) { - black = 214; - colors = 1; - filters = 0; - } else if (!strcmp(model,"DCS760M")) { - colors = 1; - filters = 0; - } - switch (tiff_data_compression) { - case 0: /* No compression */ - case 1: - load_raw = kodak_easy_load_raw; - break; - case 7: /* Lossless JPEG */ - load_raw = lossless_jpeg_load_raw; - case 32867: - break; - case 65000: /* Kodak DCR compression */ + if (is_foveon) { if (!have64BitArithmetic) pm_error("This program was built without 64 bit arithmetic " - "capability, and Kodak DCR compression requires it."); - if (kodak_data_compression == 32803) - load_raw = kodak_compressed_load_raw; - else { - load_raw = kodak_yuv_load_raw; - height = (height+1) & -2; - width = (width +1) & -2; + "capability and the Foveon format requires it."); + if (height*2 < width) ymag = 2; + if (width < height) xmag = 2; + filters = 0; + load_raw = foveon_load_raw; + foveon_coeff(&use_coeff, coeff); + } else if (!strcmp(model,"PowerShot 600")) { + height = 613; + width = 854; + colors = 4; + filters = 0xe1e4e1e4; + load_raw = canon_600_load_raw; + } else if (!strcmp(model,"PowerShot A5") || + !strcmp(model,"PowerShot A5 Zoom")) { + height = 773; + width = 960; + raw_width = 992; + colors = 4; + filters = 0x1e4e1e4e; + load_raw = canon_a5_load_raw; + } else if (!strcmp(model,"PowerShot A50")) { + height = 968; + width = 1290; + raw_width = 1320; + colors = 4; + filters = 0x1b4e4b1e; + load_raw = canon_a5_load_raw; + } else if (!strcmp(model,"PowerShot Pro70")) { + height = 1024; + width = 1552; + colors = 4; + filters = 0x1e4b4e1b; + load_raw = canon_a5_load_raw; + black = 34; + } else if (!strcmp(model,"PowerShot Pro90 IS")) { + width = 1896; + colors = 4; + filters = 0xb4b4b4b4; + } else if (is_canon && raw_width == 2144) { + height = 1550; + width = 2088; + top_margin = 8; + left_margin = 4; + if (!strcmp(model,"PowerShot G1")) { + colors = 4; + filters = 0xb4b4b4b4; + } + } else if (is_canon && raw_width == 2224) { + height = 1448; + width = 2176; + top_margin = 6; + left_margin = 48; + } else if (is_canon && raw_width == 2376) { + height = 1720; + width = 2312; + top_margin = 6; + left_margin = 12; + } else if (is_canon && raw_width == 2672) { + height = 1960; + width = 2616; + top_margin = 6; + left_margin = 12; + } else if (is_canon && raw_width == 3152) { + height = 2056; + width = 3088; + top_margin = 12; + left_margin = 64; + maximum = 0xfa0; + } else if (is_canon && raw_width == 3160) { + height = 2328; + width = 3112; + top_margin = 12; + left_margin = 44; + } else if (is_canon && raw_width == 3344) { + height = 2472; + width = 3288; + top_margin = 6; + left_margin = 4; + } else if (!strcmp(model,"EOS D2000C")) { + filters = 0x61616161; + black = curve[200]; + } else if (!strcmp(model,"EOS-1D")) { + raw_height = height = 1662; + raw_width = width = 2496; + data_offset = 288912; + filters = 0x61616161; + } else if (!strcmp(model,"EOS-1DS")) { + raw_height = height = 2718; + raw_width = width = 4082; + data_offset = 289168; + filters = 0x61616161; + } else if (is_canon && raw_width == 3516) { + top_margin = 14; + left_margin = 42; + goto canon_cr2; + } else if (is_canon && raw_width == 3596) { + top_margin = 12; + left_margin = 74; + goto canon_cr2; + } else if (is_canon && raw_width == 5108) { + top_margin = 13; + left_margin = 98; + maximum = 0xe80; + canon_cr2: + height = raw_height - top_margin; + width = raw_width - left_margin; + } else if (!strcmp(model,"D1")) { + camera_red *= 256/527.0; + camera_blue *= 256/317.0; + } else if (!strcmp(model,"D1X")) { + width = 4024; + ymag = 2; + } else if (!strcmp(model,"D100")) { + if (tiff_data_compression == 34713 && load_raw == nikon_load_raw) + raw_width = (width += 3) + 3; + } else if (!strcmp(model,"D2H")) { + width = 2482; + left_margin = 6; + } else if (!strcmp(model,"D2X")) { + width = 4312; + pre_mul[0] = 1.514; + pre_mul[2] = 1.727; + } else if (fsize == 2465792) { + height = 1203; + width = 1616; + filters = 0x4b4b4b4b; + colors = 4; + load_raw = nikon_e950_load_raw; + nikon_e950_coeff(); + pre_mul[0] = 1.18193; + pre_mul[2] = 1.16452; + pre_mul[3] = 1.17250; + } else if (!strcmp(model,"E990")) { + if (!timestamp && !nikon_e990()) goto cp_e995; + height = 1540; + width = 2064; + colors = 4; + filters = 0xb4b4b4b4; + nikon_e950_coeff(); + pre_mul[0] = 1.196; + pre_mul[1] = 1.246; + pre_mul[2] = 1.018; + } else if (!strcmp(model,"E995")) { + cp_e995: + strcpy (model, "E995"); + height = 1540; + width = 2064; + colors = 4; + filters = 0xe1e1e1e1; + } else if (!strcmp(model,"E2100")) { + if (!timestamp && !nikon_e2100()) goto cp_e2500; + width = 1616; + height = 1206; + load_raw = nikon_e2100_load_raw; + pre_mul[0] = 1.945; + pre_mul[2] = 1.040; + } else if (!strcmp(model,"E2500")) { + cp_e2500: + strcpy (model, "E2500"); + width = 1616; + height = 1204; + colors = 4; + filters = 0x4b4b4b4b; + } else if (!strcmp(model,"E3700")) { + if (!timestamp && pentax_optio33()) goto optio_33wr; + height = 1542; + width = 2064; + load_raw = nikon_e2100_load_raw; + pre_mul[0] = 1.818; + pre_mul[2] = 1.618; + } else if (!strcmp(model,"Optio 33WR")) { + optio_33wr: + strcpy (make, "PENTAX"); + strcpy (model,"Optio 33WR"); + height = 1542; + width = 2064; + load_raw = nikon_e2100_load_raw; + flip = 1; + filters = 0x16161616; + pre_mul[0] = 1.331; + pre_mul[2] = 1.820; + } else if (!strcmp(model,"E4300")) { + if (!timestamp && minolta_z2()) goto dimage_z2; + height = 1710; + width = 2288; + filters = 0x16161616; + pre_mul[0] = 508; + pre_mul[1] = 256; + pre_mul[2] = 322; + } else if (!strcmp(model,"DiMAGE Z2")) { + dimage_z2: + strcpy (make, "MINOLTA"); + strcpy (model,"DiMAGE Z2"); + height = 1710; + width = 2288; + filters = 0x16161616; + load_raw = nikon_e2100_load_raw; + pre_mul[0] = 508; + pre_mul[1] = 256; + pre_mul[2] = 450; + } else if (!strcmp(model,"E4500")) { + height = 1708; + width = 2288; + colors = 4; + filters = 0xb4b4b4b4; + } else if (!strcmp(model,"R-D1")) { + tiff_data_compression = 34713; + load_raw = nikon_load_raw; + } else if (!strcmp(model,"FinePixS2Pro")) { + height = 3584; + width = 3583; + fuji_width = 2144; + filters = 0x61616161; + load_raw = fuji_s2_load_raw; + black = 128; + strcpy (model+7, " S2Pro"); + } else if (!strcmp(model,"FinePix S3Pro")) { + height = 3583; + width = 3584; + fuji_width = 2144; + if (fsize > 18000000 && use_secondary) + data_offset += 4352*2*1444; + filters = 0x49494949; + load_raw = fuji_s3_load_raw; + maximum = 0xffff; + } else if (!strcmp(model,"FinePix S5000")) { + height = 2499; + width = 2500; + fuji_width = 1423; + filters = 0x49494949; + load_raw = fuji_s5000_load_raw; + maximum = 0x3e00; + } else if (!strcmp(model,"FinePix S5100") || + !strcmp(model,"FinePix S5500")) { + height = 1735; + width = 2304; + data_offset += width*10; + filters = 0x49494949; + load_raw = unpacked_load_raw; + maximum = 0xffff; + } else if (!strcmp(model,"FinePix E550") || + !strcmp(model,"FinePix F810") || + !strcmp(model,"FinePix S7000")) { + height = 3587; + width = 3588; + fuji_width = 2047; + filters = 0x49494949; + load_raw = fuji_s7000_load_raw; + maximum = 0x3e00; + } else if (!strcmp(model,"FinePix F700") || + !strcmp(model,"FinePix S20Pro")) { + height = 2523; + width = 2524; + fuji_width = 1440; + filters = 0x49494949; + load_raw = fuji_f700_load_raw; + maximum = 0x3e00; + } else if (!strcmp(model,"Digital Camera KD-400Z")) { + height = 1712; + width = 2312; + raw_width = 2336; + data_offset = 4034; + fseek (ifp, 2032, SEEK_SET); + goto konica_400z; + } else if (!strcmp(model,"Digital Camera KD-510Z")) { + data_offset = 4032; + pre_mul[0] = 1.297; + pre_mul[2] = 1.438; + fseek (ifp, 2032, SEEK_SET); + goto konica_510z; + } else if (!strcasecmp(make,"MINOLTA")) { + load_raw = unpacked_load_raw; + maximum = 0xf7d; + if (!strncmp(model,"DiMAGE A",8)) { + if (!strcmp(model,"DiMAGE A200")) { + filters = 0x49494949; + tmp = camera_red; + camera_red = 1 / camera_blue; + camera_blue = 1 / tmp; + } + load_raw = packed_12_load_raw; + maximum = model[8] == '1' ? 0xf8b : 0xfff; + } else if (!strncmp(model,"ALPHA",5) || + !strncmp(model,"DYNAX",5) || + !strncmp(model,"MAXXUM",6)) { + load_raw = packed_12_load_raw; + maximum = 0xffb; + } else if (!strncmp(model,"DiMAGE G",8)) { + if (model[8] == '4') { + data_offset = 5056; + pre_mul[0] = 1.602; + pre_mul[2] = 1.441; + fseek (ifp, 2078, SEEK_SET); + height = 1716; + width = 2304; + } else if (model[8] == '5') { + data_offset = 4016; + fseek (ifp, 1936, SEEK_SET); + konica_510z: + height = 1956; + width = 2607; + raw_width = 2624; + } else if (model[8] == '6') { + data_offset = 4032; + fseek (ifp, 2030, SEEK_SET); + height = 2136; + width = 2848; + } + filters = 0x61616161; + konica_400z: + load_raw = unpacked_load_raw; + maximum = 0x3df; + order = 0x4d4d; + camera_red = get2(ifp); + camera_blue = get2(ifp); + camera_red /= get2(ifp); + camera_blue /= get2(ifp); + } + if (pre_mul[0] == 1 && pre_mul[2] == 1) { + pre_mul[0] = 1.42; + pre_mul[2] = 1.25; + } + } else if (!strcmp(model,"*ist D")) { + load_raw = unpacked_load_raw; + } else if (!strcmp(model,"*ist DS")) { + height--; + load_raw = packed_12_load_raw; + } else if (!strcmp(model,"Optio S")) { + if (fsize == 3178560) { + height = 1540; + width = 2064; + load_raw = eight_bit_load_raw; + camera_red *= 4; + camera_blue *= 4; + pre_mul[0] = 1.391; + pre_mul[2] = 1.188; + } else { + height = 1544; + width = 2068; + raw_width = 3136; + load_raw = packed_12_load_raw; + maximum = 0xf7c; + pre_mul[0] = 1.137; + pre_mul[2] = 1.453; + } + } else if (!strncmp(model,"Optio S4",8)) { + height = 1737; + width = 2324; + raw_width = 3520; + load_raw = packed_12_load_raw; + maximum = 0xf7a; + pre_mul[0] = 1.980; + pre_mul[2] = 1.570; + } else if (!strcmp(model,"STV680 VGA")) { + height = 484; + width = 644; + load_raw = eight_bit_load_raw; + flip = 2; + filters = 0x16161616; + black = 16; + pre_mul[0] = 1.097; + pre_mul[2] = 1.128; + } else if (!strcmp(make,"Phase One")) { + switch (raw_height) { + case 2060: + strcpy (model, "LightPhase"); + height = 2048; + width = 3080; + top_margin = 5; + left_margin = 22; + pre_mul[0] = 1.331; + pre_mul[2] = 1.154; + break; + case 2682: + strcpy (model, "H10"); + height = 2672; + width = 4012; + top_margin = 5; + left_margin = 26; + break; + case 4128: + strcpy (model, "H20"); + height = 4098; + width = 4098; + top_margin = 20; + left_margin = 26; + pre_mul[0] = 1.963; + pre_mul[2] = 1.430; + break; + case 5488: + strcpy (model, "H25"); + height = 5458; + width = 4098; + top_margin = 20; + left_margin = 26; + pre_mul[0] = 2.80; + pre_mul[2] = 1.20; + } + filters = top_margin & 1 ? 0x94949494 : 0x49494949; + load_raw = phase_one_load_raw; + maximum = 0xffff; + } else if (!strcmp(model,"Ixpress")) { + height = 4084; + width = 4080; + filters = 0x49494949; + load_raw = ixpress_load_raw; + maximum = 0xffff; + pre_mul[0] = 1.963; + pre_mul[2] = 1.430; + } else if (!strcmp(make,"Sinar") && !memcmp(head,"8BPS",4)) { + fseek (ifp, 14, SEEK_SET); + height = get4(ifp); + width = get4(ifp); + filters = 0x61616161; + data_offset = 68; + load_raw = unpacked_load_raw; + maximum = 0xffff; + } else if (!strcmp(make,"Leaf")) { + if (height > width) + filters = 0x16161616; + load_raw = unpacked_load_raw; + maximum = 0x3fff; + strcpy (model, "Valeo"); + if (raw_width == 2060) { filters = 0; + load_raw = leaf_load_raw; + maximum = 0xffff; + strcpy (model, "Volare"); + } + } else if (!strcmp(model,"DIGILUX 2") || !strcmp(model,"DMC-LC1")) { + height = 1928; + width = 2568; + data_offset = 1024; + load_raw = unpacked_load_raw; + maximum = 0xfff0; + } else if (!strcmp(model,"E-1")) { + filters = 0x61616161; + load_raw = unpacked_load_raw; + maximum = 0xfff0; + black = 1024; + } else if (!strcmp(model,"E-10")) { + load_raw = unpacked_load_raw; + maximum = 0xfff0; + black = 2048; + } else if (!strncmp(model,"E-20",4)) { + load_raw = unpacked_load_raw; + maximum = 0xffc0; + black = 2560; + } else if (!strcmp(model,"E-300")) { + width -= 21; + load_raw = olympus_e300_load_raw; + if (fsize > 15728640) { + load_raw = unpacked_load_raw; + maximum = 0xfc30; + } else + black = 62; + } else if (!strcmp(make,"OLYMPUS")) { + load_raw = olympus_cseries_load_raw; + if (!strcmp(model,"C5050Z") || + !strcmp(model,"C8080WZ")) + filters = 0x16161616; + } else if (!strcmp(model,"N Digital")) { + height = 2047; + width = 3072; + filters = 0x61616161; + data_offset = 0x1a00; + load_raw = packed_12_load_raw; + maximum = 0xf1e; + } else if (!strcmp(model,"DSC-F828")) { + width = 3288; + left_margin = 5; + load_raw = sony_load_raw; + filters = 0x9c9c9c9c; + colors = 4; + black = 491; + } else if (!strcmp(model,"DSC-V3")) { + width = 3109; + left_margin = 59; + load_raw = sony_load_raw; + } else if (!strcasecmp(make,"KODAK")) { + filters = 0x61616161; + if (!strcmp(model,"NC2000F")) { + width -= 4; + left_margin = 1; + for (i=176; i < 0x1000; i++) + curve[i] = curve[i-1]; + pre_mul[0] = 1.509; + pre_mul[2] = 2.686; + } else if (!strcmp(model,"EOSDCS3B")) { + width -= 4; + left_margin = 2; + } else if (!strcmp(model,"EOSDCS1")) { + width -= 4; + left_margin = 2; + } else if (!strcmp(model,"DCS315C")) { + black = 8; + } else if (!strcmp(model,"DCS330C")) { + black = 8; + } else if (!strcmp(model,"DCS420")) { + width -= 4; + left_margin = 2; + } else if (!strcmp(model,"DCS460")) { + width -= 4; + left_margin = 2; + } else if (!strcmp(model,"DCS460A")) { + width -= 4; + left_margin = 2; + colors = 1; + filters = 0; + } else if (!strcmp(model,"DCS520C")) { + black = 180; + } else if (!strcmp(model,"DCS560C")) { + black = 188; + } else if (!strcmp(model,"DCS620C")) { + black = 180; + } else if (!strcmp(model,"DCS620X")) { + black = 185; + } else if (!strcmp(model,"DCS660C")) { + black = 214; + } else if (!strcmp(model,"DCS660M")) { + black = 214; + colors = 1; + filters = 0; + } else if (!strcmp(model,"DCS760M")) { + colors = 1; + filters = 0; + } + switch (tiff_data_compression) { + case 0: /* No compression */ + case 1: + load_raw = kodak_easy_load_raw; + break; + case 7: /* Lossless JPEG */ + load_raw = lossless_jpeg_load_raw; + case 32867: + break; + case 65000: /* Kodak DCR compression */ + if (!have64BitArithmetic) + pm_error("This program was built without 64 bit arithmetic " + "capability, and Kodak DCR compression requires it."); + if (kodak_data_compression == 32803) + load_raw = kodak_compressed_load_raw; + else { + load_raw = kodak_yuv_load_raw; + height = (height+1) & -2; + width = (width +1) & -2; + filters = 0; + } + break; + default: + pm_message ("%s %s uses unrecognized compression method %d.", + make, model, tiff_data_compression); + return 1; + } + if (!strcmp(model,"DC20")) { + height = 242; + if (fsize < 100000) { + width = 249; + raw_width = 256; + } else { + width = 501; + raw_width = 512; + } + data_offset = raw_width + 1; + colors = 4; + filters = 0x8d8d8d8d; + kodak_dc20_coeff (1.0); + pre_mul[1] = 1.179; + pre_mul[2] = 1.209; + pre_mul[3] = 1.036; + load_raw = kodak_easy_load_raw; + } else if (strstr(model,"DC25")) { + strcpy (model, "DC25"); + height = 242; + if (fsize < 100000) { + width = 249; + raw_width = 256; + data_offset = 15681; + } else { + width = 501; + raw_width = 512; + data_offset = 15937; + } + colors = 4; + filters = 0xb4b4b4b4; + load_raw = kodak_easy_load_raw; + } else if (!strcmp(model,"Digital Camera 40")) { + strcpy (model, "DC40"); + height = 512; + width = 768; + data_offset = 1152; + load_raw = kodak_radc_load_raw; + } else if (strstr(model,"DC50")) { + strcpy (model, "DC50"); + height = 512; + width = 768; + data_offset = 19712; + load_raw = kodak_radc_load_raw; + } else if (strstr(model,"DC120")) { + strcpy (model, "DC120"); + height = 976; + width = 848; + if (tiff_data_compression == 7) + load_raw = kodak_jpeg_load_raw; + else + load_raw = kodak_dc120_load_raw; + } + } else if (!strcmp(make,"Rollei")) { + switch (raw_width) { + case 1316: + height = 1030; + width = 1300; + top_margin = 1; + left_margin = 6; + break; + case 2568: + height = 1960; + width = 2560; + top_margin = 2; + left_margin = 8; + } + filters = 0x16161616; + load_raw = rollei_load_raw; + pre_mul[0] = 1.8; + pre_mul[2] = 1.3; + } else if (!strcmp(model,"PC-CAM 600")) { + height = 768; + data_offset = width = 1024; + filters = 0x49494949; + load_raw = eight_bit_load_raw; + pre_mul[0] = 1.14; + pre_mul[2] = 2.73; + } else if (!strcmp(model,"QV-2000UX")) { + height = 1208; + width = 1632; + data_offset = width * 2; + load_raw = eight_bit_load_raw; + } else if (!strcmp(model,"QV-3*00EX")) { + height = 1546; + width = 2070; + raw_width = 2080; + load_raw = eight_bit_load_raw; + } else if (!strcmp(model,"QV-4000")) { + height = 1700; + width = 2260; + load_raw = unpacked_load_raw; + maximum = 0xffff; + } else if (!strcmp(model,"QV-5700")) { + height = 1924; + width = 2576; + load_raw = casio_qv5700_load_raw; + } else if (!strcmp(model,"QV-R51")) { + height = 1926; + width = 2576; + raw_width = 3904; + load_raw = packed_12_load_raw; + pre_mul[0] = 1.340; + pre_mul[2] = 1.672; + } else if (!strcmp(model,"EX-Z55")) { + height = 1960; + width = 2570; + raw_width = 3904; + load_raw = packed_12_load_raw; + pre_mul[0] = 1.520; + pre_mul[2] = 1.316; + } else if (!strcmp(model,"EX-P600")) { + height = 2142; + width = 2844; + raw_width = 4288; + load_raw = packed_12_load_raw; + pre_mul[0] = 1.797; + pre_mul[2] = 1.219; + } else if (!strcmp(model,"EX-P700")) { + height = 2318; + width = 3082; + raw_width = 4672; + load_raw = packed_12_load_raw; + pre_mul[0] = 1.758; + pre_mul[2] = 1.504; + } else if (!strcmp(make,"Nucore")) { + filters = 0x61616161; + load_raw = unpacked_load_raw; + if (width == 2598) { + filters = 0x16161616; + load_raw = nucore_load_raw; + flip = 2; } - break; - default: - pm_message ("%s %s uses unrecognized compression method %d.", - make, model, tiff_data_compression); - return 1; - } - if (!strcmp(model,"DC20")) { - height = 242; - if (fsize < 100000) { - width = 249; - raw_width = 256; - } else { - width = 501; - raw_width = 512; - } - data_offset = raw_width + 1; - colors = 4; - filters = 0x8d8d8d8d; - kodak_dc20_coeff (1.0); - pre_mul[1] = 1.179; - pre_mul[2] = 1.209; - pre_mul[3] = 1.036; - load_raw = kodak_easy_load_raw; - } else if (strstr(model,"DC25")) { - strcpy (model, "DC25"); - height = 242; - if (fsize < 100000) { - width = 249; - raw_width = 256; - data_offset = 15681; - } else { - width = 501; - raw_width = 512; - data_offset = 15937; - } - colors = 4; - filters = 0xb4b4b4b4; - load_raw = kodak_easy_load_raw; - } else if (!strcmp(model,"Digital Camera 40")) { - strcpy (model, "DC40"); - height = 512; - width = 768; - data_offset = 1152; - load_raw = kodak_radc_load_raw; - } else if (strstr(model,"DC50")) { - strcpy (model, "DC50"); - height = 512; - width = 768; - data_offset = 19712; - load_raw = kodak_radc_load_raw; - } else if (strstr(model,"DC120")) { - strcpy (model, "DC120"); - height = 976; - width = 848; - if (tiff_data_compression == 7) - load_raw = kodak_jpeg_load_raw; - else - load_raw = kodak_dc120_load_raw; - } - } else if (!strcmp(make,"Rollei")) { - switch (raw_width) { - case 1316: - height = 1030; - width = 1300; - top_margin = 1; - left_margin = 6; - break; - case 2568: - height = 1960; - width = 2560; - top_margin = 2; - left_margin = 8; - } - filters = 0x16161616; - load_raw = rollei_load_raw; - pre_mul[0] = 1.8; - pre_mul[2] = 1.3; - } else if (!strcmp(model,"PC-CAM 600")) { - height = 768; - data_offset = width = 1024; - filters = 0x49494949; - load_raw = eight_bit_load_raw; - pre_mul[0] = 1.14; - pre_mul[2] = 2.73; - } else if (!strcmp(model,"QV-2000UX")) { - height = 1208; - width = 1632; - data_offset = width * 2; - load_raw = eight_bit_load_raw; - } else if (!strcmp(model,"QV-3*00EX")) { - height = 1546; - width = 2070; - raw_width = 2080; - load_raw = eight_bit_load_raw; - } else if (!strcmp(model,"QV-4000")) { - height = 1700; - width = 2260; - load_raw = unpacked_load_raw; - maximum = 0xffff; - } else if (!strcmp(model,"QV-5700")) { - height = 1924; - width = 2576; - load_raw = casio_qv5700_load_raw; - } else if (!strcmp(model,"QV-R51")) { - height = 1926; - width = 2576; - raw_width = 3904; - load_raw = packed_12_load_raw; - pre_mul[0] = 1.340; - pre_mul[2] = 1.672; - } else if (!strcmp(model,"EX-Z55")) { - height = 1960; - width = 2570; - raw_width = 3904; - load_raw = packed_12_load_raw; - pre_mul[0] = 1.520; - pre_mul[2] = 1.316; - } else if (!strcmp(model,"EX-P600")) { - height = 2142; - width = 2844; - raw_width = 4288; - load_raw = packed_12_load_raw; - pre_mul[0] = 1.797; - pre_mul[2] = 1.219; - } else if (!strcmp(model,"EX-P700")) { - height = 2318; - width = 3082; - raw_width = 4672; - load_raw = packed_12_load_raw; - pre_mul[0] = 1.758; - pre_mul[2] = 1.504; - } else if (!strcmp(make,"Nucore")) { - filters = 0x61616161; - load_raw = unpacked_load_raw; - if (width == 2598) { - filters = 0x16161616; - load_raw = nucore_load_raw; - flip = 2; } - } - if (!use_coeff) adobe_coeff(); + if (!use_coeff) + adobeCoeff(make, model); dng_skip: - if (!load_raw || !height) { - pm_message ("This program cannot handle data from %s %s.", - make, model); - return 1; - } + if (!load_raw || !height) { + pm_message ("This program cannot handle data from %s %s.", + make, model); + return 1; + } #ifdef NO_JPEG - if (load_raw == kodak_jpeg_load_raw) { - pm_message ("decoder was not linked with libjpeg."); - return 1; - } -#endif - if (!raw_height) raw_height = height; - if (!raw_width ) raw_width = width; - if (use_camera_rgb && colors == 3) - use_coeff = 0; - if (use_coeff) /* Apply user-selected color balance */ - for (i=0; i < colors; i++) { - coeff[0][i] *= red_scale; - coeff[2][i] *= blue_scale; + if (load_raw == kodak_jpeg_load_raw) { + pm_message ("decoder was not linked with libjpeg."); + return 1; } - if (four_color_rgb && filters && colors == 3) { - for (i=0; i < 32; i+=4) { - if ((filters >> i & 15) == 9) - filters |= 2 << i; - if ((filters >> i & 15) == 6) - filters |= 8 << i; +#endif + if (!raw_height) raw_height = height; + if (!raw_width ) raw_width = width; + if (use_camera_rgb && colors == 3) + use_coeff = 0; + if (use_coeff) /* Apply user-selected color balance */ + for (i=0; i < colors; i++) { + coeff[0][i] *= red_scale; + coeff[2][i] *= blue_scale; + } + if (four_color_rgb && filters && colors == 3) { + for (i=0; i < 32; i+=4) { + if ((filters >> i & 15) == 9) + filters |= 2 << i; + if ((filters >> i & 15) == 6) + filters |= 8 << i; + } + colors++; + pre_mul[3] = pre_mul[1]; + if (use_coeff) + for (i=0; i < 3; i++) + coeff[i][3] = coeff[i][1] /= 2; } - colors++; - pre_mul[3] = pre_mul[1]; - if (use_coeff) - for (i=0; i < 3; i++) - coeff[i][3] = coeff[i][1] /= 2; - } - fseek (ifp, data_offset, SEEK_SET); + fseek (ifp, data_offset, SEEK_SET); - *loadRawFnP = load_raw; + *loadRawFnP = load_raw; - return 0; + return 0; } diff --git a/converter/other/cameratopam/identify.h b/converter/other/cameratopam/identify.h index 012b807c..62c9aae5 100644 --- a/converter/other/cameratopam/identify.h +++ b/converter/other/cameratopam/identify.h @@ -1,4 +1,4 @@ -typedef void (*loadRawFn)(); +#include "camera.h" int identify(FILE * const ifp, @@ -8,4 +8,4 @@ identify(FILE * const ifp, float const blue_scale, unsigned int const four_color_rgb, const char * const inputFileName, - loadRawFn * const loadRawFnP); + LoadRawFn ** const loadRawFnP); diff --git a/converter/other/cameratopam/ljpeg.c b/converter/other/cameratopam/ljpeg.c index 4b092933..07791e25 100644 --- a/converter/other/cameratopam/ljpeg.c +++ b/converter/other/cameratopam/ljpeg.c @@ -20,127 +20,145 @@ */ int -ljpeg_start (FILE * ifp, struct jhead *jh) -{ - int i, tag, len; - unsigned char data[256], *dp; - - init_decoder(); - for (i=0; i < 4; i++) - jh->huff[i] = free_decode; - fread (data, 2, 1, ifp); - if (data[0] != 0xff || data[1] != 0xd8) return 0; - do { - fread (data, 2, 2, ifp); - tag = data[0] << 8 | data[1]; - len = (data[2] << 8 | data[3]); - if (len < 2) - pm_error("Length field is %u; must be at least 2", len); - else { - unsigned int const dataLen = len - 2; - if (tag <= 0xff00 || dataLen > 255) return 0; - fread (data, 1, dataLen, ifp); - switch (tag) { - case 0xffc3: - jh->bits = data[0]; - jh->high = data[1] << 8 | data[2]; - jh->wide = data[3] << 8 | data[4]; - jh->clrs = data[5]; - break; - case 0xffc4: - for (dp = data; dp < data+dataLen && *dp < 4; ) { - jh->huff[*dp] = free_decode; - dp = make_decoder (++dp, 0); +ljpeg_start(FILE * const ifP, + struct jhead * const jhP) { + + int i, tag; + unsigned char data[256], *dp; + + init_decoder(); + for (i=0; i < 4; i++) + jhP->huff[i] = free_decode; + fread (data, 2, 1, ifP); + if (data[0] != 0xff || data[1] != 0xd8) return 0; + do { + unsigned int len; + + fread (data, 2, 2, ifP); + tag = data[0] << 8 | data[1]; + len = data[2] << 8 | data[3]; + + if (len < 2) + pm_error("Length field is %u; must be at least 2", len); + else { + unsigned int const dataLen = len - 2; + + if (tag <= 0xff00 || dataLen > 255) return 0; + fread (data, 1, dataLen, ifP); + switch (tag) { + case 0xffc3: + jhP->bits = data[0]; + jhP->high = data[1] << 8 | data[2]; + jhP->wide = data[3] << 8 | data[4]; + jhP->clrs = data[5]; + break; + case 0xffc4: + for (dp = data; dp < data + dataLen && *dp < 4; ) { + jhP->huff[*dp] = free_decode; + dp = make_decoder (++dp, 0); + } + } } - } - } - } while (tag != 0xffda); - jh->row = calloc (jh->wide*jh->clrs, 2); - if (jh->row == NULL) - pm_error("Out of memory in ljpeg_start()"); - for (i=0; i < 4; i++) - jh->vpred[i] = 1 << (jh->bits-1); - zero_after_ff = 1; - getbits(ifp, -1); - return 1; + } while (tag != 0xffda); + jhP->row = calloc (jhP->wide*jhP->clrs, 2); + if (jhP->row == NULL) + pm_error("Out of memory in ljpeg_start()"); + for (i=0; i < 4; i++) + jhP->vpred[i] = 1 << (jhP->bits-1); + zero_after_ff = 1; + getbits(ifP, -1); + return 1; } + + int -ljpeg_diff (struct decode *dindex) -{ - int len, diff; - - while (dindex->branch[0]) - dindex = dindex->branch[getbits(ifp, 1)]; - diff = getbits(ifp, len = dindex->leaf); - if ((diff & (1 << (len-1))) == 0) - diff -= (1 << len) - 1; - return diff; +ljpeg_diff(FILE * const ifP, + struct decode * const dindexHeadP) { + + int len; + int diff; + struct decode * dindexP; + + for (dindexP = dindexHeadP; dindexP->branch[0]; ) + dindexP = dindexP->branch[getbits(ifP, 1)]; + + diff = getbits(ifP, len = dindexP->leaf); + + if ((diff & (1 << (len-1))) == 0) + diff -= (1 << len) - 1; + + return diff; } + + void -ljpeg_row (struct jhead *jh) -{ - int col, c, diff; - unsigned short *outp=jh->row; - - for (col=0; col < jh->wide; col++) - for (c=0; c < jh->clrs; c++) { - diff = ljpeg_diff (jh->huff[c]); - *outp = col ? outp[-jh->clrs]+diff : (jh->vpred[c] += diff); - outp++; - } +ljpeg_row(FILE * const ifP, + struct jhead * const jhP) { + + int col, c, diff; + unsigned short *outp=jhP->row; + + for (col=0; col < jhP->wide; col++) + for (c=0; c < jhP->clrs; c++) { + diff = ljpeg_diff(ifP, jhP->huff[c]); + *outp = col ? outp[-jhP->clrs]+diff : (jhP->vpred[c] += diff); + outp++; + } } + + void -lossless_jpeg_load_raw(void) -{ - int jwide, jrow, jcol, val, jidx, i, row, col; - struct jhead jh; - int min=INT_MAX; - - if (!ljpeg_start (ifp, &jh)) return; - jwide = jh.wide * jh.clrs; - - for (jrow=0; jrow < jh.high; jrow++) { - ljpeg_row (&jh); - for (jcol=0; jcol < jwide; jcol++) { - val = curve[jh.row[jcol]]; - jidx = jrow*jwide + jcol; - if (raw_width == 5108) { - i = jidx / (1680*jh.high); - if (i < 2) { - row = jidx / 1680 % jh.high; - col = jidx % 1680 + i*1680; - } else { - jidx -= 2*1680*jh.high; - row = jidx / 1748; - col = jidx % 1748 + 2*1680; - } - } else if (raw_width == 3516) { - row = jidx / 1758; - col = jidx % 1758; - if (row >= raw_height) { - row -= raw_height; - col += 1758; - } - } else { - row = jidx / raw_width; - col = jidx % raw_width; - } - if ((unsigned) (row-top_margin) >= height) continue; - if ((unsigned) (col-left_margin) < width) { - BAYER(row-top_margin,col-left_margin) = val; - if (min > val) min = val; - } else - black += val; +lossless_jpeg_load_raw(Image const image) { + + int jwide, jrow, jcol, val, jidx, i, row, col; + struct jhead jh; + int min=INT_MAX; + + if (!ljpeg_start (ifp, &jh)) return; + jwide = jh.wide * jh.clrs; + + for (jrow=0; jrow < jh.high; jrow++) { + ljpeg_row (ifp, &jh); + for (jcol=0; jcol < jwide; jcol++) { + val = curve[jh.row[jcol]]; + jidx = jrow*jwide + jcol; + if (raw_width == 5108) { + i = jidx / (1680*jh.high); + if (i < 2) { + row = jidx / 1680 % jh.high; + col = jidx % 1680 + i*1680; + } else { + jidx -= 2*1680*jh.high; + row = jidx / 1748; + col = jidx % 1748 + 2*1680; + } + } else if (raw_width == 3516) { + row = jidx / 1758; + col = jidx % 1758; + if (row >= raw_height) { + row -= raw_height; + col += 1758; + } + } else { + row = jidx / raw_width; + col = jidx % raw_width; + } + if ((unsigned) (row-top_margin) >= height) continue; + if ((unsigned) (col-left_margin) < width) { + BAYER(row-top_margin,col-left_margin) = val; + if (min > val) min = val; + } else + black += val; + } } - } - free (jh.row); - if (raw_width > width) - black /= (raw_width - width) * height; - if (!strcasecmp(make,"KODAK")) - black = min; + free (jh.row); + if (raw_width > width) + black /= (raw_width - width) * height; + if (!strcasecmp(make,"KODAK")) + black = min; } diff --git a/converter/other/cameratopam/ljpeg.h b/converter/other/cameratopam/ljpeg.h index 60832a3d..9d9d8ee9 100644 --- a/converter/other/cameratopam/ljpeg.h +++ b/converter/other/cameratopam/ljpeg.h @@ -1,17 +1,21 @@ +#include "camera.h" + struct jhead { int bits, high, wide, clrs, vpred[4]; struct decode *huff[4]; unsigned short *row; }; -void -lossless_jpeg_load_raw(void); +LoadRawFn lossless_jpeg_load_raw; int -ljpeg_start (FILE * ifp, struct jhead *jh); +ljpeg_start (FILE * const ifP, + struct jhead * const jhP); int -ljpeg_diff (struct decode *dindex); +ljpeg_diff (FILE * const ifP, + struct decode * const dindexP); void -ljpeg_row (struct jhead *jh); +ljpeg_row(FILE * const ifP, + struct jhead * const jhP); diff --git a/converter/other/exif.c b/converter/other/exif.c index f9592d6c..1bfe4b2b 100644 --- a/converter/other/exif.c +++ b/converter/other/exif.c @@ -21,6 +21,7 @@ See the EXIF specs at http://exif.org (2001.09.01). --------------------------------------------------------------------------*/ +#include "pm_config.h" #include #include #include @@ -30,7 +31,7 @@ #include #include -#ifdef _WIN32 +#if MSVCRT #include #else #include @@ -45,22 +46,21 @@ #include "exif.h" -static unsigned char * LastExifRefd; -static unsigned char * DirWithThumbnailPtrs; +static const unsigned char * DirWithThumbnailPtrs; static double FocalplaneXRes; bool HaveXRes; static double FocalplaneUnits; static int ExifImageWidth; -static int MotorolaOrder = 0; typedef struct { unsigned short Tag; const char * Desc; -}TagTable_t; +} TagTable; + /* Describes format descriptor */ -static int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8}; +static int const bytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8}; #define NUM_FORMATS 12 #define FMT_BYTE 1 @@ -119,7 +119,7 @@ static int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8}; #define TAG_THUMBNAIL_OFFSET 0x0201 #define TAG_THUMBNAIL_LENGTH 0x0202 -static TagTable_t const TagTable[] = { +static TagTable const tagTable[] = { { 0x100, "ImageWidth"}, { 0x101, "ImageLength"}, { 0x102, "BitsPerSample"}, @@ -207,498 +207,583 @@ static TagTable_t const TagTable[] = { +typedef enum { NORMAL, MOTOROLA } ByteOrder; + + + +static uint16_t +get16u(const void * const data, + ByteOrder const byteOrder) { /*-------------------------------------------------------------------------- Convert a 16 bit unsigned value from file's native byte order --------------------------------------------------------------------------*/ -static int Get16u(void * Short) -{ - if (MotorolaOrder){ - return (((unsigned char *)Short)[0] << 8) | - ((unsigned char *)Short)[1]; + if (byteOrder == MOTOROLA){ + return (((const unsigned char *)data)[0] << 8) | + ((const unsigned char *)data)[1]; }else{ - return (((unsigned char *)Short)[1] << 8) | - ((unsigned char *)Short)[0]; + return (((const unsigned char *)data)[1] << 8) | + ((const unsigned char *)data)[0]; } } + + +static int32_t +get32s(const void * const data, + ByteOrder const byteOrder) { /*-------------------------------------------------------------------------- Convert a 32 bit signed value from file's native byte order --------------------------------------------------------------------------*/ -static int Get32s(void * Long) -{ - if (MotorolaOrder){ + if (byteOrder == MOTOROLA){ return - ((( char *)Long)[0] << 24) | (((unsigned char *)Long)[1] << 16) | - (((unsigned char *)Long)[2] << 8 ) | - (((unsigned char *)Long)[3] << 0 ); - }else{ + (((const char *)data)[0] << 24) | + (((const unsigned char *)data)[1] << 16) | + (((const unsigned char *)data)[2] << 8 ) | + (((const unsigned char *)data)[3] << 0 ); + } else { return - ((( char *)Long)[3] << 24) | (((unsigned char *)Long)[2] << 16) | - (((unsigned char *)Long)[1] << 8 ) | - (((unsigned char *)Long)[0] << 0 ); + (((const char *)data)[3] << 24) | + (((const unsigned char *)data)[2] << 16) | + (((const unsigned char *)data)[1] << 8 ) | + (((const unsigned char *)data)[0] << 0 ); } } + + +static uint32_t +get32u(const void * const data, + ByteOrder const byteOrder) { /*-------------------------------------------------------------------------- Convert a 32 bit unsigned value from file's native byte order --------------------------------------------------------------------------*/ -static unsigned Get32u(void * Long) -{ - return (unsigned)Get32s(Long) & 0xffffffff; + return (uint32_t)get32s(data, byteOrder) & 0xffffffff; } + + +static void +printFormatNumber(FILE * const fileP, + const void * const ValuePtr, + int const Format, + int const ByteCount, + ByteOrder const byteOrder) { /*-------------------------------------------------------------------------- Display a number as one of its many formats --------------------------------------------------------------------------*/ -static void PrintFormatNumber(FILE * const file, - void * const ValuePtr, - int const Format, int const ByteCount) -{ switch(Format){ case FMT_SBYTE: - case FMT_BYTE: printf("%02x\n",*(unsigned char *)ValuePtr); break; - case FMT_USHORT: fprintf(file, "%d\n",Get16u(ValuePtr)); break; + case FMT_BYTE: + fprintf(fileP, "%02x\n", *(unsigned char *)ValuePtr); + break; + case FMT_USHORT: + fprintf(fileP, "%d\n",get16u(ValuePtr, byteOrder)); + break; case FMT_ULONG: - case FMT_SLONG: fprintf(file, "%d\n",Get32s(ValuePtr)); break; + case FMT_SLONG: + fprintf(fileP, "%d\n",get32s(ValuePtr, byteOrder)); + break; case FMT_SSHORT: - fprintf(file, "%hd\n",(signed short)Get16u(ValuePtr)); break; + fprintf(fileP, "%hd\n",(signed short)get16u(ValuePtr, byteOrder)); + break; case FMT_URATIONAL: case FMT_SRATIONAL: - fprintf(file, "%d/%d\n",Get32s(ValuePtr), Get32s(4+(char *)ValuePtr)); + fprintf(fileP, "%d/%d\n",get32s(ValuePtr, byteOrder), + get32s(4+(char *)ValuePtr, byteOrder)); break; case FMT_SINGLE: - fprintf(file, "%f\n",(double)*(float *)ValuePtr); break; - case FMT_DOUBLE: fprintf(file, "%f\n",*(double *)ValuePtr); break; + fprintf(fileP, "%f\n",(double)*(float *)ValuePtr); + break; + case FMT_DOUBLE: + fprintf(fileP, "%f\n",*(double *)ValuePtr); + break; default: - fprintf(file, "Unknown format %d:", Format); + fprintf(fileP, "Unknown format %d:", Format); { - int a; - for (a=0; a < ByteCount && a < 16; ++a) + unsigned int a; + for (a = 0; a < ByteCount && a < 16; ++a) printf("%02x", ((unsigned char *)ValuePtr)[a]); } - fprintf(file, "\n"); + fprintf(fileP, "\n"); } } + +static double +convertAnyFormat(const void * const ValuePtr, + int const Format, + ByteOrder const byteOrder) { /*-------------------------------------------------------------------------- Evaluate number, be it int, rational, or float from directory. --------------------------------------------------------------------------*/ -static double ConvertAnyFormat(void * ValuePtr, int Format) -{ double Value; Value = 0; switch(Format){ - case FMT_SBYTE: Value = *(signed char *)ValuePtr; break; - case FMT_BYTE: Value = *(unsigned char *)ValuePtr; break; - - case FMT_USHORT: Value = Get16u(ValuePtr); break; - case FMT_ULONG: Value = Get32u(ValuePtr); break; - - case FMT_URATIONAL: - case FMT_SRATIONAL: - { - int Num,Den; - Num = Get32s(ValuePtr); - Den = Get32s(4+(char *)ValuePtr); - if (Den == 0){ - Value = 0; - }else{ - Value = (double)Num/Den; - } - break; - } - - case FMT_SSHORT: Value = (signed short)Get16u(ValuePtr); break; - case FMT_SLONG: Value = Get32s(ValuePtr); break; + case FMT_SBYTE: + Value = *(signed char *)ValuePtr; + break; + case FMT_BYTE: + Value = *(unsigned char *)ValuePtr; + break; + case FMT_USHORT: + Value = get16u(ValuePtr, byteOrder); + break; + case FMT_ULONG: + Value = get32u(ValuePtr, byteOrder); + break; + case FMT_URATIONAL: + case FMT_SRATIONAL: { + int num, den; + num = get32s(ValuePtr, byteOrder); + den = get32s(4+(char *)ValuePtr, byteOrder); + Value = den == 0 ? 0 : (double)(num/den); + } break; + case FMT_SSHORT: + Value = (signed short)get16u(ValuePtr, byteOrder); + break; + case FMT_SLONG: + Value = get32s(ValuePtr, byteOrder); + break; - /* Not sure if this is correct (never seen float used in Exif format) - */ - case FMT_SINGLE: Value = (double)*(float *)ValuePtr; break; - case FMT_DOUBLE: Value = *(double *)ValuePtr; break; + /* Not sure if this is correct (never seen float used in Exif format) */ + case FMT_SINGLE: + Value = (double)*(float *)ValuePtr; + break; + case FMT_DOUBLE: + Value = *(double *)ValuePtr; + break; } return Value; } -/*-------------------------------------------------------------------------- - Process one of the nested EXIF directories. ---------------------------------------------------------------------------*/ -static void -ProcessExifDir(unsigned char * const ExifData, - unsigned int const ExifLength, - unsigned int const DirOffset, - ImageInfo_t * const ImageInfoP, - int const ShowTags, - unsigned char ** const LastExifRefdP) { - - unsigned char * const DirStart = ExifData + DirOffset; - int de; - int a; - int NumDirEntries; - unsigned ThumbnailOffset = 0; - unsigned ThumbnailSize = 0; - - NumDirEntries = Get16u(DirStart); - #define DIR_ENTRY_ADDR(Start, Entry) (Start+2+12*(Entry)) - { - unsigned char * DirEnd; - DirEnd = DIR_ENTRY_ADDR(DirStart, NumDirEntries); - if (DirEnd+4 > (ExifData+ExifLength)){ - if (DirEnd+2 == ExifData+ExifLength || - DirEnd == ExifData+ExifLength){ - /* Version 1.3 of jhead would truncate a bit too much. - This also caught later on as well. - */ - }else{ - /* Note: Files that had thumbnails trimmed with jhead - 1.3 or earlier might trigger this. + +static void +traceTag(int const tag, + int const format, + const unsigned char * const valuePtr, + unsigned int const byteCount, + ByteOrder const byteOrder) { + + /* Show tag name */ + unsigned int a; + bool found; + for (a = 0, found = false; !found; ++a){ + if (tagTable[a].Tag == 0){ + fprintf(stderr, " Unknown Tag %04x Value = ", tag); + found = true; + } + if (tagTable[a].Tag == tag){ + fprintf(stderr, " %s = ",tagTable[a].Desc); + found = true; + } + } + + /* Show tag value. */ + switch(format){ + + case FMT_UNDEFINED: + /* Undefined is typically an ascii string. */ + + case FMT_STRING: { + /* String arrays printed without function call + (different from int arrays) + */ + bool noPrint; + printf("\""); + for (a = 0, noPrint = false; a < byteCount; ++a){ + if (ISPRINT((valuePtr)[a])){ + fprintf(stderr, "%c", valuePtr[a]); + noPrint = false; + } else { + /* Avoiding indicating too many unprintable characters of + proprietary bits of binary information this program may not + know how to parse. */ - pm_message("Illegal directory entry size"); - return; + if (!noPrint){ + fprintf(stderr, "?"); + noPrint = true; + } } } - if (DirEnd > LastExifRefd) LastExifRefd = DirEnd; + fprintf(stderr, "\"\n"); + } break; + + default: + /* Handle arrays of numbers later (will there ever be?)*/ + printFormatNumber(stderr, valuePtr, format, byteCount, byteOrder); } +} + + + +/* Forward declaration for recursion */ + +static void +processExifDir(const unsigned char * const ExifData, + unsigned int const ExifLength, + unsigned int const DirOffset, + exif_ImageInfo * const imageInfoP, + ByteOrder const byteOrder, + bool const wantTagTrace, + const unsigned char ** const LastExifRefdP); + + +static void +processDirEntry(const unsigned char * const dirEntry, + const unsigned char * const exifData, + unsigned int const exifLength, + ByteOrder const byteOrder, + bool const wantTagTrace, + exif_ImageInfo * const imageInfoP, + unsigned int * const thumbnailOffsetP, + unsigned int * const thumbnailSizeP, + bool * const haveThumbnailP, + const unsigned char ** const lastExifRefdP) { + + int const tag = get16u(&dirEntry[0], byteOrder); + int const format = get16u(&dirEntry[2], byteOrder); + int const components = get32u(&dirEntry[4], byteOrder); + + const unsigned char * valuePtr; + /* This actually can point to a variety of things; it must be cast to + other types when used. But we use it as a byte-by-byte cursor, so + we declare it as a pointer to a generic byte here. + */ + unsigned int byteCount; - if (ShowTags){ - pm_message("Directory with %d entries",NumDirEntries); + if ((format-1) >= NUM_FORMATS) { + /* (-1) catches illegal zero case as unsigned underflows + to positive large. + */ + pm_message("Illegal number format %d for tag %04x", format, tag); + return; + } + + byteCount = components * bytesPerFormat[format]; + + if (byteCount > 4){ + unsigned const offsetVal = get32u(&dirEntry[8], byteOrder); + /* If its bigger than 4 bytes, the dir entry contains an offset.*/ + if (offsetVal + byteCount > exifLength){ + /* Bogus pointer offset and / or bytecount value */ + pm_message("Illegal pointer offset value in EXIF " + "for tag %04x. " + "Offset %d bytes %d ExifLen %d\n", + tag, offsetVal, byteCount, exifLength); + return; + } + valuePtr = &exifData[offsetVal]; + } else { + /* 4 bytes or less and value is in the dir entry itself */ + valuePtr = &dirEntry[8]; } - for (de=0;de= NUM_FORMATS) { - /* (-1) catches illegal zero case as unsigned underflows - to positive large. - */ - pm_message("Illegal number format %d for tag %04x", Format, Tag); - continue; + *haveThumbnailP = (tag == TAG_THUMBNAIL_OFFSET); + + /* Extract useful components of tag */ + switch (tag){ + + case TAG_MAKE: + STRSCPY(imageInfoP->CameraMake, (const char*)valuePtr); + break; + + case TAG_MODEL: + STRSCPY(imageInfoP->CameraModel, (const char*)valuePtr); + break; + + case TAG_XRESOLUTION: + imageInfoP->XResolution = + convertAnyFormat(valuePtr, format, byteOrder); + break; + + case TAG_YRESOLUTION: + imageInfoP->YResolution = + convertAnyFormat(valuePtr, format, byteOrder); + break; + + case TAG_DATETIME_ORIGINAL: + STRSCPY(imageInfoP->DateTime, (const char*)valuePtr); + imageInfoP->DatePointer = (const char*)valuePtr; + break; + + case TAG_USERCOMMENT: { + /* Olympus has this padded with trailing spaces. We stop the copy + where those start. + */ + const char * const value = (const char *)valuePtr; + + unsigned int cursor; + unsigned int outCursor; + unsigned int end; + + for (end = byteCount; end > 0 && value[end] == ' '; --end); + + /* Skip "ASCII" if it is there */ + if (end >= 5 && MEMEQ(value, "ASCII", 5)) + cursor = 5; + else + cursor = 0; + + /* Skip consecutive blanks and NULs */ + + for (; + cursor < byteCount && + (value[cursor] == '\0' || value[cursor] == ' '); + ++cursor); + + /* Copy the rest as the comment */ + + for (outCursor = 0; + cursor < end && outCursor < MAX_COMMENT-1; + ++cursor) + imageInfoP->Comments[outCursor++] = value[cursor]; + + imageInfoP->Comments[outCursor++] = '\0'; + } break; + + case TAG_FNUMBER: + /* Simplest way of expressing aperture, so I trust it the most. + (overwrite previously computd value if there is one) + */ + imageInfoP->ApertureFNumber = + (float)convertAnyFormat(valuePtr, format, byteOrder); + break; + + case TAG_APERTURE: + case TAG_MAXAPERTURE: + /* More relevant info always comes earlier, so only use this field if + we don't have appropriate aperture information yet. + */ + if (imageInfoP->ApertureFNumber == 0){ + imageInfoP->ApertureFNumber = (float) + exp(convertAnyFormat(valuePtr, format, byteOrder) + * log(2) * 0.5); } - - ByteCount = Components * BytesPerFormat[Format]; - - if (ByteCount > 4){ - unsigned OffsetVal; - OffsetVal = Get32u(DirEntry+8); - /* If its bigger than 4 bytes, the dir entry contains an offset.*/ - if (OffsetVal+ByteCount > ExifLength){ - /* Bogus pointer offset and / or bytecount value */ - pm_message("Illegal pointer offset value in EXIF " - "for tag %04x. " - "Offset %d bytes %d ExifLen %d\n", - Tag, OffsetVal, ByteCount, ExifLength); - continue; - } - ValuePtr = ExifData+OffsetVal; + break; + + case TAG_FOCALLENGTH: + /* Nice digital cameras actually save the focal length + as a function of how farthey are zoomed in. + */ + + imageInfoP->FocalLength = + (float)convertAnyFormat(valuePtr, format, byteOrder); + break; + + case TAG_SUBJECT_DISTANCE: + /* Inidcates the distacne the autofocus camera is focused to. + Tends to be less accurate as distance increases. + */ + imageInfoP->Distance = + (float)convertAnyFormat(valuePtr, format, byteOrder); + break; + + case TAG_EXPOSURETIME: + /* Simplest way of expressing exposure time, so I + trust it most. (overwrite previously computd value + if there is one) + */ + imageInfoP->ExposureTime = + (float)convertAnyFormat(valuePtr, format, byteOrder); + break; + + case TAG_SHUTTERSPEED: + /* More complicated way of expressing exposure time, + so only use this value if we don't already have it + from somewhere else. + */ + if (imageInfoP->ExposureTime == 0){ + imageInfoP->ExposureTime = (float) + (1/exp(convertAnyFormat(valuePtr, format, byteOrder) + * log(2))); + } + break; + + case TAG_FLASH: + if ((int)convertAnyFormat(valuePtr, format, byteOrder) & 0x7){ + imageInfoP->FlashUsed = TRUE; }else{ - /* 4 bytes or less and value is in the dir entry itself */ - ValuePtr = DirEntry+8; + imageInfoP->FlashUsed = FALSE; } + break; - if (*LastExifRefdP < ValuePtr+ByteCount){ - /* Keep track of last byte in the exif header that was - actually referenced. That way, we know where the - discardable thumbnail data begins. - */ - *LastExifRefdP = ValuePtr+ByteCount; + case TAG_ORIENTATION: + imageInfoP->Orientation = + (int)convertAnyFormat(valuePtr, format, byteOrder); + if (imageInfoP->Orientation < 1 || + imageInfoP->Orientation > 8){ + pm_message("Undefined rotation value %d", + imageInfoP->Orientation); + imageInfoP->Orientation = 0; } + break; - if (ShowTags){ - /* Show tag name */ - for (a=0;;a++){ - if (TagTable[a].Tag == 0){ - fprintf(stderr, " Unknown Tag %04x Value = ", Tag); - break; - } - if (TagTable[a].Tag == Tag){ - fprintf(stderr, " %s = ",TagTable[a].Desc); - break; - } - } + case TAG_EXIF_IMAGELENGTH: + case TAG_EXIF_IMAGEWIDTH: + /* Use largest of height and width to deal with images + that have been rotated to portrait format. + */ + ExifImageWidth = + MIN(ExifImageWidth, + (int)convertAnyFormat(valuePtr, format, byteOrder)); + break; - /* Show tag value. */ - switch(Format){ - - case FMT_UNDEFINED: - /* Undefined is typically an ascii string. */ - - case FMT_STRING: - /* String arrays printed without function call - (different from int arrays) - */ - { - int NoPrint = 0; - printf("\""); - for (a=0;aCameraMake, (char*)ValuePtr); - break; - - case TAG_MODEL: - STRSCPY(ImageInfoP->CameraModel, (char*)ValuePtr); - break; - - case TAG_XRESOLUTION: - ImageInfoP->XResolution = - ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_YRESOLUTION: - ImageInfoP->YResolution = - ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_DATETIME_ORIGINAL: - STRSCPY(ImageInfoP->DateTime, (char*)ValuePtr); - ImageInfoP->DatePointer = (char*)ValuePtr; - break; - - case TAG_USERCOMMENT: - /* Olympus has this padded with trailing spaces. - Remove these first. - */ - for (a=ByteCount;;){ - a--; - if (((char*)ValuePtr)[a] == ' '){ - ((char*)ValuePtr)[a] = '\0'; - }else{ - break; - } - if (a == 0) break; - } + /* Remaining cases contributed by: Volker C. Schoech + (schoech@gmx.de) + */ - /* Copy the comment */ - if (memcmp(ValuePtr, "ASCII",5) == 0){ - for (a=5;a<10;a++){ - char c; - c = ((char*)ValuePtr)[a]; - if (c != '\0' && c != ' '){ - strncpy(ImageInfoP->Comments, (char*)ValuePtr+a, - 199); - break; - } - } - - }else{ - strncpy(ImageInfoP->Comments, (char*)ValuePtr, 199); - } - break; - - case TAG_FNUMBER: - /* Simplest way of expressing aperture, so I trust it the most. - (overwrite previously computd value if there is one) - */ - ImageInfoP->ApertureFNumber = - (float)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_APERTURE: - case TAG_MAXAPERTURE: - /* More relevant info always comes earlier, so only - use this field if we don't have appropriate aperture - information yet. - */ - if (ImageInfoP->ApertureFNumber == 0){ - ImageInfoP->ApertureFNumber = (float) - exp(ConvertAnyFormat(ValuePtr, Format)*log(2)*0.5); - } - break; + case TAG_EXPOSURE_BIAS: + imageInfoP->ExposureBias = + (float) convertAnyFormat(valuePtr, format, byteOrder); + break; - case TAG_FOCALLENGTH: - /* Nice digital cameras actually save the focal length - as a function of how farthey are zoomed in. - */ + case TAG_WHITEBALANCE: + imageInfoP->Whitebalance = + (int)convertAnyFormat(valuePtr, format, byteOrder); + break; - ImageInfoP->FocalLength = - (float)ConvertAnyFormat(ValuePtr, Format); - break; + case TAG_METERING_MODE: + imageInfoP->MeteringMode = + (int)convertAnyFormat(valuePtr, format, byteOrder); + break; - case TAG_SUBJECT_DISTANCE: - /* Inidcates the distacne the autofocus camera is focused to. - Tends to be less accurate as distance increases. - */ - ImageInfoP->Distance = - (float)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_EXPOSURETIME: - /* Simplest way of expressing exposure time, so I - trust it most. (overwrite previously computd value - if there is one) - */ - ImageInfoP->ExposureTime = - (float)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_SHUTTERSPEED: - /* More complicated way of expressing exposure time, - so only use this value if we don't already have it - from somewhere else. - */ - if (ImageInfoP->ExposureTime == 0){ - ImageInfoP->ExposureTime = (float) - (1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2))); - } - break; + case TAG_EXPOSURE_PROGRAM: + imageInfoP->ExposureProgram = + (int)convertAnyFormat(valuePtr, format, byteOrder); + break; - case TAG_FLASH: - if ((int)ConvertAnyFormat(ValuePtr, Format) & 7){ - ImageInfoP->FlashUsed = TRUE; - }else{ - ImageInfoP->FlashUsed = FALSE; - } - break; - - case TAG_ORIENTATION: - ImageInfoP->Orientation = - (int)ConvertAnyFormat(ValuePtr, Format); - if (ImageInfoP->Orientation < 1 || - ImageInfoP->Orientation > 8){ - pm_message("Undefined rotation value %d", - ImageInfoP->Orientation); - ImageInfoP->Orientation = 0; - } - break; + case TAG_ISO_EQUIVALENT: + imageInfoP->ISOequivalent = + (int)convertAnyFormat(valuePtr, format, byteOrder); + if ( imageInfoP->ISOequivalent < 50 ) + imageInfoP->ISOequivalent *= 200; + break; - case TAG_EXIF_IMAGELENGTH: - case TAG_EXIF_IMAGEWIDTH: - /* Use largest of height and width to deal with images - that have been rotated to portrait format. - */ - a = (int)ConvertAnyFormat(ValuePtr, Format); - if (ExifImageWidth < a) ExifImageWidth = a; - break; - - case TAG_FOCALPLANEXRES: - HaveXRes = TRUE; - FocalplaneXRes = ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_FOCALPLANEUNITS: - switch((int)ConvertAnyFormat(ValuePtr, Format)){ - case 1: FocalplaneUnits = 25.4; break; /* 1 inch */ - case 2: - /* According to the information I was using, 2 - means meters. But looking at the Cannon - powershot's files, inches is the only - sensible value. - */ - FocalplaneUnits = 25.4; - break; + case TAG_COMPRESSION_LEVEL: + imageInfoP->CompressionLevel = + (int)convertAnyFormat(valuePtr, format, byteOrder); + break; - case 3: FocalplaneUnits = 10; break; /* 1 centimeter*/ - case 4: FocalplaneUnits = 1; break; /* 1 millimeter*/ - case 5: FocalplaneUnits = .001; break; /* 1 micrometer*/ - } - break; + case TAG_THUMBNAIL_OFFSET: + *thumbnailOffsetP = (unsigned int) + convertAnyFormat(valuePtr, format, byteOrder); + break; - /* Remaining cases contributed by: Volker C. Schoech - (schoech@gmx.de) - */ + case TAG_THUMBNAIL_LENGTH: + *thumbnailSizeP = (unsigned int) + convertAnyFormat(valuePtr, format, byteOrder); + break; - case TAG_EXPOSURE_BIAS: - ImageInfoP->ExposureBias = - (float) ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_WHITEBALANCE: - ImageInfoP->Whitebalance = - (int)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_METERING_MODE: - ImageInfoP->MeteringMode = - (int)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_EXPOSURE_PROGRAM: - ImageInfoP->ExposureProgram = - (int)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_ISO_EQUIVALENT: - ImageInfoP->ISOequivalent = - (int)ConvertAnyFormat(ValuePtr, Format); - if ( ImageInfoP->ISOequivalent < 50 ) - ImageInfoP->ISOequivalent *= 200; - break; - - case TAG_COMPRESSION_LEVEL: - ImageInfoP->CompressionLevel = - (int)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_THUMBNAIL_OFFSET: - ThumbnailOffset = (unsigned)ConvertAnyFormat(ValuePtr, Format); - DirWithThumbnailPtrs = DirStart; - break; - - case TAG_THUMBNAIL_LENGTH: - ThumbnailSize = (unsigned)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_EXIF_OFFSET: - case TAG_INTEROP_OFFSET: - { - unsigned int const SubdirOffset = Get32u(ValuePtr); - if (SubdirOffset >= ExifLength) - pm_message("Illegal exif or interop offset " - "directory link. Offset is %u, " - "but Exif data is only %u bytes.", - SubdirOffset, ExifLength); - else - ProcessExifDir(ExifData, ExifLength, SubdirOffset, - ImageInfoP, ShowTags, LastExifRefdP); - continue; - } - } + case TAG_EXIF_OFFSET: + case TAG_INTEROP_OFFSET: { + unsigned int const subdirOffset = get32u(valuePtr, byteOrder); + if (subdirOffset >= exifLength) + pm_message("Illegal exif or interop offset " + "directory link. Offset is %u, " + "but Exif data is only %u bytes.", + subdirOffset, exifLength); + else + processExifDir(exifData, exifLength, subdirOffset, + imageInfoP, byteOrder, wantTagTrace, + lastExifRefdP); + } break; + } +} + + + +static void +processExifDir(const unsigned char * const exifData, + unsigned int const exifLength, + unsigned int const dirOffset, + exif_ImageInfo * const imageInfoP, + ByteOrder const byteOrder, + bool const wantTagTrace, + const unsigned char ** const lastExifRefdP) { +/*-------------------------------------------------------------------------- + Process one of the nested EXIF directories. +--------------------------------------------------------------------------*/ + const unsigned char * const dirStart = exifData + dirOffset; + unsigned int const numDirEntries = get16u(&dirStart[0], byteOrder); + unsigned int de; + bool haveThumbnail; + unsigned int thumbnailOffset; + unsigned int thumbnailSize; + + #define DIR_ENTRY_ADDR(Start, Entry) (Start+2+12*(Entry)) + { + const unsigned char * const dirEnd = + DIR_ENTRY_ADDR(dirStart, numDirEntries); + if (dirEnd + 4 > (exifData + exifLength)){ + if (dirEnd + 2 == exifData + exifLength || + dirEnd == exifData + exifLength){ + /* Version 1.3 of jhead would truncate a bit too much. + This also caught later on as well. + */ + }else{ + /* Note: Files that had thumbnails trimmed with jhead + 1.3 or earlier might trigger this. + */ + pm_message("Illegal directory entry size"); + return; + } + } + *lastExifRefdP = MAX(*lastExifRefdP, dirEnd); } + if (wantTagTrace) + pm_message("Directory with %d entries", numDirEntries); + + haveThumbnail = false; /* initial value */ + thumbnailOffset = 0; /* initial value */ + thumbnailSize = 0; /* initial value */ + + for (de = 0; de < numDirEntries; ++de) + processDirEntry(DIR_ENTRY_ADDR(dirStart, de), exifData, exifLength, + byteOrder, wantTagTrace, imageInfoP, + &thumbnailOffset, &thumbnailSize, &haveThumbnail, + lastExifRefdP); + + if (haveThumbnail) + DirWithThumbnailPtrs = dirStart; { /* In addition to linking to subdirectories via exif tags, @@ -706,28 +791,30 @@ ProcessExifDir(unsigned char * const ExifData, of each directory. This has got to be the result of a committee! */ - if (DIR_ENTRY_ADDR(DirStart, NumDirEntries) + 4 <= - ExifData+ExifLength){ - unsigned int const SubdirOffset = - Get32u(DirStart+2+12*NumDirEntries); - if (SubdirOffset){ - unsigned char * const SubdirStart = ExifData + SubdirOffset; - if (SubdirStart > ExifData+ExifLength){ - if (SubdirStart < ExifData+ExifLength+20){ + if (DIR_ENTRY_ADDR(dirStart, numDirEntries) + 4 <= + exifData + exifLength){ + unsigned int const subdirOffset = + get32u(dirStart + 2 + 12*numDirEntries, byteOrder); + if (subdirOffset){ + const unsigned char * const subdirStart = + exifData + subdirOffset; + if (subdirStart > exifData + exifLength){ + if (subdirStart < exifData + exifLength + 20){ /* Jhead 1.3 or earlier would crop the whole directory! As Jhead produces this form of format incorrectness, I'll just let it pass silently. */ - if (ShowTags) + if (wantTagTrace) printf("Thumbnail removed with " "Jhead 1.3 or earlier\n"); }else{ pm_message("Illegal subdirectory link"); } }else{ - if (SubdirOffset <= ExifLength) - ProcessExifDir(ExifData, ExifLength, SubdirOffset, - ImageInfoP, ShowTags, LastExifRefdP); + if (subdirOffset <= exifLength) + processExifDir(exifData, exifLength, subdirOffset, + imageInfoP, byteOrder, wantTagTrace, + lastExifRefdP); } } }else{ @@ -735,14 +822,14 @@ ProcessExifDir(unsigned char * const ExifData, } } - if (ThumbnailSize && ThumbnailOffset){ - if (ThumbnailSize + ThumbnailOffset <= ExifLength){ + if (thumbnailSize && thumbnailOffset){ + if (thumbnailSize + thumbnailOffset <= exifLength){ /* The thumbnail pointer appears to be valid. Store it. */ - ImageInfoP->ThumbnailPointer = ExifData + ThumbnailOffset; - ImageInfoP->ThumbnailSize = ThumbnailSize; + imageInfoP->ThumbnailPointer = exifData + thumbnailOffset; + imageInfoP->ThumbnailSize = thumbnailSize; - if (ShowTags){ - fprintf(stderr, "Thumbnail size: %d bytes\n",ThumbnailSize); + if (wantTagTrace){ + fprintf(stderr, "Thumbnail size: %u bytes\n", thumbnailSize); } } } @@ -751,56 +838,56 @@ ProcessExifDir(unsigned char * const ExifData, void -process_EXIF(unsigned char * const ExifData, - unsigned int const length, - ImageInfo_t * const ImageInfoP, - int const ShowTags, - const char ** const errorP) { +exif_parse(const unsigned char * const exifData, + unsigned int const length, + exif_ImageInfo * const imageInfoP, + bool const wantTagTrace, + const char ** const errorP) { /*-------------------------------------------------------------------------- Interpret an EXIF APP1 marker - 'ExifData' is the actual Exif data; it does not include the + 'exifData' is the actual Exif data; it does not include the "Exif" identifier and length field that often prefix Exif data. 'length' is the length of the Exif section. --------------------------------------------------------------------------*/ + ByteOrder byteOrder; int FirstOffset; - unsigned char * LastExifRefd; + const unsigned char * lastExifRefd; *errorP = NULL; /* initial assumption */ - if (ShowTags){ + if (wantTagTrace) fprintf(stderr, "Exif header %d bytes long\n",length); - } - if (memcmp(ExifData+0,"II",2) == 0) { - if (ShowTags) + if (MEMEQ(exifData + 0, "II" , 2)) { + if (wantTagTrace) fprintf(stderr, "Exif header in Intel order\n"); - MotorolaOrder = 0; + byteOrder = NORMAL; } else { - if (memcmp(ExifData+0, "MM", 2) == 0) { - if (ShowTags) + if (MEMEQ(exifData + 0, "MM", 2)) { + if (wantTagTrace) fprintf(stderr, "Exif header in Motorola order\n"); - MotorolaOrder = 1; + byteOrder = MOTOROLA; } else { - asprintfN(errorP, "Invalid alignment marker in Exif " - "data. First two bytes are '%c%c' (0x%02x%02x) " - "instead of 'II' or 'MM'.", - ExifData[0], ExifData[1], ExifData[0], ExifData[1]); + pm_asprintf(errorP, "Invalid alignment marker in Exif " + "data. First two bytes are '%c%c' (0x%02x%02x) " + "instead of 'II' or 'MM'.", + exifData[0], exifData[1], exifData[0], exifData[1]); } } if (!*errorP) { - unsigned short const start = Get16u(ExifData + 2); + unsigned short const start = get16u(exifData + 2, byteOrder); /* Check the next value for correctness. */ if (start != 0x002a){ - asprintfN(errorP, "Invalid Exif header start. " - "two bytes after the alignment marker " - "should be 0x002a, but is 0x%04x", - start); + pm_asprintf(errorP, "Invalid Exif header start. " + "two bytes after the alignment marker " + "should be 0x002a, but is 0x%04x", + start); } } if (!*errorP) { - FirstOffset = Get32u(ExifData + 4); + FirstOffset = get32u(exifData + 4, byteOrder); if (FirstOffset < 8 || FirstOffset > 16){ /* I used to ensure this was set to 8 (website I used indicated its 8) but PENTAX Optio 230 has it set @@ -809,51 +896,54 @@ process_EXIF(unsigned char * const ExifData, pm_message("Suspicious offset of first IFD value in Exif header"); } - ImageInfoP->Comments[0] = '\0'; /* Initial value - null string */ + imageInfoP->Comments[0] = '\0'; /* Initial value - null string */ HaveXRes = FALSE; /* Initial assumption */ FocalplaneUnits = 0; ExifImageWidth = 0; - LastExifRefd = ExifData; + lastExifRefd = exifData; DirWithThumbnailPtrs = NULL; - ProcessExifDir(ExifData, length, FirstOffset, - ImageInfoP, ShowTags, &LastExifRefd); + processExifDir(exifData, length, FirstOffset, + imageInfoP, byteOrder, wantTagTrace, &lastExifRefd); /* Compute the CCD width, in millimeters. */ if (HaveXRes){ - ImageInfoP->HaveCCDWidth = 1; - ImageInfoP->CCDWidth = + imageInfoP->HaveCCDWidth = 1; + imageInfoP->CCDWidth = (float)(ExifImageWidth * FocalplaneUnits / FocalplaneXRes); } else - ImageInfoP->HaveCCDWidth = 0; + imageInfoP->HaveCCDWidth = 0; - if (ShowTags){ + if (wantTagTrace){ fprintf(stderr, - "Non-settings part of Exif header: %d bytes\n", - ExifData+length-LastExifRefd); + "Non-settings part of Exif header: %lu bytes\n", + (unsigned long)(exifData + length - lastExifRefd)); } } } + + +void +exif_showImageInfo(const exif_ImageInfo * const imageInfoP, + FILE * const fileP) { /*-------------------------------------------------------------------------- Show the collected image info, displaying camera F-stop and shutter speed in a consistent and legible fashion. --------------------------------------------------------------------------*/ -void -ShowImageInfo(ImageInfo_t * const ImageInfoP) -{ - if (ImageInfoP->CameraMake[0]){ - fprintf(stderr, "Camera make : %s\n",ImageInfoP->CameraMake); - fprintf(stderr, "Camera model : %s\n",ImageInfoP->CameraModel); + if (imageInfoP->CameraMake[0]) { + fprintf(fileP, "Camera make : %s\n", imageInfoP->CameraMake); + fprintf(fileP, "Camera model : %s\n", imageInfoP->CameraModel); } - if (ImageInfoP->DateTime[0]){ - fprintf(stderr, "Date/Time : %s\n",ImageInfoP->DateTime); - } - fprintf(stderr, "Resolution : %f x %f\n", - ImageInfoP->XResolution, ImageInfoP->YResolution); - if (ImageInfoP->Orientation > 1){ + if (imageInfoP->DateTime[0]) + fprintf(fileP, "Date/Time : %s\n", imageInfoP->DateTime); + + fprintf(fileP, "Resolution : %f x %f\n", + imageInfoP->XResolution, imageInfoP->YResolution); + + if (imageInfoP->Orientation > 1) { /* Only print orientation if one was supplied, and if its not 1 (normal orientation) @@ -890,154 +980,144 @@ ShowImageInfo(ImageInfo_t * const ImageInfoP) "rotate 270", /* rotate 270 to right it. */ }; - fprintf(stderr, "Orientation : %s\n", - OrientTab[ImageInfoP->Orientation]); + fprintf(fileP, "Orientation : %s\n", + OrientTab[imageInfoP->Orientation]); } - if (ImageInfoP->IsColor == 0){ - fprintf(stderr, "Color/bw : Black and white\n"); - } - if (ImageInfoP->FlashUsed >= 0){ - fprintf(stderr, "Flash used : %s\n", - ImageInfoP->FlashUsed ? "Yes" :"No"); - } - if (ImageInfoP->FocalLength){ - fprintf(stderr, "Focal length : %4.1fmm", - (double)ImageInfoP->FocalLength); - if (ImageInfoP->HaveCCDWidth){ - fprintf(stderr, " (35mm equivalent: %dmm)", + if (imageInfoP->IsColor == 0) + fprintf(fileP, "Color/bw : Black and white\n"); + + if (imageInfoP->FlashUsed >= 0) + fprintf(fileP, "Flash used : %s\n", + imageInfoP->FlashUsed ? "Yes" :"No"); + + if (imageInfoP->FocalLength) { + fprintf(fileP, "Focal length : %4.1fmm", + (double)imageInfoP->FocalLength); + if (imageInfoP->HaveCCDWidth){ + fprintf(fileP, " (35mm equivalent: %dmm)", (int) - (ImageInfoP->FocalLength/ImageInfoP->CCDWidth*36 + 0.5)); + (imageInfoP->FocalLength/imageInfoP->CCDWidth*36 + 0.5)); } - fprintf(stderr, "\n"); + fprintf(fileP, "\n"); } - if (ImageInfoP->HaveCCDWidth){ - fprintf(stderr, "CCD width : %2.4fmm\n", - (double)ImageInfoP->CCDWidth); - } + if (imageInfoP->HaveCCDWidth) + fprintf(fileP, "CCD width : %2.4fmm\n", + (double)imageInfoP->CCDWidth); - if (ImageInfoP->ExposureTime){ - if (ImageInfoP->ExposureTime < 0.010){ - fprintf(stderr, + if (imageInfoP->ExposureTime) { + if (imageInfoP->ExposureTime < 0.010){ + fprintf(fileP, "Exposure time: %6.4f s ", - (double)ImageInfoP->ExposureTime); + (double)imageInfoP->ExposureTime); }else{ - fprintf(stderr, + fprintf(fileP, "Exposure time: %5.3f s ", - (double)ImageInfoP->ExposureTime); + (double)imageInfoP->ExposureTime); } - if (ImageInfoP->ExposureTime <= 0.5){ - fprintf(stderr, " (1/%d)",(int)(0.5 + 1/ImageInfoP->ExposureTime)); + if (imageInfoP->ExposureTime <= 0.5){ + fprintf(fileP, " (1/%d)",(int)(0.5 + 1/imageInfoP->ExposureTime)); } - fprintf(stderr, "\n"); + fprintf(fileP, "\n"); } - if (ImageInfoP->ApertureFNumber){ - fprintf(stderr, "Aperture : f/%3.1f\n", - (double)ImageInfoP->ApertureFNumber); + if (imageInfoP->ApertureFNumber){ + fprintf(fileP, "Aperture : f/%3.1f\n", + (double)imageInfoP->ApertureFNumber); } - if (ImageInfoP->Distance){ - if (ImageInfoP->Distance < 0){ - fprintf(stderr, "Focus dist. : Infinite\n"); + if (imageInfoP->Distance){ + if (imageInfoP->Distance < 0){ + fprintf(fileP, "Focus dist. : Infinite\n"); }else{ - fprintf(stderr, "Focus dist. :%5.2fm\n", - (double)ImageInfoP->Distance); + fprintf(fileP, "Focus dist. :%5.2fm\n", + (double)imageInfoP->Distance); } } - - - - - if (ImageInfoP->ISOequivalent){ /* 05-jan-2001 vcs */ - fprintf(stderr, "ISO equiv. : %2d\n",(int)ImageInfoP->ISOequivalent); + if (imageInfoP->ISOequivalent){ /* 05-jan-2001 vcs */ + fprintf(fileP, "ISO equiv. : %2d\n",(int)imageInfoP->ISOequivalent); } - if (ImageInfoP->ExposureBias){ /* 05-jan-2001 vcs */ - fprintf(stderr, "Exposure bias:%4.2f\n", - (double)ImageInfoP->ExposureBias); + if (imageInfoP->ExposureBias){ /* 05-jan-2001 vcs */ + fprintf(fileP, "Exposure bias:%4.2f\n", + (double)imageInfoP->ExposureBias); } - if (ImageInfoP->Whitebalance){ /* 05-jan-2001 vcs */ - switch(ImageInfoP->Whitebalance) { + if (imageInfoP->Whitebalance){ /* 05-jan-2001 vcs */ + switch(imageInfoP->Whitebalance) { case 1: - fprintf(stderr, "Whitebalance : sunny\n"); + fprintf(fileP, "Whitebalance : sunny\n"); break; case 2: - fprintf(stderr, "Whitebalance : fluorescent\n"); + fprintf(fileP, "Whitebalance : fluorescent\n"); break; case 3: - fprintf(stderr, "Whitebalance : incandescent\n"); + fprintf(fileP, "Whitebalance : incandescent\n"); break; default: - fprintf(stderr, "Whitebalance : cloudy\n"); + fprintf(fileP, "Whitebalance : cloudy\n"); } } - if (ImageInfoP->MeteringMode){ /* 05-jan-2001 vcs */ - switch(ImageInfoP->MeteringMode) { + if (imageInfoP->MeteringMode){ /* 05-jan-2001 vcs */ + switch(imageInfoP->MeteringMode) { case 2: - fprintf(stderr, "Metering Mode: center weight\n"); + fprintf(fileP, "Metering Mode: center weight\n"); break; case 3: - fprintf(stderr, "Metering Mode: spot\n"); + fprintf(fileP, "Metering Mode: spot\n"); break; case 5: - fprintf(stderr, "Metering Mode: matrix\n"); + fprintf(fileP, "Metering Mode: matrix\n"); break; } } - if (ImageInfoP->ExposureProgram){ /* 05-jan-2001 vcs */ - switch(ImageInfoP->ExposureProgram) { + if (imageInfoP->ExposureProgram){ /* 05-jan-2001 vcs */ + switch(imageInfoP->ExposureProgram) { case 2: - fprintf(stderr, "Exposure : program (auto)\n"); + fprintf(fileP, "Exposure : program (auto)\n"); break; case 3: - fprintf(stderr, "Exposure : aperture priority (semi-auto)\n"); + fprintf(fileP, "Exposure : aperture priority (semi-auto)\n"); break; case 4: - fprintf(stderr, "Exposure : shutter priority (semi-auto)\n"); + fprintf(fileP, "Exposure : shutter priority (semi-auto)\n"); break; } } - if (ImageInfoP->CompressionLevel){ /* 05-jan-2001 vcs */ - switch(ImageInfoP->CompressionLevel) { + if (imageInfoP->CompressionLevel){ /* 05-jan-2001 vcs */ + switch(imageInfoP->CompressionLevel) { case 1: - fprintf(stderr, "Jpeg Quality : basic\n"); + fprintf(fileP, "Jpeg Quality : basic\n"); break; case 2: - fprintf(stderr, "Jpeg Quality : normal\n"); + fprintf(fileP, "Jpeg Quality : normal\n"); break; case 4: - fprintf(stderr, "Jpeg Quality : fine\n"); + fprintf(fileP, "Jpeg Quality : fine\n"); break; } } - - /* Print the comment. Print 'Comment:' for each new line of comment. */ - if (ImageInfoP->Comments[0]){ - int a,c; - fprintf(stderr, "Comment : "); - for (a=0;aComments[a]; - if (c == '\0') break; + if (imageInfoP->Comments[0]) { + unsigned int a; + + fprintf(fileP, "Comment : "); + + for (a = 0; a < MAX_COMMENT && imageInfoP->Comments[a]; ++a) { + char const c = imageInfoP->Comments[a]; if (c == '\n'){ /* Do not start a new line if the string ends with a cr */ - if (ImageInfoP->Comments[a+1] != '\0'){ - fprintf(stderr, "\nComment : "); - }else{ - fprintf(stderr, "\n"); - } - }else{ - putc(c, stderr); - } + if (imageInfoP->Comments[a+1] != '\0') + fprintf(fileP, "\nComment : "); + else + fprintf(fileP, "\n"); + } else + putc(c, fileP); } - fprintf(stderr, "\n"); + fprintf(fileP, "\n"); } - fprintf(stderr, "\n"); + fprintf(fileP, "\n"); } - - diff --git a/converter/other/exif.h b/converter/other/exif.h index 4630988f..57eb745b 100644 --- a/converter/other/exif.h +++ b/converter/other/exif.h @@ -1,9 +1,12 @@ #ifndef EXIF_H_INCLUDED #define EXIF_H_INCLUDED +#include +#include "netpbm/pm_c_util.h" + #define MAX_COMMENT 2000 -#ifdef _WIN32 +#if MSVCRT #define PATH_MAX _MAX_PATH #endif @@ -35,23 +38,24 @@ typedef struct { int CompressionLevel; char Comments[MAX_COMMENT]; - unsigned char * ThumbnailPointer; /* Pointer at the thumbnail */ + const unsigned char * ThumbnailPointer; /* Pointer at the thumbnail */ unsigned ThumbnailSize; /* Size of thumbnail. */ - char * DatePointer; -}ImageInfo_t; + const char * DatePointer; +} exif_ImageInfo; /* Prototypes for exif.c functions. */ void -process_EXIF(unsigned char * const ExifSection, - unsigned int const length, - ImageInfo_t * const ImageInfoP, - int const ShowTags, - const char ** const errorP); +exif_parse(const unsigned char * const exifSection, + unsigned int const length, + exif_ImageInfo * const imageInfoP, + bool const wantTagTrace, + const char ** const errorP); void -ShowImageInfo(ImageInfo_t * const ImageInfoP); +exif_showImageInfo(const exif_ImageInfo * const imageInfoP, + FILE * const fileP); #endif diff --git a/converter/other/fiasco/Makefile b/converter/other/fiasco/Makefile index 16221d77..392e843c 100644 --- a/converter/other/fiasco/Makefile +++ b/converter/other/fiasco/Makefile @@ -11,8 +11,9 @@ COMP_INCLUDES = \ -I$(SRCDIR)/$(SUBDIR)/codec -I$(SRCDIR)/$(SUBDIR)/input \ -I$(SRCDIR)/$(SUBDIR)/output -I$(SRCDIR)/$(SUBDIR)/lib \ -BINARIES = pnmtofiasco fiascotopnm +PORTBINARIES = pnmtofiasco fiascotopnm +BINARIES = $(PORTBINARIES) MERGEBINARIES = $(BINARIES) SCRIPTS = @@ -24,21 +25,18 @@ FIASCOLIBS = codec/libfiasco_codec.a \ output/libfiasco_output.a \ lib/libfiasco_lib.a -COMMON_OBJECTS = binerror.o getopt.o getopt1.o params.o +ADDL_OBJECTS = binerror.o getopt.o getopt1.o params.o -OBJECTS = $(BINARIES:%=%.o) $(COMMON_OBJECTS) +OBJECTS = $(BINARIES:%=%.o) $(ADDL_OBJECTS) -MERGE_OBJECTS = $(BINARIES:%=%.o2) $(COMMON_OBJECTS) $(FIASCOLIBS) +MERGE_OBJECTS = $(BINARIES:%=%.o2) $(ADDL_OBJECTS) $(FIASCOLIBS) SUBDIRS = codec input output lib include $(SRCDIR)/common.mk -$(BINARIES):%:%.o $(COMMON_OBJECTS) $(FIASCOLIBS) $(NETPBMLIB) \ - $(LIBOPT) - $(LD) -o $@ $< $(COMMON_OBJECTS) \ - $(shell $(LIBOPT) $(FIASCOLIBS) $(NETPBMLIB)) $(MATHLIB) \ - $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD) +$(BINARIES):%:%.o $(ADDL_OBJECTS) $(FIASCOLIBS) +$(BINARIES): LDFLAGS_TARGET = $(shell $(LIBOPT) $(FIASCOLIBS)) codec/libfiasco_codec.a: $(BUILDDIR)/$(SUBDIR)/codec FORCE $(MAKE) -C codec -f $(SRCDIR)/$(SUBDIR)/codec/Makefile \ diff --git a/converter/other/fiasco/binerror.c b/converter/other/fiasco/binerror.c index 8a41a214..77243c64 100644 --- a/converter/other/fiasco/binerror.c +++ b/converter/other/fiasco/binerror.c @@ -92,11 +92,7 @@ _error (const char *format, ...) fprintf (stderr, "%s: %s: line %d:\nError: ", executable, error_file, error_line); -#if HAVE_VPRINTF vfprintf (stderr, format, args); -#elif HAVE_DOPRNT - _doprnt (format, args, stderr); -#endif /* HAVE_DOPRNT */ fputc ('\n', stderr); va_end(args); @@ -132,11 +128,7 @@ _warning (const char *format, ...) fprintf (stderr, "%s: %s: line %d:\nWarning: ", executable, error_file, error_line); -#if HAVE_VPRINTF vfprintf (stderr, format, args); -#elif HAVE_DOPRNT - _doprnt (format, args, stderr); -#endif /* HAVE_DOPRNT */ fputc ('\n', stderr); va_end (args); diff --git a/converter/other/fiasco/codec/approx.c b/converter/other/fiasco/codec/approx.c index 72e38cbf..5072fae3 100644 --- a/converter/other/fiasco/codec/approx.c +++ b/converter/other/fiasco/codec/approx.c @@ -294,7 +294,7 @@ static real_t ip_domain_ortho_vector [MAXSTATES][MAXEDGES]; static real_t rem_denominator [MAXSTATES]; static real_t rem_numerator [MAXSTATES]; /* - * At step n of the orthogonalization the comparitive value + * At step n of the orthogonalization the comparative value * (numerator_i / denominator_i):= ^2 / ||o_n|| , * is computed for every domain i, * where o_n := s_i - \sum(k = 0, ... , n-1) {( / ||o_k||^2) o_k} @@ -670,7 +670,7 @@ orthogonalize (unsigned index, unsigned n, unsigned level, real_t min_norm, * for (i = 0, ... , wfa->states) * := - * \sum (k = 0, ... , n - 1){ / ||o_k||^2} - * Moreover the denominator and numerator parts of the comparitive + * Moreover the denominator and numerator parts of the comparative * value are updated. */ for (domain = 0; domain_blocks [domain] >= 0; domain++) diff --git a/converter/other/fiasco/codec/coder.c b/converter/other/fiasco/codec/coder.c index 927ebbda..94e367dd 100644 --- a/converter/other/fiasco/codec/coder.c +++ b/converter/other/fiasco/codec/coder.c @@ -252,14 +252,14 @@ alloc_coder (char const * const * const inputname, lx = (unsigned) (log2 (wi->width - 1) + 1); ly = (unsigned) (log2 (wi->height - 1) + 1); - wi->level = max (lx, ly) * 2 - ((ly == lx + 1) ? 1 : 0); + wi->level = MAX(lx, ly) * 2 - ((ly == lx + 1) ? 1 : 0); } c = Calloc (1, sizeof (coding_t)); c->options = *options; - c->options.lc_min_level = max (options->lc_min_level, 3); - c->options.lc_max_level = min (options->lc_max_level, wi->level - 1); + c->options.lc_min_level = MAX(options->lc_min_level, 3); + c->options.lc_max_level = MIN(options->lc_max_level, wi->level - 1); c->tiling = alloc_tiling (options->tiling_method, options->tiling_exponent, wi->level); @@ -273,7 +273,7 @@ alloc_coder (char const * const * const inputname, if (c->options.lc_max_level >= wi->level - c->tiling->exponent) { message ("'max_level' changed from %d to %d " - "due to image tiling level.", + "because of image tiling level.", c->options.lc_max_level, wi->level - c->tiling->exponent - 1); c->options.lc_max_level = wi->level - c->tiling->exponent - 1; } @@ -285,16 +285,16 @@ alloc_coder (char const * const * const inputname, * p_min_level, p_max_level min and max level for ND/MC prediction * [p_min_level, p_max_level] must be a subset of [min_level, max_level] ! */ - wi->p_min_level = max (options->p_min_level, c->options.lc_min_level); - wi->p_max_level = min (options->p_max_level, c->options.lc_max_level); + wi->p_min_level = MAX(options->p_min_level, c->options.lc_min_level); + wi->p_max_level = MIN(options->p_max_level, c->options.lc_max_level); if (wi->p_min_level > wi->p_max_level) wi->p_min_level = wi->p_max_level; - c->options.images_level = min (c->options.images_level, - c->options.lc_max_level - 1); + c->options.images_level = MIN(c->options.images_level, + c->options.lc_max_level - 1); - c->products_level = max (0, ((signed int) c->options.lc_max_level - - (signed int) c->options.images_level - 1)); + c->products_level = MAX(0, ((signed int) c->options.lc_max_level + - (signed int) c->options.images_level - 1)); c->pixels = Calloc (size_of_level (c->options.lc_max_level), sizeof (real_t)); c->images_of_state = Calloc (MAXSTATES, sizeof (real_t *)); @@ -324,8 +324,8 @@ alloc_coder (char const * const * const inputname, /* * Max. number of states and edges */ - wi->max_states = max (min (options->max_states, MAXSTATES), 1); - c->options.max_elements = max (min (options->max_elements, MAXEDGES), 1); + wi->max_states = MAX(MIN(options->max_states, MAXSTATES), 1); + c->options.max_elements = MAX(MIN(options->max_elements, MAXEDGES), 1); /* * Title and comment strings @@ -348,7 +348,7 @@ alloc_coder (char const * const * const inputname, /* * Color image options ... */ - wi->chroma_max_states = max (1, options->chroma_max_states); + wi->chroma_max_states = MAX(1, options->chroma_max_states); /* * Set up motion compensation struct. @@ -432,9 +432,9 @@ print_statistics (char c, real_t costs, const wfa_t *wfa, const image_t *image, if (lincomb) { - max_level = max (max_level, + max_level = MAX(max_level, (unsigned) (wfa->level_of_state [state] - 1)); - min_level = min (min_level, + min_level = MIN(min_level, (unsigned) (wfa->level_of_state [state] - 1)); } } @@ -548,77 +548,78 @@ frame_coder (wfa_t *wfa, coding_t *c, bitfile_t *output) } else { - int YCb_node = -1; - int tree [3]; /* 3 root states of each color comp. */ - color_e band; + int YCb_node = -1; + int tree [3]; /* 3 root states of each color comp. */ + color_e band; - /* - * When compressing color images, the three color components (YCbCr) - * are copied into a large image: - * [ Y Cr ] - * [ Cb 0 ] - * I.e. the color components of an image are processed in a row. - * After all components are compressed, virtual states are generated - * to describe the large image. - */ - for (band = first_band (YES); band <= last_band (YES) ; band++) - { - debug_message ("Encoding color component %d", band); - tree [band] = RANGE; - if (band == Cb) - { - unsigned min_level; - - c->domain_pool->chroma (wfa->wfainfo->chroma_max_states, wfa, - c->domain_pool->model); - /* - * Don't use a finer partioning for the chrominancy bands than for - * the luminancy band. - */ - for (min_level = MAXLEVEL, state = wfa->basis_states; - state < wfa->states; state++) - { - unsigned lincomb, label; + /* + * When compressing color images, the three color components (YCbCr) + * are copied into a large image: + * [ Y Cr ] + * [ Cb 0 ] + * I.e. the color components of an image are processed in a row. + * After all components are compressed, virtual states are generated + * to describe the large image. + */ + for (band = first_band (YES); band <= last_band (YES) ; band++) + { + debug_message ("Encoding color component %d", band); + tree [band] = RANGE; + if (band == Cb) + { + unsigned min_level; + + c->domain_pool->chroma (wfa->wfainfo->chroma_max_states, wfa, + c->domain_pool->model); + /* + * Don't use a finer partioning for the chrominancy bands than + * for the luminancy band. + */ + for (min_level = MAXLEVEL, state = wfa->basis_states; + state < wfa->states; state++) + { + unsigned lincomb, label; - for (lincomb = 0, label = 0; label < MAXLABELS; label++) - lincomb += isrange (wfa->tree [state][label]) ? 1 : 0; - if (lincomb) - min_level = min (min_level, - (unsigned) (wfa->level_of_state [state] - - 1)); - } - c->options.lc_min_level = min_level; - if (c->mt->frame_type != I_FRAME) /* subtract mc of luminance */ - subtract_mc (c->mt->original, c->mt->past, c->mt->future, wfa); - } - - memset (&range, 0, sizeof (range_t)); - range.level = wfa->wfainfo->level; + for (lincomb = 0, label = 0; label < MAXLABELS; label++) + lincomb += isrange (wfa->tree [state][label]) ? 1 : 0; + if (lincomb) + min_level = MIN(min_level, + (unsigned) (wfa->level_of_state [state] + - 1)); + } + c->options.lc_min_level = min_level; + if (c->mt->frame_type != I_FRAME) /* subtract mc of luminance */ + subtract_mc (c->mt->original, c->mt->past, c->mt->future, + wfa); + } + + memset (&range, 0, sizeof (range_t)); + range.level = wfa->wfainfo->level; - costs = subdivide (MAXCOSTS, band, tree [Y], &range, wfa, c, - c->mt->frame_type != I_FRAME && band == Y, NO); - if (c->options.progress_meter != FIASCO_PROGRESS_NONE) - message (""); - { - char colors [] = {'Y', 'B', 'R'}; + costs = subdivide (MAXCOSTS, band, tree [Y], &range, wfa, c, + c->mt->frame_type != I_FRAME && band == Y, NO); + if (c->options.progress_meter != FIASCO_PROGRESS_NONE) + message (""); + { + char colors [] = {'Y', 'B', 'R'}; - print_statistics (colors [band], costs, wfa, - c->mt->original, &range); - } + print_statistics (colors [band], costs, wfa, + c->mt->original, &range); + } - if (isrange (range.tree)) /* whole image is approx. by a l.c. */ - error ("No root state generated for color component %d!", band); - else - tree[band] = range.tree; + if (isrange (range.tree)) /* whole image is approx. by a l.c. */ + error ("No root state generated for color component %d!", band); + else + tree[band] = range.tree; - if (band == Cb) - { - wfa->tree [wfa->states][0] = tree[Y]; - wfa->tree [wfa->states][1] = tree[Cb]; - YCb_node = wfa->states; - append_state (YES, compute_final_distribution (wfa->states, wfa), - wfa->wfainfo->level + 1, wfa, c); - } + if (band == Cb) + { + wfa->tree [wfa->states][0] = tree[Y]; + wfa->tree [wfa->states][1] = tree[Cb]; + YCb_node = wfa->states; + append_state (YES, compute_final_distribution(wfa->states, wfa), + wfa->wfainfo->level + 1, wfa, c); + } } /* * generate two virtual states (*) diff --git a/converter/other/fiasco/codec/control.c b/converter/other/fiasco/codec/control.c index 9af9928b..94c23c83 100644 --- a/converter/other/fiasco/codec/control.c +++ b/converter/other/fiasco/codec/control.c @@ -16,11 +16,7 @@ #include "config.h" -#if HAVE_STRING_H -# include -#else /* not HAVE_STRING_H */ -# include -#endif /* not HAVE_STRING_H */ +#include #include "types.h" #include "macros.h" diff --git a/converter/other/fiasco/codec/decoder.c b/converter/other/fiasco/codec/decoder.c index 77d5340f..26284596 100644 --- a/converter/other/fiasco/codec/decoder.c +++ b/converter/other/fiasco/codec/decoder.c @@ -1,9 +1,9 @@ /* - * decode.c: Decoding of an image represented by a WFA + * decode.c: Decoding of an image represented by a WFA * - * Written by: Ullrich Hafner - * Michael Unger - * + * Written by: Ullrich Hafner + * Michael Unger + * * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) * Copyright (C) 1994-2000 Ullrich Hafner */ @@ -15,13 +15,12 @@ * $State: Exp $ */ +#include "pm_config.h" #include "config.h" -#if HAVE_STRING_H -# include -#else /* not HAVE_STRING_H */ -# include -#endif /* not HAVE_STRING_H */ +#include + +#include "pm_c_util.h" #include "types.h" #include "macros.h" @@ -37,33 +36,33 @@ /***************************************************************************** - prototypes + prototypes *****************************************************************************/ static void compute_state_images (unsigned frame_level, word_t **simg, - const u_word_t *offset, const wfa_t *wfa); + const u_word_t *offset, const wfa_t *wfa); static void free_state_images (unsigned max_level, bool_t color, word_t **state_image, - u_word_t *offset, const unsigned *root_state, - unsigned range_state, format_e format, const wfa_t *wfa); + u_word_t *offset, const unsigned *root_state, + unsigned range_state, format_e format, const wfa_t *wfa); static void alloc_state_images (word_t ***images, u_word_t **offsets, const image_t *frame, - const unsigned *root_state, unsigned range_state, - unsigned max_level, format_e format, const wfa_t *wfa); + const unsigned *root_state, unsigned range_state, + unsigned max_level, format_e format, const wfa_t *wfa); static void compute_actual_size (unsigned luminance_root, - unsigned *width, unsigned *height, const wfa_t *wfa); + unsigned *width, unsigned *height, const wfa_t *wfa); static void enlarge_image (int enlarge_factor, format_e format, unsigned y_root, - wfa_t *wfa); + wfa_t *wfa); static word_t * duplicate_state_image (const word_t *domain, unsigned offset, unsigned level); /***************************************************************************** - public code + public code *****************************************************************************/ @@ -75,7 +74,7 @@ alloc_video (bool_t store_wfa) * and future WFA if flag 'store_wfa' is TRUE. * * Return value: - * pointer to the new video structure + * pointer to the new video structure */ { video_t *video = Calloc (1, sizeof (video_t)); @@ -84,7 +83,7 @@ alloc_video (bool_t store_wfa) video->display = 0; video->future = video->sfuture = video->past - = video->frame = video->sframe = NULL; + = video->frame = video->sframe = NULL; if (store_wfa) { @@ -107,7 +106,7 @@ free_video (video_t *video) * No return value. * * Side effects: - * 'video' struct is discarded. + * 'video' struct is discarded. */ { if (video->past) @@ -132,9 +131,9 @@ free_video (video_t *video) image_t * get_next_frame (bool_t store_wfa, int enlarge_factor, - int smoothing, const char *reference_frame, - format_e format, video_t *video, dectimer_t *timer, - wfa_t *orig_wfa, bitfile_t *input) + int smoothing, const char *reference_frame, + format_e format, video_t *video, dectimer_t *timer, + wfa_t *orig_wfa, bitfile_t *input) /* * Get next frame of the WFA 'video' from stream 'input'. * 'orig_wfa' is the constant part of the WFA used by all frames. @@ -148,265 +147,265 @@ get_next_frame (bool_t store_wfa, int enlarge_factor, * If 'timer' is not NULL, then accumulate running time statistics. * * Return value: - * pointer to decoded frame + * pointer to decoded frame * * Side effects: - * 'video' and 'timer' struct are modified. + * 'video' and 'timer' struct are modified. */ { - image_t *frame = NULL; /* current frame */ - image_t *sframe = NULL; /* current smoothed frame */ + image_t *frame = NULL; /* current frame */ + image_t *sframe = NULL; /* current smoothed frame */ bool_t current_frame_is_future_frame = NO; - if (video->future_display == video->display) + if (video->future_display == video->display) { /* * Future frame is already computed since it has been used * as reference frame. So just return the stored frame. */ if (video->frame) /* discard current frame */ - free_image (video->frame); + free_image (video->frame); video->frame = video->future; video->future = NULL; if (video->sframe) /* discard current (smoothed) frame */ - free_image (video->sframe); + free_image (video->sframe); video->sframe = video->sfuture; video->sfuture = NULL; if (store_wfa) - copy_wfa (video->wfa, video->wfa_future); + copy_wfa (video->wfa, video->wfa_future); video->display++; if (!store_wfa) - video->wfa = NULL; + video->wfa = NULL; } else { - do /* compute next frame(s) */ + do /* compute next frame(s) */ { - unsigned frame_number; /* current frame number */ - clock_t ptimer; - unsigned int stop_timer [3]; - wfa_t *tmp_wfa = NULL; - - if (!store_wfa) - video->wfa = orig_wfa; - else - { - tmp_wfa = alloc_wfa (NO); - copy_wfa (tmp_wfa, video->wfa); - copy_wfa (video->wfa, orig_wfa); - } + unsigned frame_number; /* current frame number */ + clock_t ptimer; + unsigned int stop_timer [3]; + wfa_t *tmp_wfa = NULL; + + if (!store_wfa) + video->wfa = orig_wfa; + else + { + tmp_wfa = alloc_wfa (NO); + copy_wfa (tmp_wfa, video->wfa); + copy_wfa (video->wfa, orig_wfa); + } - /* - * First step: read WFA from disk - */ - prg_timer (&ptimer, START); - frame_number = read_next_wfa (video->wfa, input); - stop_timer [0] = prg_timer (&ptimer, STOP); - if (timer) - { - timer->input [video->wfa->frame_type] += stop_timer [0]; - timer->frames [video->wfa->frame_type]++; - } + /* + * First step: read WFA from disk + */ + prg_timer (&ptimer, START); + frame_number = read_next_wfa (video->wfa, input); + stop_timer [0] = prg_timer (&ptimer, STOP); + if (timer) + { + timer->input [video->wfa->frame_type] += stop_timer [0]; + timer->frames [video->wfa->frame_type]++; + } - /* - * Read reference frame from disk if required - * (i.e., 1st frame is of type B or P) - */ - if (video->display == 0 && video->wfa->frame_type != I_FRAME) - { - if (!reference_frame) - error ("First frame is %c-frame but no " - "reference frame is given.", - video->wfa->frame_type == B_FRAME ? 'B' : 'P'); - - video->frame = read_image_file (reference_frame); - video->sframe = NULL; - } + /* + * Read reference frame from disk if required + * (i.e., 1st frame is of type B or P) + */ + if (video->display == 0 && video->wfa->frame_type != I_FRAME) + { + if (!reference_frame) + error ("First frame is %c-frame but no " + "reference frame is given.", + video->wfa->frame_type == B_FRAME ? 'B' : 'P'); + + video->frame = read_image_file (reference_frame); + video->sframe = NULL; + } - /* - * Depending on current frame type update past and future frames - */ - if (video->wfa->frame_type == I_FRAME) - { - if (video->past) /* discard past frame */ - free_image (video->past); - video->past = NULL; - if (video->future) /* discard future frame */ - free_image (video->future); - video->future = NULL; - if (video->sfuture) /* discard (smoothed) future frame */ - free_image (video->sfuture); - video->sfuture = NULL; - if (video->frame) /* discard current frame */ - free_image (video->frame); - video->frame = NULL; - if (video->sframe) /* discard current (smoothed) frame */ - free_image (video->sframe); - video->sframe = NULL; - } - else if (video->wfa->frame_type == P_FRAME) - { - if (video->past) /* discard past frame */ - free_image (video->past); - video->past = video->frame; /* past <- current frame */ - video->frame = NULL; - if (video->sframe) /* discard current (smoothed) frame */ - free_image (video->sframe); - video->sframe = NULL; - if (store_wfa) - copy_wfa (video->wfa_past, tmp_wfa); - if (video->future) /* discard future frame */ - free_image (video->future); - video->future = NULL; - if (video->sfuture) /* discard (smoothed) future frame */ - free_image (video->sfuture); - video->sfuture = NULL; - } - else /* B_FRAME */ - { - if (current_frame_is_future_frame) - { - if (video->future) /* discard future frame */ - free_image (video->future); - video->future = frame; /* future <- current frame */ - if (video->sfuture) /* discard (smoothed) future frame */ - free_image (video->sfuture); - video->sfuture = sframe; /* future <- current (smoothed) */ - if (store_wfa) - copy_wfa (video->wfa_future, tmp_wfa); - if (video->frame) /* discard current frame */ - free_image (video->frame); - video->frame = NULL; - if (video->sframe) /* discard current (smoothed) frame */ - free_image (video->sframe); - video->sframe = NULL; - frame = NULL; - sframe = NULL; - } - else - { - if (video->wfa->wfainfo->B_as_past_ref == YES) - { - if (video->past) /* discard past frame */ - free_image (video->past); - video->past = video->frame; /* past <- current frame */ - video->frame = NULL; - if (video->sframe) /* discard current (smoothed) frame */ - free_image (video->sframe); - video->sframe = NULL; - if (store_wfa) - copy_wfa (video->wfa_past, tmp_wfa); - } - else - { - if (video->frame) /* discard current */ - free_image (video->frame); - video->frame = NULL; - if (video->sframe) /* discard current (smoothed) frame */ - free_image (video->sframe); - video->sframe = NULL; - } - } - } - if (tmp_wfa) - free_wfa (tmp_wfa); - - current_frame_is_future_frame = NO; - /* - * Second step: decode image - * Optionally enlarge image if specified by option 'enlarge_factor'. - */ - { - unsigned orig_width, orig_height; - - stop_timer [0] = stop_timer [1] = stop_timer [2] = 0; - - enlarge_image (enlarge_factor, format, - (video->wfa->wfainfo->color - && format == FORMAT_4_2_0) - ? video->wfa->tree [video->wfa->tree [video->wfa->root_state][0]][0] : -1, video->wfa); - - if (enlarge_factor > 0) - { - orig_width = video->wfa->wfainfo->width << enlarge_factor; - orig_height = video->wfa->wfainfo->height << enlarge_factor; - } - else - { - orig_width = video->wfa->wfainfo->width >> - enlarge_factor; - orig_height = video->wfa->wfainfo->height >> - enlarge_factor; - if (orig_width & 1) - orig_width++; - if (orig_height & 1) - orig_height++; - } - - frame = decode_image (orig_width, orig_height, format, - timer != NULL ? stop_timer : NULL, - video->wfa); - if (timer) - { - timer->preprocessing [video->wfa->frame_type] += stop_timer [0]; - timer->decoder [video->wfa->frame_type] += stop_timer [1]; - timer->cleanup [video->wfa->frame_type] += stop_timer [2]; - } - } - - /* - * Third step: restore motion compensation - */ - if (video->wfa->frame_type != I_FRAME) - { - prg_timer (&ptimer, START); - restore_mc (enlarge_factor, frame, video->past, video->future, - video->wfa); - stop_timer [0] = prg_timer (&ptimer, STOP); - if (timer) - timer->motion [video->wfa->frame_type] += stop_timer [0]; - } - - /* - * Fourth step: smooth image along partitioning borders - */ - prg_timer (&ptimer, START); - if (smoothing < 0) /* smoothing not changed by user */ - smoothing = video->wfa->wfainfo->smoothing; - if (smoothing > 0 && smoothing <= 100) - { - sframe = clone_image (frame); - smooth_image (smoothing, video->wfa, sframe); - } - else - sframe = NULL; - - stop_timer [0] = prg_timer (&ptimer, STOP); - if (timer) - timer->smooth [video->wfa->frame_type] += stop_timer [0]; - - if (frame_number == video->display) - { - video->display++; - video->frame = frame; - video->sframe = sframe; - frame = NULL; - sframe = NULL; - } - else if (frame_number > video->display) - { - video->future_display = frame_number; - current_frame_is_future_frame = YES; - } + /* + * Depending on current frame type update past and future frames + */ + if (video->wfa->frame_type == I_FRAME) + { + if (video->past) /* discard past frame */ + free_image (video->past); + video->past = NULL; + if (video->future) /* discard future frame */ + free_image (video->future); + video->future = NULL; + if (video->sfuture) /* discard (smoothed) future frame */ + free_image (video->sfuture); + video->sfuture = NULL; + if (video->frame) /* discard current frame */ + free_image (video->frame); + video->frame = NULL; + if (video->sframe) /* discard current (smoothed) frame */ + free_image (video->sframe); + video->sframe = NULL; + } + else if (video->wfa->frame_type == P_FRAME) + { + if (video->past) /* discard past frame */ + free_image (video->past); + video->past = video->frame; /* past <- current frame */ + video->frame = NULL; + if (video->sframe) /* discard current (smoothed) frame */ + free_image (video->sframe); + video->sframe = NULL; + if (store_wfa) + copy_wfa (video->wfa_past, tmp_wfa); + if (video->future) /* discard future frame */ + free_image (video->future); + video->future = NULL; + if (video->sfuture) /* discard (smoothed) future frame */ + free_image (video->sfuture); + video->sfuture = NULL; + } + else /* B_FRAME */ + { + if (current_frame_is_future_frame) + { + if (video->future) /* discard future frame */ + free_image (video->future); + video->future = frame; /* future <- current frame */ + if (video->sfuture) /* discard (smoothed) future frame */ + free_image (video->sfuture); + video->sfuture = sframe; /* future <- current (smoothed) */ + if (store_wfa) + copy_wfa (video->wfa_future, tmp_wfa); + if (video->frame) /* discard current frame */ + free_image (video->frame); + video->frame = NULL; + if (video->sframe) /* discard current (smoothed) frame */ + free_image (video->sframe); + video->sframe = NULL; + frame = NULL; + sframe = NULL; + } + else + { + if (video->wfa->wfainfo->B_as_past_ref == YES) + { + if (video->past) /* discard past frame */ + free_image (video->past); + video->past = video->frame; /* past <- current frame */ + video->frame = NULL; + if (video->sframe) /* discard current (smoothed) frame */ + free_image (video->sframe); + video->sframe = NULL; + if (store_wfa) + copy_wfa (video->wfa_past, tmp_wfa); + } + else + { + if (video->frame) /* discard current */ + free_image (video->frame); + video->frame = NULL; + if (video->sframe) /* discard current (smoothed) frame */ + free_image (video->sframe); + video->sframe = NULL; + } + } + } + if (tmp_wfa) + free_wfa (tmp_wfa); + + current_frame_is_future_frame = NO; + /* + * Second step: decode image + * Optionally enlarge image if specified by option 'enlarge_factor'. + */ + { + unsigned orig_width, orig_height; + + stop_timer [0] = stop_timer [1] = stop_timer [2] = 0; + + enlarge_image (enlarge_factor, format, + (video->wfa->wfainfo->color + && format == FORMAT_4_2_0) + ? video->wfa->tree [video->wfa->tree [video->wfa->root_state][0]][0] : -1, video->wfa); + + if (enlarge_factor > 0) + { + orig_width = video->wfa->wfainfo->width << enlarge_factor; + orig_height = video->wfa->wfainfo->height << enlarge_factor; + } + else + { + orig_width = video->wfa->wfainfo->width >> - enlarge_factor; + orig_height = video->wfa->wfainfo->height >> - enlarge_factor; + if (orig_width & 1) + orig_width++; + if (orig_height & 1) + orig_height++; + } + + frame = decode_image (orig_width, orig_height, format, + timer != NULL ? stop_timer : NULL, + video->wfa); + if (timer) + { + timer->preprocessing [video->wfa->frame_type] += stop_timer [0]; + timer->decoder [video->wfa->frame_type] += stop_timer [1]; + timer->cleanup [video->wfa->frame_type] += stop_timer [2]; + } + } + + /* + * Third step: restore motion compensation + */ + if (video->wfa->frame_type != I_FRAME) + { + prg_timer (&ptimer, START); + restore_mc (enlarge_factor, frame, video->past, video->future, + video->wfa); + stop_timer [0] = prg_timer (&ptimer, STOP); + if (timer) + timer->motion [video->wfa->frame_type] += stop_timer [0]; + } + + /* + * Fourth step: smooth image along partitioning borders + */ + prg_timer (&ptimer, START); + if (smoothing < 0) /* smoothing not changed by user */ + smoothing = video->wfa->wfainfo->smoothing; + if (smoothing > 0 && smoothing <= 100) + { + sframe = clone_image (frame); + smooth_image (smoothing, video->wfa, sframe); + } + else + sframe = NULL; + + stop_timer [0] = prg_timer (&ptimer, STOP); + if (timer) + timer->smooth [video->wfa->frame_type] += stop_timer [0]; + + if (frame_number == video->display) + { + video->display++; + video->frame = frame; + video->sframe = sframe; + frame = NULL; + sframe = NULL; + } + else if (frame_number > video->display) + { + video->future_display = frame_number; + current_frame_is_future_frame = YES; + } - if (!store_wfa) - remove_states (video->wfa->basis_states, video->wfa); + if (!store_wfa) + remove_states (video->wfa->basis_states, video->wfa); } while (!video->frame); if (!store_wfa) - video->wfa = NULL; + video->wfa = NULL; } return video->sframe ? video->sframe : video->frame; @@ -414,7 +413,7 @@ get_next_frame (bool_t store_wfa, int enlarge_factor, image_t * decode_image (unsigned orig_width, unsigned orig_height, format_e format, - unsigned *dec_timer, const wfa_t *wfa) + unsigned *dec_timer, const wfa_t *wfa) /* * Compute image which is represented by the given 'wfa'. * 'orig_width'x'orig_height' gives the resolution of the image at @@ -422,20 +421,20 @@ decode_image (unsigned orig_width, unsigned orig_height, format_e format, * If 'dec_timer' is given, accumulate running time statistics. * * Return value: - * pointer to decoded image + * pointer to decoded image * * Side effects: - * '*dectimer' is changed if 'dectimer' != NULL. + * '*dectimer' is changed if 'dectimer' != NULL. */ { - unsigned root_state [3]; /* root of bintree for each band */ - unsigned width, height; /* computed image size */ - image_t *frame; /* regenerated frame */ - word_t **images; /* pointer to array of pointers - to state images */ - u_word_t *offsets; /* pointer to array of state image - offsets */ - unsigned max_level; /* max. level of state with approx. */ + unsigned root_state [3]; /* root of bintree for each band */ + unsigned width, height; /* computed image size */ + image_t *frame; /* regenerated frame */ + word_t **images; /* pointer to array of pointers + to state images */ + u_word_t *offsets; /* pointer to array of state image + offsets */ + unsigned max_level; /* max. level of state with approx. */ unsigned state; clock_t ptimer; @@ -458,16 +457,16 @@ decode_image (unsigned orig_width, unsigned orig_height, format_e format, */ for (max_level = 0, state = wfa->basis_states; state < wfa->states; state++) if (isedge (wfa->into [state][0][0]) || isedge (wfa->into [state][1][0])) - max_level = max (max_level, wfa->level_of_state [state]); + max_level = MAX(max_level, wfa->level_of_state [state]); /* * Allocate frame buffer for decoded image */ compute_actual_size (format == FORMAT_4_2_0 ? root_state [Y] : MAXSTATES, - &width, &height, wfa); - width = max (width, orig_width); - height = max (height, orig_height); + &width, &height, wfa); + width = MAX(width, orig_width); + height = MAX(height, orig_height); frame = alloc_image (width, height, wfa->wfainfo->color, format); /* @@ -480,7 +479,7 @@ decode_image (unsigned orig_width, unsigned orig_height, format_e format, wfa->level_of_state [wfa->tree[wfa->root_state][1]] = 128; } alloc_state_images (&images, &offsets, frame, root_state, 0, max_level, - format, wfa); + format, wfa); if (dec_timer) dec_timer [0] += prg_timer (&ptimer, STOP); @@ -498,38 +497,38 @@ decode_image (unsigned orig_width, unsigned orig_height, format_e format, */ prg_timer (&ptimer, START); free_state_images (max_level, frame->color, images, offsets, root_state, 0, - format, wfa); + format, wfa); /* * Crop decoded image if the image size differs. */ if (orig_width != width || orig_height != height) { - frame->height = orig_height; - frame->width = orig_width; - if (orig_width != width) + frame->height = orig_height; + frame->width = orig_width; + if (orig_width != width) { - color_e band; /* current color band */ - word_t *src, *dst; /* source and destination pointers */ - unsigned y; /* current row */ - - for (band = first_band (frame->color); - band <= last_band (frame->color); band++) - { - src = dst = frame->pixels [band]; - for (y = orig_height; y; y--) - { - memmove (dst, src, orig_width * sizeof (word_t)); - dst += orig_width; - src += width; - } - if (format == FORMAT_4_2_0 && band == Y) - { - orig_width >>= 1; - orig_height >>= 1; - width >>= 1; - } - } + color_e band; /* current color band */ + word_t *src, *dst; /* source and destination pointers */ + unsigned y; /* current row */ + + for (band = first_band (frame->color); + band <= last_band (frame->color); band++) + { + src = dst = frame->pixels [band]; + for (y = orig_height; y; y--) + { + memmove (dst, src, orig_width * sizeof (word_t)); + dst += orig_width; + src += width; + } + if (format == FORMAT_4_2_0 && band == Y) + { + orig_width >>= 1; + orig_height >>= 1; + width >>= 1; + } + } } } if (dec_timer) @@ -544,10 +543,10 @@ decode_state (unsigned state, unsigned level, wfa_t *wfa) * Decode 'state' image of 'wfa' at given 'level'. * * Return value. - * pointer to decoded state image + * pointer to decoded state image * * Side effects: - * 'wfa' states > 'state' are removed. + * 'wfa' states > 'state' are removed. */ { word_t *domains [2]; @@ -571,15 +570,15 @@ decode_state (unsigned state, unsigned level, wfa_t *wfa) */ { word_t *src, *dst; - unsigned y; - + unsigned y; + src = domains [0]; dst = img->pixels [GRAY]; for (y = img->height; y; y--) { - memcpy (dst, src, width_of_level (level) * sizeof (word_t)); - src += width_of_level (level); - dst += img->width; + memcpy (dst, src, width_of_level (level) * sizeof (word_t)); + src += width_of_level (level); + dst += img->width; } Free (domains [0]); } @@ -589,87 +588,87 @@ decode_state (unsigned state, unsigned level, wfa_t *wfa) word_t * decode_range (unsigned range_state, unsigned range_label, unsigned range_level, - word_t **domain, wfa_t *wfa) + word_t **domain, wfa_t *wfa) /* * Compute 'wfa' image of range (identified by 'state' and 'label') * at 'range_level (works as function decode_image()). * * Return value: - * pointer to the pixels in SHORT format + * pointer to the pixels in SHORT format * * Side effects: - * if 'domain' != NULL then also the domain blocks - * of the corresponding range blocks are generated + * if 'domain' != NULL then also the domain blocks + * of the corresponding range blocks are generated * and returned in domain[] - * 'wfa->level_of_state []' is changed + * 'wfa->level_of_state []' is changed */ { - unsigned root_state [3]; /* dummy (for alloc_state_images) */ - image_t *state_image; /* regenerated state image */ - word_t **images; /* pointer to array of pointers - to state images */ - u_word_t *offsets; /* pointer to array of state image - offsets */ + unsigned root_state [3]; /* dummy (for alloc_state_images) */ + image_t *state_image; /* regenerated state image */ + word_t **images; /* pointer to array of pointers + to state images */ + u_word_t *offsets; /* pointer to array of state image + offsets */ word_t *range; enlarge_image (range_level - (wfa->level_of_state [range_state] - 1), - FORMAT_4_4_4, -1, wfa); + FORMAT_4_4_4, -1, wfa); root_state [0] = range_state; state_image = alloc_image (width_of_level (range_level + 1), - height_of_level (range_level + 1), - NO, FORMAT_4_4_4); + height_of_level (range_level + 1), + NO, FORMAT_4_4_4); alloc_state_images (&images, &offsets, state_image, NULL, range_state, - range_level + 1, NO, wfa); + range_level + 1, NO, wfa); compute_state_images (range_level + 1, images, offsets, wfa); range = Calloc (size_of_level (range_level), sizeof (word_t)); - if ((range_level & 1) == 0) /* square image */ + if ((range_level & 1) == 0) /* square image */ { memcpy (range, - images [range_state + (range_level + 1) * wfa->states] - + range_label * size_of_level (range_level), - size_of_level (range_level) * sizeof (word_t)); + images [range_state + (range_level + 1) * wfa->states] + + range_label * size_of_level (range_level), + size_of_level (range_level) * sizeof (word_t)); } - else /* rectangle */ + else /* rectangle */ { word_t *src, *dst; unsigned y; src = images [range_state + (range_level + 1) * wfa->states] - + range_label * width_of_level (range_level); + + range_label * width_of_level (range_level); dst = range; for (y = height_of_level (range_level); y; y--) { - memcpy (dst, src, width_of_level (range_level) * sizeof (word_t)); - dst += width_of_level (range_level); - src += width_of_level (range_level + 1); + memcpy (dst, src, width_of_level (range_level) * sizeof (word_t)); + dst += width_of_level (range_level); + src += width_of_level (range_level + 1); } } - if (domain != NULL) /* copy domain images */ + if (domain != NULL) /* copy domain images */ { - int s; /* domain state */ - unsigned edge; /* counter */ - + int s; /* domain state */ + unsigned edge; /* counter */ + if (ischild (s = wfa->tree [range_state][range_label])) - *domain++ = duplicate_state_image (images [s + (range_level) - * wfa->states], - offsets [s + (range_level) - * wfa->states], - range_level); + *domain++ = duplicate_state_image (images [s + (range_level) + * wfa->states], + offsets [s + (range_level) + * wfa->states], + range_level); for (edge = 0; isedge (s = wfa->into[range_state][range_label][edge]); - edge++) - *domain++ = duplicate_state_image (images [s + (range_level) - * wfa->states], - offsets [s + (range_level) - * wfa->states], - range_level); + edge++) + *domain++ = duplicate_state_image (images [s + (range_level) + * wfa->states], + offsets [s + (range_level) + * wfa->states], + range_level); *domain = NULL; } free_state_images (range_level + 1, NO, images, offsets, NULL, range_state, - NO, wfa); + NO, wfa); free_image (state_image); return range; @@ -684,102 +683,102 @@ smooth_image (unsigned sf, const wfa_t *wfa, image_t *image) * No return value. * * Side effects: - * pixel values of the 'image' are modified with respect to 's' + * pixel values of the 'image' are modified with respect to 's' */ { - int is, inegs; /* integer factors of s and 1 - s*/ - unsigned state; + int is, inegs; /* integer factors of s and 1 - s*/ + unsigned state; unsigned img_width = image->width; unsigned img_height = image->height; - real_t s = 1.0 - sf / 200.0; + real_t s = 1.0 - sf / 200.0; - if (s < 0.5 || s >= 1) /* value out of range */ + if (s < 0.5 || s >= 1) /* value out of range */ return; - is = s * 512 + .5; /* integer representation of s */ - inegs = (1 - s) * 512 + .5; /* integer representation of 1 - s */ + is = s * 512 + .5; /* integer representation of s */ + inegs = (1 - s) * 512 + .5; /* integer representation of 1 - s */ for (state = wfa->basis_states; - state < (wfa->wfainfo->color - ? wfa->tree [wfa->root_state][0] - : wfa->states); state++) + state < (wfa->wfainfo->color + ? wfa->tree [wfa->root_state][0] + : wfa->states); state++) { word_t *bptr = image->pixels [Y]; /* pointer to right or - lower line */ + lower line */ unsigned level = wfa->level_of_state[state]; /* level of state image */ unsigned width = width_of_level (level); /* size of state image */ unsigned height = height_of_level (level); /* size of state image */ if (wfa->y [state][1] >= img_height || wfa->x [state][1] >= img_width) - continue; /* outside visible area */ - - if (level % 2) /* horizontal smoothing */ + continue; /* outside visible area */ + + if (level % 2) /* horizontal smoothing */ { - unsigned i; /* line counter */ - word_t *img1; /* pointer to left or upper line */ - word_t *img2; /* pointer to right or lower line */ - - img1 = bptr + (wfa->y [state][1] - 1) * img_width - + wfa->x [state][1]; - img2 = bptr + wfa->y [state][1] * img_width + wfa->x [state][1]; - - for (i = min (width, img_width - wfa->x [state][1]); i; - i--, img1++, img2++) - { - int tmp = *img1; - + unsigned i; /* line counter */ + word_t *img1; /* pointer to left or upper line */ + word_t *img2; /* pointer to right or lower line */ + + img1 = bptr + (wfa->y [state][1] - 1) * img_width + + wfa->x [state][1]; + img2 = bptr + wfa->y [state][1] * img_width + wfa->x [state][1]; + + for (i = MIN(width, img_width - wfa->x [state][1]); i; + i--, img1++, img2++) + { + int tmp = *img1; + #ifdef HAVE_SIGNED_SHIFT - *img1 = (((is * tmp) >> 10) << 1) - + (((inegs * (int) *img2) >> 10) << 1); - *img2 = (((is * (int) *img2) >> 10) << 1) - + (((inegs * tmp) >> 10) << 1); + *img1 = (((is * tmp) >> 10) << 1) + + (((inegs * (int) *img2) >> 10) << 1); + *img2 = (((is * (int) *img2) >> 10) << 1) + + (((inegs * tmp) >> 10) << 1); #else /* not HAVE_SIGNED_SHIFT */ - *img1 = (((is * tmp) / 1024) * 2) - + (((inegs * (int) *img2) / 1024) * 2); - *img2 = (((is * (int) *img2) / 1024) * 2) - + (((inegs * tmp) / 1024) *2); + *img1 = (((is * tmp) / 1024) * 2) + + (((inegs * (int) *img2) / 1024) * 2); + *img2 = (((is * (int) *img2) / 1024) * 2) + + (((inegs * tmp) / 1024) *2); #endif /* not HAVE_SIGNED_SHIFT */ - } + } } - else /* vertical smoothing */ + else /* vertical smoothing */ { - unsigned i; /* line counter */ - word_t *img1; /* pointer to left or upper line */ - word_t *img2; /* pointer to right or lower line */ - - img1 = bptr + wfa->y [state][1] * img_width + wfa->x [state][1] - 1; - img2 = bptr + wfa->y [state][1] * img_width + wfa->x [state][1]; - - for (i = min (height, img_height - wfa->y [state][1]); i; - i--, img1 += img_width, img2 += img_width) - { - int tmp = *img1; - + unsigned i; /* line counter */ + word_t *img1; /* pointer to left or upper line */ + word_t *img2; /* pointer to right or lower line */ + + img1 = bptr + wfa->y [state][1] * img_width + wfa->x [state][1] - 1; + img2 = bptr + wfa->y [state][1] * img_width + wfa->x [state][1]; + + for (i = MIN(height, img_height - wfa->y [state][1]); i; + i--, img1 += img_width, img2 += img_width) + { + int tmp = *img1; + #ifdef HAVE_SIGNED_SHIFT - *img1 = (((is * tmp) >> 10) << 1) - + (((inegs * (int) *img2) >> 10) << 1); - *img2 = (((is * (int) *img2) >> 10) << 1) - + (((inegs * tmp) >> 10) << 1); + *img1 = (((is * tmp) >> 10) << 1) + + (((inegs * (int) *img2) >> 10) << 1); + *img2 = (((is * (int) *img2) >> 10) << 1) + + (((inegs * tmp) >> 10) << 1); #else /* not HAVE_SIGNED_SHIFT */ - *img1 = (((is * tmp) / 1024) * 2) - + (((inegs * (int) *img2) / 1024) * 2); - *img2 = (((is * (int) *img2) / 1024) * 2) - + (((inegs * tmp) / 1024) *2); + *img1 = (((is * tmp) / 1024) * 2) + + (((inegs * (int) *img2) / 1024) * 2); + *img2 = (((is * (int) *img2) / 1024) * 2) + + (((inegs * tmp) / 1024) *2); #endif /* not HAVE_SIGNED_SHIFT */ - } + } } } } /***************************************************************************** - private code + private code *****************************************************************************/ static void enlarge_image (int enlarge_factor, format_e format, unsigned y_root, - wfa_t *wfa) + wfa_t *wfa) /* * Enlarge or reduce size of state images by factor 2^'enlarge_factor'. * Use 4:2:0 subsampling if specified by 'format', else use 4:4:4 format. @@ -788,8 +787,8 @@ enlarge_image (int enlarge_factor, format_e format, unsigned y_root, * No return value. * * Side effects: - * coordinates of ranges and motion blocks in the WFA structure 'wfa' - * are modified. + * coordinates of ranges and motion blocks in the WFA structure 'wfa' + * are modified. */ { @@ -799,53 +798,53 @@ enlarge_image (int enlarge_factor, format_e format, unsigned y_root, if (enlarge_factor == 0) { - state = y_root + 1; - enlarge_factor = -1; + state = y_root + 1; + enlarge_factor = -1; } else - state = wfa->basis_states; + state = wfa->basis_states; for (; state < wfa->states; state++) { - unsigned label, n; - - wfa->level_of_state [state] - = max (wfa->level_of_state [state] + enlarge_factor * 2, 0); - - for (label = 0; label < MAXLABELS; label++) - if (enlarge_factor > 0) - { - wfa->x [state][label] <<= enlarge_factor; - wfa->y [state][label] <<= enlarge_factor; - for (n = enlarge_factor; n; n--) - { - wfa->mv_tree [state][label].fx *= 2; - wfa->mv_tree [state][label].fy *= 2; - wfa->mv_tree [state][label].bx *= 2; - wfa->mv_tree [state][label].by *= 2; - } - } - else /* enlarge_factor < 0 */ - { - wfa->x [state][label] >>= - enlarge_factor; - wfa->y [state][label] >>= - enlarge_factor; - for (n = - enlarge_factor; n; n--) - { - wfa->mv_tree [state][label].fx /= 2; - wfa->mv_tree [state][label].fy /= 2; - wfa->mv_tree [state][label].bx /= 2; - wfa->mv_tree [state][label].by /= 2; - } - } - if (format == FORMAT_4_2_0 && state == y_root) - enlarge_factor--; + unsigned label, n; + + wfa->level_of_state [state] + = MAX(wfa->level_of_state [state] + enlarge_factor * 2, 0); + + for (label = 0; label < MAXLABELS; label++) + if (enlarge_factor > 0) + { + wfa->x [state][label] <<= enlarge_factor; + wfa->y [state][label] <<= enlarge_factor; + for (n = enlarge_factor; n; n--) + { + wfa->mv_tree [state][label].fx *= 2; + wfa->mv_tree [state][label].fy *= 2; + wfa->mv_tree [state][label].bx *= 2; + wfa->mv_tree [state][label].by *= 2; + } + } + else /* enlarge_factor < 0 */ + { + wfa->x [state][label] >>= - enlarge_factor; + wfa->y [state][label] >>= - enlarge_factor; + for (n = - enlarge_factor; n; n--) + { + wfa->mv_tree [state][label].fx /= 2; + wfa->mv_tree [state][label].fy /= 2; + wfa->mv_tree [state][label].bx /= 2; + wfa->mv_tree [state][label].by /= 2; + } + } + if (format == FORMAT_4_2_0 && state == y_root) + enlarge_factor--; } } } static void compute_actual_size (unsigned luminance_root, - unsigned *width, unsigned *height, const wfa_t *wfa) + unsigned *width, unsigned *height, const wfa_t *wfa) /* * Compute actual size of the frame represented by the given 'wfa'. * (The reconstructed frame may get larger than the original due @@ -853,24 +852,24 @@ compute_actual_size (unsigned luminance_root, * If 'luminance_root' < MAXSTATES then the size of chroma ranges (4:2:0). * * Return values: - * actual 'width' and 'height' of the decoded frame. + * actual 'width' and 'height' of the decoded frame. */ { - unsigned x = 0, y = 0; /* maximum coordinates */ - unsigned state; /* counter */ + unsigned x = 0, y = 0; /* maximum coordinates */ + unsigned state; /* counter */ for (state = wfa->basis_states; state < wfa->states; state++) if (isedge (wfa->into [state][0][0]) || isedge (wfa->into [state][1][0])) { - unsigned mult = state > luminance_root ? 2 : 1; - - x = max ((wfa->x [state][0] - + width_of_level (wfa->level_of_state [state])) * mult, x); - y = max ((wfa->y [state][0] - + height_of_level (wfa->level_of_state [state])) * mult, y); + unsigned mult = state > luminance_root ? 2 : 1; + + x = MAX((wfa->x [state][0] + + width_of_level (wfa->level_of_state [state])) * mult, x); + y = MAX((wfa->y [state][0] + + height_of_level (wfa->level_of_state [state])) * mult, y); } - if (x & 1) /* ensure that image size is even */ + if (x & 1) /* ensure that image size is even */ x++; if (y & 1) y++; @@ -880,8 +879,8 @@ compute_actual_size (unsigned luminance_root, static void alloc_state_images (word_t ***images, u_word_t **offsets, const image_t *frame, - const unsigned *root_state, unsigned range_state, - unsigned max_level, format_e format, const wfa_t *wfa) + const unsigned *root_state, unsigned range_state, + unsigned max_level, format_e format, const wfa_t *wfa) /* * Generate list of 'wfa' state images which have to be computed for * each level to obtain the decoded 'frame'. 'root_state[]' denotes the @@ -893,24 +892,24 @@ alloc_state_images (word_t ***images, u_word_t **offsets, const image_t *frame, * image of 'wfa->root_state'. * * Return values: - * '*images' Pointer to array of state image pointers - * '*offsets' Pointer to array of state image offsets. + * '*images' Pointer to array of state image pointers + * '*offsets' Pointer to array of state image offsets. * * Side effects: - * The arrays given above are filled with useful values. + * The arrays given above are filled with useful values. */ { - word_t **simg; /* ptr to list of state image ptr's */ - u_word_t *offs; /* ptr to list of offsets */ - unsigned level; /* counter */ + word_t **simg; /* ptr to list of state image ptr's */ + u_word_t *offs; /* ptr to list of offsets */ + unsigned level; /* counter */ - simg = Calloc (wfa->states * (max_level + 1), sizeof (word_t *)); - offs = Calloc (wfa->states * (max_level + 1), sizeof (u_word_t)); + simg = Calloc (wfa->states * (max_level + 1), sizeof (word_t *)); + offs = Calloc (wfa->states * (max_level + 1), sizeof (u_word_t)); /* * Initialize buffers for those state images which are at 'max_level'. */ - if (range_state > 0) /* a range is given */ + if (range_state > 0) /* a range is given */ { simg [range_state + max_level * wfa->states] = frame->pixels [GRAY]; offs [range_state + max_level * wfa->states] = frame->width; @@ -920,25 +919,25 @@ alloc_state_images (word_t ***images, u_word_t **offsets, const image_t *frame, unsigned state; for (state = wfa->basis_states; state <= root_state [Y]; state++) - if (wfa->level_of_state [state] == max_level) - { - simg [state + max_level * wfa->states] - = (frame->pixels [Y] + wfa->y [state][0] * frame->width - + wfa->x [state][0]); - offs [state + max_level * wfa->states] = frame->width; - } + if (wfa->level_of_state [state] == max_level) + { + simg [state + max_level * wfa->states] + = (frame->pixels [Y] + wfa->y [state][0] * frame->width + + wfa->x [state][0]); + offs [state + max_level * wfa->states] = frame->width; + } if (frame->color) { - unsigned width = format == FORMAT_4_2_0 ? - (frame->width >> 1) : frame->width; - for (; state < wfa->states; state++) - if (wfa->level_of_state [state] == max_level) - { - simg [state + max_level * wfa->states] - = (frame->pixels [state > root_state [Cb] ? Cr : Cb] - + wfa->y [state][0] * width + wfa->x [state][0]); - offs [state + max_level * wfa->states] = width; - } + unsigned width = format == FORMAT_4_2_0 ? + (frame->width >> 1) : frame->width; + for (; state < wfa->states; state++) + if (wfa->level_of_state [state] == max_level) + { + simg [state + max_level * wfa->states] + = (frame->pixels [state > root_state [Cb] ? Cr : Cb] + + wfa->y [state][0] * width + wfa->x [state][0]); + offs [state + max_level * wfa->states] = width; + } } } @@ -954,63 +953,63 @@ alloc_state_images (word_t ***images, u_word_t **offsets, const image_t *frame, * Range approximation with child. */ for (state = 1; state < (range_state > 0 ? - range_state + 1 : wfa->states); state++) - if (simg [state + level * wfa->states]) - for (label = 0; label < MAXLABELS; label++) - if (ischild (child = wfa->tree[state][label])) - { - if (isedge (wfa->into[state][label][0])) - { - /* - * Allocate new image block. - */ - simg [child + (level - 1) * wfa->states] - = Calloc (size_of_level (level - 1), sizeof (word_t)); - offs [child + (level - 1) * wfa->states] - = width_of_level (level - 1); - } - else - { - /* - * Use image block and offset of parent. - */ - if (level & 1) /* split vertically */ - { - simg [child + (level - 1) * wfa->states] - = (simg [state + level * wfa->states] - + label * (height_of_level (level - 1) - * offs [state - + level * wfa->states])); - } - else /* split horizontally */ - { - simg [child + (level - 1) * wfa->states] - = (simg [state + level * wfa->states] - + label * width_of_level (level - 1)); - } - offs [child + (level - 1) * wfa->states] - = offs [state + level * wfa->states]; - } - } + range_state + 1 : wfa->states); state++) + if (simg [state + level * wfa->states]) + for (label = 0; label < MAXLABELS; label++) + if (ischild (child = wfa->tree[state][label])) + { + if (isedge (wfa->into[state][label][0])) + { + /* + * Allocate new image block. + */ + simg [child + (level - 1) * wfa->states] + = Calloc (size_of_level (level - 1), sizeof (word_t)); + offs [child + (level - 1) * wfa->states] + = width_of_level (level - 1); + } + else + { + /* + * Use image block and offset of parent. + */ + if (level & 1) /* split vertically */ + { + simg [child + (level - 1) * wfa->states] + = (simg [state + level * wfa->states] + + label * (height_of_level (level - 1) + * offs [state + + level * wfa->states])); + } + else /* split horizontally */ + { + simg [child + (level - 1) * wfa->states] + = (simg [state + level * wfa->states] + + label * width_of_level (level - 1)); + } + offs [child + (level - 1) * wfa->states] + = offs [state + level * wfa->states]; + } + } /* * Range approximation with linear combination */ for (state = 1; state < (range_state > 0 ? - range_state + 1 : wfa->states); state++) - if (simg [state + level * wfa->states]) - for (label = 0; label < MAXLABELS; label++) - for (edge = 0; isedge (domain = wfa->into[state][label][edge]); - edge++) - { - if (domain > 0 /* don't allocate memory for state 0 */ - && !simg [domain + (level - 1) * wfa->states]) - { - simg [domain + (level - 1) * wfa->states] - = Calloc (size_of_level (level - 1), sizeof (word_t)); - offs [domain + (level - 1) * wfa->states] - = width_of_level (level - 1); - } - } + range_state + 1 : wfa->states); state++) + if (simg [state + level * wfa->states]) + for (label = 0; label < MAXLABELS; label++) + for (edge = 0; isedge (domain = wfa->into[state][label][edge]); + edge++) + { + if (domain > 0 /* don't allocate memory for state 0 */ + && !simg [domain + (level - 1) * wfa->states]) + { + simg [domain + (level - 1) * wfa->states] + = Calloc (size_of_level (level - 1), sizeof (word_t)); + offs [domain + (level - 1) * wfa->states] + = width_of_level (level - 1); + } + } } @@ -1020,8 +1019,8 @@ alloc_state_images (word_t ***images, u_word_t **offsets, const image_t *frame, static void free_state_images (unsigned max_level, bool_t color, word_t **state_image, - u_word_t *offset, const unsigned *root_state, - unsigned range_state, format_e format, const wfa_t *wfa) + u_word_t *offset, const unsigned *root_state, + unsigned range_state, format_e format, const wfa_t *wfa) /* * Free memory of state images. * For more details refer to the inverse function 'alloc_state_images()'. @@ -1029,10 +1028,10 @@ free_state_images (unsigned max_level, bool_t color, word_t **state_image, * No return value. * * Side effects: - * arrays 'state_image' and 'offset' are discarded. + * arrays 'state_image' and 'offset' are discarded. */ { - word_t marker; /* ptr is required as a marker */ + word_t marker; /* ptr is required as a marker */ unsigned level; if (range_state > 0) @@ -1047,19 +1046,19 @@ free_state_images (unsigned max_level, bool_t color, word_t **state_image, * Initialize state image array with states at 'max_level' */ for (state = wfa->basis_states; state <= root_state [Y]; state++) - if (wfa->level_of_state [state] == max_level) - state_image [state + max_level * wfa->states] = ▮ + if (wfa->level_of_state [state] == max_level) + state_image [state + max_level * wfa->states] = ▮ if (color) { - if (format == FORMAT_4_2_0) - level = max_level - 2; - else - level = max_level; + if (format == FORMAT_4_2_0) + level = max_level - 2; + else + level = max_level; - for (; state < wfa->states; state++) - if (wfa->level_of_state [state] == level) - state_image [state + level * wfa->states] = ▮ + for (; state < wfa->states; state++) + if (wfa->level_of_state [state] == level) + state_image [state + level * wfa->states] = ▮ } } @@ -1071,37 +1070,37 @@ free_state_images (unsigned max_level, bool_t color, word_t **state_image, * Range approximation with child. */ for (state = 1; state < (range_state > 0 ? - range_state + 1 : wfa->states); state++) - if (state_image [state + level * wfa->states]) - for (label = 0; label < MAXLABELS; label++) - if (ischild (child = wfa->tree[state][label])) - { - if (isedge (wfa->into[state][label][0]) - && (state_image [child + (level - 1) * wfa->states] - != &marker)) - Free (state_image [child + (level - 1) * wfa->states]); - state_image [child + (level - 1) * wfa->states] = ▮ - } + range_state + 1 : wfa->states); state++) + if (state_image [state + level * wfa->states]) + for (label = 0; label < MAXLABELS; label++) + if (ischild (child = wfa->tree[state][label])) + { + if (isedge (wfa->into[state][label][0]) + && (state_image [child + (level - 1) * wfa->states] + != &marker)) + Free (state_image [child + (level - 1) * wfa->states]); + state_image [child + (level - 1) * wfa->states] = ▮ + } /* * Range approximation with linear combination */ for (state = 1; state < (range_state > 0 ? - range_state + 1 : wfa->states); - state++) - if (state_image [state + level * wfa->states]) - for (label = 0; label < MAXLABELS; label++) - for (edge = 0; isedge (domain = wfa->into[state][label][edge]); - edge++) - if (domain > 0 - && (state_image [domain + (level - 1) * wfa->states] - != NULL) - && (state_image [domain + (level - 1) * wfa->states] - != &marker)) - { - Free (state_image [domain + (level - 1) * wfa->states]); - state_image [domain + (level - 1) * wfa->states] - = ▮ - } + range_state + 1 : wfa->states); + state++) + if (state_image [state + level * wfa->states]) + for (label = 0; label < MAXLABELS; label++) + for (edge = 0; isedge (domain = wfa->into[state][label][edge]); + edge++) + if (domain > 0 + && (state_image [domain + (level - 1) * wfa->states] + != NULL) + && (state_image [domain + (level - 1) * wfa->states] + != &marker)) + { + Free (state_image [domain + (level - 1) * wfa->states]); + state_image [domain + (level - 1) * wfa->states] + = ▮ + } } Free (state_image); Free (offset); @@ -1109,7 +1108,7 @@ free_state_images (unsigned max_level, bool_t color, word_t **state_image, static void compute_state_images (unsigned max_level, word_t **simg, - const u_word_t *offset, const wfa_t *wfa) + const u_word_t *offset, const wfa_t *wfa) /* * Compute all state images of the 'wfa' at level {1, ... , 'max_level'} * which are marked in the array 'simg' (offsets of state images @@ -1121,8 +1120,8 @@ compute_state_images (unsigned max_level, word_t **simg, * No return value. * * Side effects: - * state images (given by pointers in the array 'state_image') - * are computed. + * state images (given by pointers in the array 'state_image') + * are computed. */ { unsigned level, state; @@ -1132,8 +1131,8 @@ compute_state_images (unsigned max_level, word_t **simg, */ for (state = 1; state < wfa->states; state++) - if (simg [state] != NULL) /* compute image at level 0 */ - *simg [state] = (int) (wfa->final_distribution[state] * 8 + .5) * 2; + if (simg [state] != NULL) /* compute image at level 0 */ + *simg [state] = (int) (wfa->final_distribution[state] * 8 + .5) * 2; /* * Compute images of states @@ -1153,351 +1152,351 @@ compute_state_images (unsigned max_level, word_t **simg, unsigned height = height_of_level (level - 1); for (state = 1; state < wfa->states; state++) - if (simg [state + level * wfa->states] != NULL) - for (label = 0; label < MAXLABELS; label++) - if (isedge (wfa->into [state][label][0])) - { - unsigned edge; - int domain; - word_t *range; /* address of current range */ - bool_t prediction_used; /* ND prediction found ? */ - - /* - * Compute address of range image - */ - if (level & 1) /* split vertically */ - { - range = simg [state + level * wfa->states] - + label * (height_of_level (level - 1) - * offset [state - + level * wfa->states]); - } - else /* split horizontally */ - { - range = simg [state + level * wfa->states] - + label * width_of_level (level - 1); - } - - /* - * Generate the state images by adding the corresponding - * weighted state images: - * subimage [label] = - * weight_1 * image_1 + ... + weight_n * image_n - */ - if (!ischild (domain = wfa->tree[state][label])) - prediction_used = NO; - else - { - unsigned y; - word_t *src; - word_t *dst; - unsigned src_offset; - unsigned dst_offset; - - prediction_used = YES; - /* - * Copy child image - */ - src = simg [domain + (level - 1) * wfa->states]; - src_offset = offset [domain + (level - 1) * wfa->states] ; - dst = range; - dst_offset = offset [state + level * wfa->states]; - for (y = height; y; y--) - { - memcpy (dst, src, width * sizeof (word_t)); - src += src_offset; - dst += dst_offset; - } - } - - if (!prediction_used - && isedge (domain = wfa->into[state][label][0])) - { - /* - * If prediction is not used then the range is - * filled with the first domain. No addition is needed. - */ - edge = 0; - if (domain != 0) - { - int weight; - word_t *src; - unsigned src_offset; - - src = simg [domain + ((level - 1) - * wfa->states)]; - src_offset = offset [domain + ((level - 1) - * wfa->states)] - width; - weight = wfa->int_weight [state][label][edge]; - - if (width == 1) /* can't add two-pixels in a row */ - { - word_t *dst; - unsigned dst_offset; - - dst = range; - dst_offset = offset [state + level * wfa->states] - - width; + if (simg [state + level * wfa->states] != NULL) + for (label = 0; label < MAXLABELS; label++) + if (isedge (wfa->into [state][label][0])) + { + unsigned edge; + int domain; + word_t *range; /* address of current range */ + bool_t prediction_used; /* ND prediction found ? */ + + /* + * Compute address of range image + */ + if (level & 1) /* split vertically */ + { + range = simg [state + level * wfa->states] + + label * (height_of_level (level - 1) + * offset [state + + level * wfa->states]); + } + else /* split horizontally */ + { + range = simg [state + level * wfa->states] + + label * width_of_level (level - 1); + } + + /* + * Generate the state images by adding the corresponding + * weighted state images: + * subimage [label] = + * weight_1 * image_1 + ... + weight_n * image_n + */ + if (!ischild (domain = wfa->tree[state][label])) + prediction_used = NO; + else + { + unsigned y; + word_t *src; + word_t *dst; + unsigned src_offset; + unsigned dst_offset; + + prediction_used = YES; + /* + * Copy child image + */ + src = simg [domain + (level - 1) * wfa->states]; + src_offset = offset [domain + (level - 1) * wfa->states] ; + dst = range; + dst_offset = offset [state + level * wfa->states]; + for (y = height; y; y--) + { + memcpy (dst, src, width * sizeof (word_t)); + src += src_offset; + dst += dst_offset; + } + } + + if (!prediction_used + && isedge (domain = wfa->into[state][label][0])) + { + /* + * If prediction is not used then the range is + * filled with the first domain. No addition is needed. + */ + edge = 0; + if (domain != 0) + { + int weight; + word_t *src; + unsigned src_offset; + + src = simg [domain + ((level - 1) + * wfa->states)]; + src_offset = offset [domain + ((level - 1) + * wfa->states)] - width; + weight = wfa->int_weight [state][label][edge]; + + if (width == 1) /* can't add two-pixels in a row */ + { + word_t *dst; + unsigned dst_offset; + + dst = range; + dst_offset = offset [state + level * wfa->states] + - width; #ifdef HAVE_SIGNED_SHIFT - *dst++ = ((weight * (int) *src++) >> 10) << 1; -#else /* not HAVE_SIGNED_SHIFT */ - *dst++ = ((weight * (int) *src++) / 1024) * 2; + *dst++ = ((weight * (int) *src++) >> 10) << 1; +#else /* not HAVE_SIGNED_SHIFT */ + *dst++ = ((weight * (int) *src++) / 1024) * 2; #endif /* not HAVE_SIGNED_SHIFT */ - if (height == 2) - { - src += src_offset; - dst += dst_offset; + if (height == 2) + { + src += src_offset; + dst += dst_offset; #ifdef HAVE_SIGNED_SHIFT - *dst++ = ((weight * (int) *src++) >> 10) << 1; + *dst++ = ((weight * (int) *src++) >> 10) << 1; #else /* not HAVE_SIGNED_SHIFT */ - *dst++ = ((weight * (int) *src++) / 1024) * 2; + *dst++ = ((weight * (int) *src++) / 1024) * 2; #endif /* not HAVE_SIGNED_SHIFT */ - } - } - else - { - unsigned y; - int *idst; - unsigned idst_offset; - - idst = (int *) range; - idst_offset = (offset [state + level * wfa->states] - - width) / 2; - for (y = height; y; y--) - { - int *comp_dst = idst + (width >> 1); - - for (; idst != comp_dst; ) - { - int tmp; /* temp. value of adjacent pixels */ + } + } + else + { + unsigned y; + int *idst; + unsigned idst_offset; + + idst = (int *) range; + idst_offset = (offset [state + level * wfa->states] + - width) / 2; + for (y = height; y; y--) + { + int *comp_dst = idst + (width >> 1); + + for (; idst != comp_dst; ) + { + int tmp; /* temp. value of adjacent pixels */ #ifdef HAVE_SIGNED_SHIFT -# if BYTE_ORDER == LITTLE_ENDIAN - tmp = (((weight * (int) src [1]) >> 10) << 17) - | (((weight * (int) src [0]) >> 9) - & 0xfffe); -# else - tmp = (((weight * (int) src [0]) >> 10) << 17) - | (((weight * (int) src [1]) >> 9) - & 0xfffe); -# endif +# if BYTE_ORDER == LITTLE_ENDIAN + tmp = (((weight * (int) src [1]) >> 10) << 17) + | (((weight * (int) src [0]) >> 9) + & 0xfffe); +# else + tmp = (((weight * (int) src [0]) >> 10) << 17) + | (((weight * (int) src [1]) >> 9) + & 0xfffe); +# endif #else /* not HAVE_SIGNED_SHIFT */ -# if BYTE_ORDER == LITTLE_ENDIAN - tmp = (((weight * (int) src [1]) / 1024) - * 131072) - | (((weight * (int) src [0])/ 512) - & 0xfffe); -# else - tmp = (((weight * (int) src [0]) / 1024) - * 131072) - | (((weight * (int) src [1]) / 512) - & 0xfffe); -# endif /* not WORDS_BIGENDIAN */ -#endif - src += 2; - *idst++ = tmp & 0xfffefffe; - } - src += src_offset; - idst += idst_offset; - } - } - } - else - { - int weight = (int) (wfa->weight[state][label][edge] - * wfa->final_distribution[0] - * 8 + .5) * 2; - /* - * Range needs domain 0 - * (the constant function f(x, y) = 1), - * hence a faster algorithm is used. - */ - if (width == 1) /* can't add two-pixels in a row */ - { - word_t *dst; - unsigned dst_offset; - - dst = range; - dst_offset = offset [state + level * wfa->states] - - width; - - *dst++ = weight; - if (height == 2) - { - dst += dst_offset; - *dst++ = weight; - } - } - else - { - unsigned x, y; - int *idst; - unsigned idst_offset; - - weight = (weight * 65536) | (weight & 0xffff); - idst = (int *) range; - idst_offset = offset [state + level * wfa->states] - / 2; - for (x = width >> 1; x; x--) - *idst++ = weight & 0xfffefffe; - idst += (offset [state + level * wfa->states] - - width) / 2; - - for (y = height - 1; y; y--) - { - memcpy (idst, idst - idst_offset, - width * sizeof (word_t)); - idst += idst_offset; - } - } - } - edge = 1; - } - else - edge = 0; - - /* - * Add remaining weighted domain images to current range - */ - for (; isedge (domain = wfa->into[state][label][edge]); - edge++) - { - if (domain != 0) - { - word_t *src; - unsigned src_offset; - int weight; - - src = simg [domain + (level - 1) * wfa->states]; - src_offset = offset [domain + ((level - 1) - * wfa->states)] - width; - weight = wfa->int_weight [state][label][edge]; - - if (width == 1) /* can't add two-pixels in a row */ - { - word_t *dst; - unsigned dst_offset; - - dst = range; - dst_offset = offset [state + level * wfa->states] - - width; +# if BYTE_ORDER == LITTLE_ENDIAN + tmp = (((weight * (int) src [1]) / 1024) + * 131072) + | (((weight * (int) src [0])/ 512) + & 0xfffe); +# else + tmp = (((weight * (int) src [0]) / 1024) + * 131072) + | (((weight * (int) src [1]) / 512) + & 0xfffe); +# endif +#endif /* not HAVE_SIGNED_SHIFT */ + src += 2; + *idst++ = tmp & 0xfffefffe; + } + src += src_offset; + idst += idst_offset; + } + } + } + else + { + int weight = (int) (wfa->weight[state][label][edge] + * wfa->final_distribution[0] + * 8 + .5) * 2; + /* + * Range needs domain 0 + * (the constant function f(x, y) = 1), + * hence a faster algorithm is used. + */ + if (width == 1) /* can't add two-pixels in a row */ + { + word_t *dst; + unsigned dst_offset; + + dst = range; + dst_offset = offset [state + level * wfa->states] + - width; + + *dst++ = weight; + if (height == 2) + { + dst += dst_offset; + *dst++ = weight; + } + } + else + { + unsigned x, y; + int *idst; + unsigned idst_offset; + + weight = (weight * 65536) | (weight & 0xffff); + idst = (int *) range; + idst_offset = offset [state + level * wfa->states] + / 2; + for (x = width >> 1; x; x--) + *idst++ = weight & 0xfffefffe; + idst += (offset [state + level * wfa->states] + - width) / 2; + + for (y = height - 1; y; y--) + { + memcpy (idst, idst - idst_offset, + width * sizeof (word_t)); + idst += idst_offset; + } + } + } + edge = 1; + } + else + edge = 0; + + /* + * Add remaining weighted domain images to current range + */ + for (; isedge (domain = wfa->into[state][label][edge]); + edge++) + { + if (domain != 0) + { + word_t *src; + unsigned src_offset; + int weight; + + src = simg [domain + (level - 1) * wfa->states]; + src_offset = offset [domain + ((level - 1) + * wfa->states)] - width; + weight = wfa->int_weight [state][label][edge]; + + if (width == 1) /* can't add two-pixels in a row */ + { + word_t *dst; + unsigned dst_offset; + + dst = range; + dst_offset = offset [state + level * wfa->states] + - width; #ifdef HAVE_SIGNED_SHIFT - *dst++ += ((weight * (int) *src++) >> 10) << 1; + *dst++ += ((weight * (int) *src++) >> 10) << 1; #else /* not HAVE_SIGNED_SHIFT */ - *dst++ += ((weight * (int) *src++) / 1024) * 2; + *dst++ += ((weight * (int) *src++) / 1024) * 2; #endif /* not HAVE_SIGNED_SHIFT */ - if (height == 2) - { - src += src_offset; - dst += dst_offset; + if (height == 2) + { + src += src_offset; + dst += dst_offset; #ifdef HAVE_SIGNED_SHIFT - *dst++ += ((weight * (int) *src++) >> 10) << 1; + *dst++ += ((weight * (int) *src++) >> 10) << 1; #else /* not HAVE_SIGNED_SHIFT */ - *dst++ += ((weight * (int) *src++) / 1024) * 2; + *dst++ += ((weight * (int) *src++) / 1024) * 2; #endif /* not HAVE_SIGNED_SHIFT */ - } - } - else - { - int *idst; - unsigned idst_offset; - unsigned y; - - idst = (int *) range; - idst_offset = (offset [state + level * wfa->states] - - width) / 2; - - for (y = height; y; y--) - { - int *comp_dst = idst + (width >> 1); - - for (; idst != comp_dst;) - { - int tmp; /* temp. value of adjacent pixels */ + } + } + else + { + int *idst; + unsigned idst_offset; + unsigned y; + + idst = (int *) range; + idst_offset = (offset [state + level * wfa->states] + - width) / 2; + + for (y = height; y; y--) + { + int *comp_dst = idst + (width >> 1); + + for (; idst != comp_dst;) + { + int tmp; /* temp. value of adjacent pixels */ #ifdef HAVE_SIGNED_SHIFT -# if BYTE_ORDER == LITTLE_ENDIAN - tmp = (((weight * (int) src [1]) >> 10) << 17) - | (((weight * (int) src [0]) >> 9) - & 0xfffe); -# else - tmp = (((weight * (int)src [0]) >> 10) << 17) - | (((weight * (int)src [1]) >> 9) - & 0xfffe); -# endif +# if BYTE_ORDER == LITTLE_ENDIAN + tmp = (((weight * (int) src [1]) >> 10) << 17) + | (((weight * (int) src [0]) >> 9) + & 0xfffe); +# else + tmp = (((weight * (int)src [0]) >> 10) << 17) + | (((weight * (int)src [1]) >> 9) + & 0xfffe); +# endif #else /* not HAVE_SIGNED_SHIFT */ -# if BYTE_ORDER == LITTLE_ENDIAN - tmp = (((weight * (int) src [1]) / 1024) - * 131072) - | (((weight * (int) src [0])/ 512) - & 0xfffe); -# else - tmp = (((weight * (int) src [0]) / 1024) - * 131072) - | (((weight * (int) src [1])/ 512) - & 0xfffe); -# endif /* not WORDS_BIGENDIAN */ -#endif - src += 2; - *idst = (*idst + tmp) & 0xfffefffe; - idst++; - } - src += src_offset; - idst += idst_offset; - } - } - } - else - { - int weight = (int) (wfa->weight[state][label][edge] - * wfa->final_distribution[0] - * 8 + .5) * 2; - /* - * Range needs domain 0 - * (the constant function f(x, y) = 1), - * hence a faster algorithm is used. - */ - if (width == 1) /* can't add two-pixels in a row */ - { - word_t *dst; - unsigned dst_offset; - - dst = range; - dst_offset = offset [state + level * wfa->states] - - width; - - *dst++ += weight; - if (height == 2) - { - dst += dst_offset; - *dst++ += weight; - } - } - else - { - int *idst; - unsigned idst_offset; - unsigned y; - - weight = (weight * 65536) | (weight & 0xffff); - idst = (int *) range; - idst_offset = (offset [state + level * wfa->states] - - width) /2; - - for (y = height; y; y--) - { - int *comp_dst = idst + (width >> 1); - - for (; idst != comp_dst; ) - { - *idst = (*idst + weight) & 0xfffefffe; +# if BYTE_ORDER == LITTLE_ENDIAN + tmp = (((weight * (int) src [1]) / 1024) + * 131072) + | (((weight * (int) src [0])/ 512) + & 0xfffe); +# else + tmp = (((weight * (int) src [0]) / 1024) + * 131072) + | (((weight * (int) src [1])/ 512) + & 0xfffe); +# endif +#endif /* not HAVE_SIGNED_SHIFT */ + src += 2; + *idst = (*idst + tmp) & 0xfffefffe; + idst++; + } + src += src_offset; + idst += idst_offset; + } + } + } + else + { + int weight = (int) (wfa->weight[state][label][edge] + * wfa->final_distribution[0] + * 8 + .5) * 2; + /* + * Range needs domain 0 + * (the constant function f(x, y) = 1), + * hence a faster algorithm is used. + */ + if (width == 1) /* can't add two-pixels in a row */ + { + word_t *dst; + unsigned dst_offset; + + dst = range; + dst_offset = offset [state + level * wfa->states] + - width; + + *dst++ += weight; + if (height == 2) + { + dst += dst_offset; + *dst++ += weight; + } + } + else + { + int *idst; + unsigned idst_offset; + unsigned y; + + weight = (weight * 65536) | (weight & 0xffff); + idst = (int *) range; + idst_offset = (offset [state + level * wfa->states] + - width) /2; + + for (y = height; y; y--) + { + int *comp_dst = idst + (width >> 1); + + for (; idst != comp_dst; ) + { + *idst = (*idst + weight) & 0xfffefffe; idst++; - } - idst += idst_offset; - } - } - } - } - } + } + idst += idst_offset; + } + } + } + } + } } } @@ -1509,24 +1508,24 @@ duplicate_state_image (const word_t *domain, unsigned offset, unsigned level) * to the lock 'pixels'. * * Return value: - * pointer to the new domain block + * pointer to the new domain block */ { word_t *dst, *pixels; - int y, n; + int y, n; dst = pixels = Calloc (size_of_level (level), sizeof (word_t)); if (domain) for (y = height_of_level (level); y; y--) { - memcpy (dst, domain, width_of_level (level) * sizeof (word_t)); - dst += width_of_level (level); - domain += offset; + memcpy (dst, domain, width_of_level (level) * sizeof (word_t)); + dst += width_of_level (level); + domain += offset; } - else /* state 0 */ + else /* state 0 */ for (n = size_of_level (level); n; n--) - *dst++ = (int) (128 * 8 + .5) * 2; + *dst++ = (int) (128 * 8 + .5) * 2; return pixels; } diff --git a/converter/other/fiasco/codec/dfiasco.c b/converter/other/fiasco/codec/dfiasco.c index 1cdfc672..2fdec573 100644 --- a/converter/other/fiasco/codec/dfiasco.c +++ b/converter/other/fiasco/codec/dfiasco.c @@ -14,8 +14,12 @@ * $State: Exp $ */ +#include #include +#include "pm_c_util.h" +#include "nstring.h" + #include "config.h" #include "types.h" @@ -112,7 +116,7 @@ fiasco_decoder_new (const char *filename, const fiasco_d_options_t *options) { set_error (_("Magnifaction factor `%d' is too large. " "Maximium value is %d."), - dfiasco->enlarge_factor, max (0, n - 1)); + dfiasco->enlarge_factor, MAX(0, n - 1)); fiasco_decoder_delete (decoder); return NULL; } @@ -129,7 +133,7 @@ fiasco_decoder_new (const char *filename, const fiasco_d_options_t *options) { set_error (_("Magnifaction factor `%d' is too small. " "Minimum value is %d."), - dfiasco->enlarge_factor, - max (0, n - 1)); + dfiasco->enlarge_factor, - MAX(0, n - 1)); fiasco_decoder_delete (decoder); return NULL; } diff --git a/converter/other/fiasco/codec/domain-pool.c b/converter/other/fiasco/codec/domain-pool.c index 09f854a6..7cc3900e 100644 --- a/converter/other/fiasco/codec/domain-pool.c +++ b/converter/other/fiasco/codec/domain-pool.c @@ -17,16 +17,10 @@ #include "config.h" #include +#include +#include -#if STDC_HEADERS -# include -#endif /* not STDC_HEADERS */ - -#if HAVE_STRING_H -# include -#else /* not HAVE_STRING_H */ -# include -#endif /* not HAVE_STRING_H */ +#include "pm_c_util.h" #include "types.h" #include "macros.h" @@ -466,7 +460,7 @@ qac_chroma (unsigned max_domains, const wfa_t *wfa, void *model) max_domains, wfa); for (n = 0; n < max_domains && domains [n] >= 0; n++) states [n] = domains [n]; - max_domains = min (max_domains, n); + max_domains = MIN(max_domains, n); Free (domains); for (old = 0, new = 0; new < max_domains && old < qac_model->n; old++) @@ -854,7 +848,7 @@ rle_chroma (unsigned max_domains, const wfa_t *wfa, void *model) states [n] = domains [n]; assert (states [0] == 0); - max_domains = min (max_domains, n); + max_domains = MIN(max_domains, n); Free (domains); Free (rle_model->states); diff --git a/converter/other/fiasco/codec/ip.c b/converter/other/fiasco/codec/ip.c index caa97baf..ade0d916 100644 --- a/converter/other/fiasco/codec/ip.c +++ b/converter/other/fiasco/codec/ip.c @@ -282,7 +282,7 @@ standard_ip_image_state (unsigned address, unsigned level, unsigned domain, real_t ip = 0, *imageptr, *stateptr; if (level > c->options.images_level) - error ("Level %d not supported.", level); + error ("We cannot interpret a Level %d image.", level); imageptr = &c->pixels [address * size_of_level (level)]; @@ -311,7 +311,7 @@ standard_ip_state_state (unsigned domain1, unsigned domain2, unsigned level, real_t ip = 0, *state1ptr, *state2ptr; if (level > c->options.images_level) - error ("Level %d not supported.", level); + error ("We cannot interpret and image with Level %d.", level); state1ptr = c->images_of_state [domain1] + address_of_level (level); state2ptr = c->images_of_state [domain2] + address_of_level (level); diff --git a/converter/other/fiasco/codec/motion.c b/converter/other/fiasco/codec/motion.c index 92951281..876a2998 100644 --- a/converter/other/fiasco/codec/motion.c +++ b/converter/other/fiasco/codec/motion.c @@ -17,11 +17,9 @@ #include "config.h" -#if HAVE_STRING_H -# include -#else /* not HAVE_STRING_H */ -# include -#endif /* not HAVE_STRING_H */ +#include + +#include "pm_c_util.h" #include "types.h" #include "macros.h" @@ -54,10 +52,10 @@ restore_mc (int enlarge_factor, image_t *image, const image_t *past, #define FX(v) ((image->format == FORMAT_4_2_0) && band != Y ? ((v) / 2) : v) - mcblock1 = Calloc (size_of_level (max ((int) wfa->wfainfo->p_max_level + mcblock1 = Calloc (size_of_level (MAX((int) wfa->wfainfo->p_max_level + 2 * enlarge_factor, 0)), sizeof (word_t)); - mcblock2 = Calloc (size_of_level (max ((int) wfa->wfainfo->p_max_level + mcblock2 = Calloc (size_of_level (MAX((int) wfa->wfainfo->p_max_level + 2 * enlarge_factor, 0)), sizeof (word_t)); diff --git a/converter/other/fiasco/codec/mwfa.c b/converter/other/fiasco/codec/mwfa.c index 6f0af8be..43a7dae2 100644 --- a/converter/other/fiasco/codec/mwfa.c +++ b/converter/other/fiasco/codec/mwfa.c @@ -18,12 +18,9 @@ #include "config.h" #include +#include -#if HAVE_STRING_H -# include -#else /* not HAVE_STRING_H */ -# include -#endif /* not HAVE_STRING_H */ +#include "pm_c_util.h" #include "types.h" #include "macros.h" @@ -441,7 +438,7 @@ find_B_frame_mc (word_t *mcpe, real_t price, range_t *range, else /* local exhaustive search */ { /* - * Keep forward and backward mv due to time constraints + * Keep forward and backward mv because of time constraints */ ifx = fx; @@ -813,10 +810,10 @@ find_second_mv (real_t price, const image_t *original, sr = wi->search_range; - y0 = max ((int) -sr, *my - (int) local_range); - y1 = min ((int) sr, *my + (int) local_range); - x0 = max ((int) -sr, *mx - (int) local_range); - x1 = min ((int) sr, *mx + (int) local_range); + y0 = MAX((int) -sr, *my - (int) local_range); + y1 = MIN((int) sr, *my + (int) local_range); + x0 = MAX((int) -sr, *mx - (int) local_range); + x1 = MIN((int) sr, *mx + (int) local_range); *mx = *my = 0; diff --git a/converter/other/fiasco/codec/options.c b/converter/other/fiasco/codec/options.c index 77dbaf00..c8e4d2e2 100644 --- a/converter/other/fiasco/codec/options.c +++ b/converter/other/fiasco/codec/options.c @@ -20,12 +20,11 @@ #include "config.h" #include -#if STDC_HEADERS -# include -#endif /* not STDC_HEADERS */ - +#include #include +#include "nstring.h" + #include "types.h" #include "macros.h" #include "error.h" diff --git a/converter/other/fiasco/codec/prediction.c b/converter/other/fiasco/codec/prediction.c index 351ba9df..e056d10f 100644 --- a/converter/other/fiasco/codec/prediction.c +++ b/converter/other/fiasco/codec/prediction.c @@ -17,11 +17,7 @@ #include "config.h" -#if HAVE_STRING_H -# include -#else /* not HAVE_STRING_H */ -# include -#endif /* not HAVE_STRING_H */ +#include #include "types.h" #include "macros.h" diff --git a/converter/other/fiasco/codec/subdivide.c b/converter/other/fiasco/codec/subdivide.c index b7982716..2ace18e4 100644 --- a/converter/other/fiasco/codec/subdivide.c +++ b/converter/other/fiasco/codec/subdivide.c @@ -16,11 +16,9 @@ #include "config.h" -#if HAVE_STRING_H -# include -#else /* not HAVE_STRING_H */ -# include -#endif /* not HAVE_STRING_H */ +#include + +#include "pm_c_util.h" #include "types.h" #include "macros.h" @@ -293,7 +291,7 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range, : rrange.y; /* - * If neccessary compute the inner products of the new states + * If necessary compute the inner products of the new states * (generated during the recursive approximation of child [0]) */ if (label && rrange.level <= c->options.lc_max_level) @@ -304,7 +302,7 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range, * Abort the recursion if 'subdivide_costs' exceed 'lincomb_costs' * or 'max_costs'. */ - remaining_costs = min (lincomb_costs, max_costs) - subdivide_costs; + remaining_costs = MIN(lincomb_costs, max_costs) - subdivide_costs; if (remaining_costs > 0) /* still a way for improvement */ { @@ -356,7 +354,7 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range, * If costs of subdivision exceed costs of linear combination * then abort recursion. */ - if (subdivide_costs >= min (lincomb_costs, max_costs)) + if (subdivide_costs >= MIN(lincomb_costs, max_costs)) { subdivide_costs = MAXCOSTS; break; @@ -386,28 +384,28 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range, */ if (try_mc || try_nd) /* try prediction */ { - real_t prediction_costs; /* Costs arising from approx. the current - range with prediction */ - - prediction_costs - = predict_range (min (min (lincomb_costs, subdivide_costs), - max_costs), - price, range, wfa, c, band, y_state, states, - &tree_model, &p_tree_model, domain_model, - d_domain_model, coeff_model, d_coeff_model); - if (prediction_costs < MAXCOSTS) /* prediction has smallest costs */ - { - c->domain_pool->model_free (domain_model); - c->d_domain_pool->model_free (d_domain_model); - c->domain_pool->model_free (lc_domain_model); - c->d_domain_pool->model_free (lc_d_domain_model); - c->coeff->model_free (coeff_model); - c->d_coeff->model_free (d_coeff_model); - c->coeff->model_free (lc_coeff_model); - c->d_coeff->model_free (lc_d_coeff_model); + real_t prediction_costs; /* Costs arising from approx. the current + range with prediction */ + + prediction_costs + = predict_range (MIN(MIN(lincomb_costs, subdivide_costs), + max_costs), + price, range, wfa, c, band, y_state, states, + &tree_model, &p_tree_model, domain_model, + d_domain_model, coeff_model, d_coeff_model); + if (prediction_costs < MAXCOSTS) /* prediction has smallest costs */ + { + c->domain_pool->model_free (domain_model); + c->d_domain_pool->model_free (d_domain_model); + c->domain_pool->model_free (lc_domain_model); + c->d_domain_pool->model_free (lc_d_domain_model); + c->coeff->model_free (coeff_model); + c->d_coeff->model_free (d_coeff_model); + c->coeff->model_free (lc_coeff_model); + c->d_coeff->model_free (lc_d_coeff_model); - return prediction_costs; - } + return prediction_costs; + } } if (lincomb_costs >= MAXCOSTS && subdivide_costs >= MAXCOSTS) diff --git a/converter/other/fiasco/codec/tiling.c b/converter/other/fiasco/codec/tiling.c index e820f7fb..21e4428a 100644 --- a/converter/other/fiasco/codec/tiling.c +++ b/converter/other/fiasco/codec/tiling.c @@ -16,9 +16,9 @@ #include "config.h" -#if STDC_HEADERS -# include -#endif /* not STDC_HEADERS */ +#include + +#include "pm_c_util.h" #include "types.h" #include "macros.h" @@ -29,22 +29,7 @@ #include "wfalib.h" #include "tiling.h" -/***************************************************************************** - - prototypes - -*****************************************************************************/ - -static int -cmpdecvar (const void *value1, const void *value2); -static int -cmpincvar (const void *value1, const void *value2); - -/***************************************************************************** - public code - -*****************************************************************************/ typedef struct var_list { @@ -52,6 +37,38 @@ typedef struct var_list real_t variance; /* variance of tile */ } var_list_t; +#ifndef LITERAL_FN_DEF_MATCH +static qsort_comparison_fn cmpincvar; +#endif + +static int +cmpincvar(const void * const value1, + const void * const value2) { +/*---------------------------------------------------------------------------- + Sorts by increasing variances (quicksort sorting function) +-----------------------------------------------------------------------------*/ + return + ((var_list_t *) value1)->variance - ((var_list_t *) value2)->variance; +} + + + +#ifndef LITERAL_FN_DEF_MATCH +static qsort_comparison_fn cmpdecvar; +#endif + +static int +cmpdecvar(const void * const value1, + const void * const value2) { +/*---------------------------------------------------------------------------- + Sorts by decreasing variances (quicksort sorting function). +-----------------------------------------------------------------------------*/ + return + ((var_list_t *) value2)->variance - ((var_list_t *) value1)->variance; +} + + + tiling_t * alloc_tiling (fiasco_tiling_e method, unsigned tiling_exponent, unsigned image_level) @@ -146,7 +163,7 @@ perform_tiling (const image_t *image, tiling_t *tiling) unsigned number; /* number of image tiles */ unsigned lx = log2 (image->width - 1) + 1; /* x level */ unsigned ly = log2 (image->height - 1) + 1; /* y level */ - unsigned level = max (lx, ly) * 2 - ((ly == lx + 1) ? 1 : 0); + unsigned level = MAX(lx, ly) * 2 - ((ly == lx + 1) ? 1 : 0); var_list_t *var_list = Calloc (tiles, sizeof (var_list_t)); /* @@ -207,33 +224,10 @@ perform_tiling (const image_t *image, tiling_t *tiling) } else { - warning ("Unsupported image tiling method.\n" + warning ("We do not know the tiling method.\n" "Skipping image tiling step."); tiling->exponent = 0; } } } -/***************************************************************************** - - private code - -*****************************************************************************/ - -static int -cmpincvar (const void *value1, const void *value2) -/* - * Sorts by increasing variances (quicksort sorting function). - */ -{ - return ((var_list_t *) value1)->variance - ((var_list_t *) value2)->variance; -} - -static int -cmpdecvar (const void *value1, const void *value2) -/* - * Sorts by decreasing variances (quicksort sorting function). - */ -{ - return ((var_list_t *) value2)->variance - ((var_list_t *) value1)->variance; -} diff --git a/converter/other/fiasco/codec/wfa.h b/converter/other/fiasco/codec/wfa.h index 8b9793f2..9253affd 100644 --- a/converter/other/fiasco/codec/wfa.h +++ b/converter/other/fiasco/codec/wfa.h @@ -19,7 +19,7 @@ #define MAXEDGES 5 #define MAXSTATES 6000 -#define MAXLABELS 2 /* only bintree supported anymore */ +#define MAXLABELS 2 /* only bintree possible anymore */ #define MAXLEVEL 22 #define FIASCO_BINFILE_RELEASE 2 @@ -122,7 +122,7 @@ typedef struct wfa real_t *final_distribution; /* one pixel images */ byte_t *level_of_state; /* level of the image part which is represented by the current state */ - byte_t *domain_type; /* Bit_0==1: auxilliary state + byte_t *domain_type; /* Bit_0==1: auxiliary state Bit_1==1: used for Y compr */ mv_t (*mv_tree)[MAXLABELS]; /* motion vectors */ word_t (*tree)[MAXLABELS]; /* bintree partitioning */ diff --git a/converter/other/fiasco/codec/wfalib.c b/converter/other/fiasco/codec/wfalib.c index a3acb975..61d64d2f 100644 --- a/converter/other/fiasco/codec/wfalib.c +++ b/converter/other/fiasco/codec/wfalib.c @@ -19,12 +19,11 @@ #include "config.h" -#if STDC_HEADERS -# include -#endif /* not STDC_HEADERS */ - +#include #include +#include "pm_c_util.h" + #include "types.h" #include "macros.h" #include "error.h" @@ -218,7 +217,7 @@ compute_hits (unsigned from, unsigned to, unsigned n, const wfa_t *wfa) qsort (hits + 1, to - 1, sizeof (pair_t), sort_desc_pair); - n = min (to, n); + n = MIN(to, n); domains = Calloc (n + 1, sizeof (word_t)); for (domain = 0; domain < (int) n && (!domain || hits [domain].key); @@ -486,7 +485,7 @@ compute_spiral (int *vorder, unsigned image_width, unsigned image_height, lx = log2 (image_width - 1) + 1; ly = log2 (image_height - 1) + 1; - level = max (lx, ly) * 2 - ((ly == lx + 1) ? 1 : 0); + level = MAX(lx, ly) * 2 - ((ly == lx + 1) ? 1 : 0); tiles = 1 << tiling_exp; /* Number of image tiles */ width = width_of_level (level - tiling_exp); height = height_of_level (level - tiling_exp); diff --git a/converter/other/fiasco/config.h b/converter/other/fiasco/config.h index 64b905f8..57b3518d 100644 --- a/converter/other/fiasco/config.h +++ b/converter/other/fiasco/config.h @@ -56,9 +56,6 @@ /* Define if you have the strcasecmp function. */ #define HAVE_STRCASECMP 1 -/* Define if you have the strdup function. */ -#define HAVE_STRDUP 1 - /* Define if you have the header file. */ /* #undef HAVE_X11_EXTENSIONS_XSHM_H */ diff --git a/converter/other/fiasco/display.c b/converter/other/fiasco/display.c index 9e531149..cf160329 100644 --- a/converter/other/fiasco/display.c +++ b/converter/other/fiasco/display.c @@ -27,16 +27,8 @@ #include #include -#if STDC_HEADERS -# include -# include -#else /* not STDC_HEADERS */ -# if HAVE_STRING_H -# include -# else /* not HAVE_STRING_H */ -# include -# endif /* not HAVE_STRING_H */ -#endif /* not STDC_HEADERS */ +#include +#include #include "types.h" #include "macros.h" @@ -315,7 +307,8 @@ alloc_ximage (x11_info_t *xinfo, unsigned width, unsigned height) shmem_flag = 0; if (fiasco_get_verbosity ()) fprintf (stderr, - "Shared memory not supported\nReverting to normal Xlib.\n"); + "Shared memory does not work on this system\n" + "Reverting to normal Xlib.\n"); } if (shmem_flag) diff --git a/converter/other/fiasco/fiascotopnm.c b/converter/other/fiasco/fiascotopnm.c index 6d8b6f7f..dfba2256 100644 --- a/converter/other/fiasco/fiascotopnm.c +++ b/converter/other/fiasco/fiascotopnm.c @@ -25,6 +25,8 @@ #include #include +#include "nstring.h" + #include "types.h" #include "macros.h" @@ -176,21 +178,21 @@ checkargs (int argc, char **argv, bool_t *double_resolution, bool_t *panel, *options = fiasco_d_options_new (); { - int n = *((int *) parameter_value (params, "smoothing")); + int const n = *((int *) parameter_value (params, "smoothing")); - if (!fiasco_d_options_set_smoothing (*options, max (-1, n))) + if (!fiasco_d_options_set_smoothing (*options, MAX(-1, n))) error (fiasco_get_error_message ()); } { - int n = *((int *) parameter_value (params, "magnify")); + int const n = *((int *) parameter_value (params, "magnify")); if (!fiasco_d_options_set_magnification (*options, n)) error (fiasco_get_error_message ()); } { - bool_t n = *((bool_t *) parameter_value (params, "fast")); + bool_t const n = *((bool_t *) parameter_value (params, "fast")); if (!fiasco_d_options_set_4_2_0_format (*options, n > 0 ? YES : NO)) error (fiasco_get_error_message ()); diff --git a/converter/other/fiasco/getopt.c b/converter/other/fiasco/getopt.c index 0b2d1b75..2f45c7cc 100644 --- a/converter/other/fiasco/getopt.c +++ b/converter/other/fiasco/getopt.c @@ -73,15 +73,7 @@ #include #endif /* GNU C library. */ -#ifdef VMS -#include -#if HAVE_STRING_H - 0 -#include -#endif -#endif - -#if defined (WIN32) && !defined (__CYGWIN32__) -/* It's not Unix, really. See? Capital letters. */ +#if MSVCRT #include #define getpid() GetCurrentProcessId() #endif diff --git a/converter/other/fiasco/input/basis.c b/converter/other/fiasco/input/basis.c index cef075e6..4a748f61 100644 --- a/converter/other/fiasco/input/basis.c +++ b/converter/other/fiasco/input/basis.c @@ -16,6 +16,8 @@ #include "config.h" +#include "nstring.h" + #include "types.h" #include "macros.h" #include "error.h" diff --git a/converter/other/fiasco/input/read.c b/converter/other/fiasco/input/read.c index 26bae7e4..e6e2d7e8 100644 --- a/converter/other/fiasco/input/read.c +++ b/converter/other/fiasco/input/read.c @@ -23,6 +23,8 @@ #include +#include "nstring.h" + #include "types.h" #include "macros.h" #include "error.h" @@ -155,7 +157,7 @@ open_wfa (const char *filename, wfa_info_t *wi) unsigned lx = log2 (wi->width - 1) + 1; unsigned ly = log2 (wi->height - 1) + 1; - wi->level = max (lx, ly) * 2 - ((ly == lx + 1) ? 1 : 0); + wi->level = MAX(lx, ly) * 2 - ((ly == lx + 1) ? 1 : 0); } wi->chroma_max_states = wi->color ? read_rice_code (rice_k, input) : -1; wi->p_min_level = read_rice_code (rice_k, input); @@ -275,7 +277,7 @@ read_basis (const char *filename, wfa_t *wfa) * string |MAGIC Number "Wfa" * int |Number of basis states 'N' * bool_t-array[N] |use vector in linear combinations, - * |0: don't use vector (auxilliary state) + * |0: don't use vector (auxiliary state) * |1: use vector in linear combinations * float-array[N] |final distribution of every state * @@ -395,7 +397,7 @@ read_next_wfa (wfa_t *wfa, bitfile_t *input) /* * Compute domain pool. - * Large images have not been used due to image tiling. + * Large images have not been used because of image tiling. */ { unsigned state; diff --git a/converter/other/fiasco/input/weights.c b/converter/other/fiasco/input/weights.c index 55339980..15c35731 100644 --- a/converter/other/fiasco/input/weights.c +++ b/converter/other/fiasco/input/weights.c @@ -1,8 +1,8 @@ /* - * weights.c: Input of weights + * weights.c: Input of weights * - * Written by: Ullrich Hafner - * + * Written by: Ullrich Hafner + * * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) * Copyright (C) 1994-2000 Ullrich Hafner */ @@ -16,6 +16,8 @@ #include "config.h" +#include "pm_c_util.h" + #include "types.h" #include "macros.h" #include "error.h" @@ -29,7 +31,7 @@ /***************************************************************************** - public code + public code *****************************************************************************/ @@ -42,17 +44,17 @@ read_weights (unsigned total, wfa_t *wfa, bitfile_t *input) * No return value. * * Side effects: - * 'wfa->weights' are filled with the decoded values + * 'wfa->weights' are filled with the decoded values */ { - unsigned state; - unsigned label; - unsigned edge; /* current edge */ - unsigned *weights_array; /* array of weights to encode */ - unsigned *level_array; /* array of corresponding levels */ - unsigned offset1, offset2; /* prob. model offsets. */ - unsigned offset3, offset4; /* prob. model offsets. */ - bool_t delta_approx = NO; /* true if delta has been used */ + unsigned state; + unsigned label; + unsigned edge; /* current edge */ + unsigned *weights_array; /* array of weights to encode */ + unsigned *level_array; /* array of corresponding levels */ + unsigned offset1, offset2; /* prob. model offsets. */ + unsigned offset3, offset4; /* prob. model offsets. */ + bool_t delta_approx = NO; /* true if delta has been used */ /* * Check whether delta approximation has been used @@ -60,52 +62,54 @@ read_weights (unsigned total, wfa_t *wfa, bitfile_t *input) for (state = wfa->basis_states; state < wfa->states; state++) if (wfa->delta_state [state]) { - delta_approx = YES; - break; + delta_approx = YES; + break; } /* * Generate array of corresponding levels (context of probability model) */ { - int min_level, max_level; /* min and max range level */ - int d_min_level, d_max_level; /* min and max range level (delta) */ - unsigned *lptr; /* pointer to current corresp. level */ - int domain; /* current domain */ - bool_t dc, d_dc; /* indicates whether DC is used */ + int min_level, max_level; /* min and max range level */ + int d_min_level, d_max_level; /* min and max range level (delta) */ + unsigned *lptr; /* pointer to current corresp. level */ + int domain; /* current domain */ + bool_t dc, d_dc; /* indicates whether DC is used */ /* * Compute minimum and maximum level of delta and normal approximations */ min_level = d_min_level = MAXLEVEL; max_level = d_max_level = 0; - dc = d_dc = NO; + dc = d_dc = NO; for (state = wfa->basis_states; state < wfa->states; state++) - for (label = 0; label < MAXLABELS; label++) - if (isrange (wfa->tree [state][label])) - { - if (delta_approx && wfa->delta_state [state]) - { - d_min_level = min (d_min_level, - wfa->level_of_state [state] - 1); - d_max_level = max (d_max_level, - wfa->level_of_state [state] - 1); - if (wfa->into [state][label][0] == 0) - d_dc = YES; - } - else - { - min_level = min (min_level, wfa->level_of_state [state] - 1); - max_level = max (max_level, wfa->level_of_state [state] - 1); - if (wfa->into [state][label][0] == 0) - dc = YES; - } - } - if (min_level > max_level) /* no lc found */ - max_level = min_level - 1; + for (label = 0; label < MAXLABELS; label++) + if (isrange (wfa->tree [state][label])) + { + if (delta_approx && wfa->delta_state [state]) + { + d_min_level = + MIN(d_min_level, wfa->level_of_state [state] - 1); + d_max_level = + MAX(d_max_level, wfa->level_of_state [state] - 1); + if (wfa->into [state][label][0] == 0) + d_dc = YES; + } + else + { + min_level = + MIN(min_level, wfa->level_of_state [state] - 1); + max_level = + MAX(max_level, wfa->level_of_state [state] - 1); + if (wfa->into [state][label][0] == 0) + dc = YES; + } + } + if (min_level > max_level) /* no lc found */ + max_level = min_level - 1; if (d_min_level > d_max_level) - d_max_level = d_min_level - 1; + d_max_level = d_min_level - 1; offset1 = dc ? 1 : 0; offset2 = offset1 + (d_dc ? 1 : 0); @@ -114,47 +118,47 @@ read_weights (unsigned total, wfa_t *wfa, bitfile_t *input) lptr = level_array = Calloc (total, sizeof (int)); for (state = wfa->basis_states; state < wfa->states; state++) - for (label = 0; label < MAXLABELS; label++) - if (isrange (wfa->tree[state][label])) - for (edge = 0; isedge (domain = wfa->into[state][label][edge]); - edge++) - { - if ((unsigned) (lptr - level_array) >= total) - error ("Can't read more than %d weights.", total); - if (domain) - { - if (delta_approx && wfa->delta_state [state]) - *lptr++ = offset3 + wfa->level_of_state [state] - - 1 - d_min_level; - else - *lptr++ = offset2 + wfa->level_of_state [state] - - 1 - min_level; - } - else - *lptr++ = delta_approx && wfa->delta_state [state] - ? offset1 : 0; - } + for (label = 0; label < MAXLABELS; label++) + if (isrange (wfa->tree[state][label])) + for (edge = 0; isedge (domain = wfa->into[state][label][edge]); + edge++) + { + if ((unsigned) (lptr - level_array) >= total) + error ("Can't read more than %d weights.", total); + if (domain) + { + if (delta_approx && wfa->delta_state [state]) + *lptr++ = offset3 + wfa->level_of_state [state] + - 1 - d_min_level; + else + *lptr++ = offset2 + wfa->level_of_state [state] + - 1 - min_level; + } + else + *lptr++ = delta_approx && wfa->delta_state [state] + ? offset1 : 0; + } } /* * Decode the list of weights with an arithmetic decoder */ { - unsigned i; - unsigned *c_symbols = Calloc (offset4, sizeof (unsigned)); - const unsigned scale = 500; /* scaling of probability model */ + unsigned i; + unsigned *c_symbols = Calloc (offset4, sizeof (unsigned)); + const unsigned scale = 500; /* scaling of probability model */ c_symbols [0] = 1 << (wfa->wfainfo->dc_rpf->mantissa_bits + 1); if (offset1 != offset2) - c_symbols [offset1] = 1 << (wfa->wfainfo->d_dc_rpf->mantissa_bits - + 1); + c_symbols [offset1] = 1 << (wfa->wfainfo->d_dc_rpf->mantissa_bits + + 1); for (i = offset2; i < offset3; i++) - c_symbols [i] = 1 << (wfa->wfainfo->rpf->mantissa_bits + 1); + c_symbols [i] = 1 << (wfa->wfainfo->rpf->mantissa_bits + 1); for (; i < offset4; i++) - c_symbols [i] = 1 << (wfa->wfainfo->d_rpf->mantissa_bits + 1); + c_symbols [i] = 1 << (wfa->wfainfo->d_rpf->mantissa_bits + 1); weights_array = decode_array (input, level_array, c_symbols, - offset4, total, scale); + offset4, total, scale); Free (c_symbols); } Free (level_array); @@ -163,36 +167,36 @@ read_weights (unsigned total, wfa_t *wfa, bitfile_t *input) * Update transitions with decoded weights */ { - unsigned *wptr = weights_array; /* pointer to current weight */ - int domain; /* current domain */ + unsigned *wptr = weights_array; /* pointer to current weight */ + int domain; /* current domain */ for (state = wfa->basis_states; state < wfa->states; state++) - for (label = 0; label < MAXLABELS; label++) - if (isrange (wfa->tree[state][label])) - for (edge = 0; isedge (domain = wfa->into[state][label][edge]); - edge++) - { - if (domain) /* not DC component */ - { - if (delta_approx && wfa->delta_state [state]) - wfa->weight [state][label][edge] - = btor (*wptr++, wfa->wfainfo->d_rpf); - else - wfa->weight [state][label][edge] - = btor (*wptr++, wfa->wfainfo->rpf); - } - else - { - if (delta_approx && wfa->delta_state [state]) - wfa->weight [state][label][edge] - = btor (*wptr++, wfa->wfainfo->d_dc_rpf); - else - wfa->weight [state][label][edge] - = btor (*wptr++, wfa->wfainfo->dc_rpf); - } - wfa->int_weight [state][label][edge] - = wfa->weight [state][label][edge] * 512 + 0.5; - } + for (label = 0; label < MAXLABELS; label++) + if (isrange (wfa->tree[state][label])) + for (edge = 0; isedge (domain = wfa->into[state][label][edge]); + edge++) + { + if (domain) /* not DC component */ + { + if (delta_approx && wfa->delta_state [state]) + wfa->weight [state][label][edge] + = btor (*wptr++, wfa->wfainfo->d_rpf); + else + wfa->weight [state][label][edge] + = btor (*wptr++, wfa->wfainfo->rpf); + } + else + { + if (delta_approx && wfa->delta_state [state]) + wfa->weight [state][label][edge] + = btor (*wptr++, wfa->wfainfo->d_dc_rpf); + else + wfa->weight [state][label][edge] + = btor (*wptr++, wfa->wfainfo->dc_rpf); + } + wfa->int_weight [state][label][edge] + = wfa->weight [state][label][edge] * 512 + 0.5; + } } Free (weights_array); diff --git a/converter/other/fiasco/lib/arith.c b/converter/other/fiasco/lib/arith.c index e3745bf7..dc35d1d1 100644 --- a/converter/other/fiasco/lib/arith.c +++ b/converter/other/fiasco/lib/arith.c @@ -90,7 +90,7 @@ encode_symbol (unsigned symbol, arith_t *arith, model_t *model) * The current state of the arithmetic coder is given by 'arith'. * Output bits are appended to the stream 'output'. * - * The model is updated after encoding the symbol (if neccessary the + * The model is updated after encoding the symbol (if necessary the * symbol counts are rescaled). * * Return value: @@ -354,7 +354,7 @@ decode_symbol (arith_t *arith, model_t *model) * Decode the next symbol - the state of the arithmetic decoder * is given in 'arith'. Read refinement bits from the stream 'input' * and use the given probability 'model'. Update the probability model after - * deconding the symbol (if neccessary also rescale the symbol counts). + * deconding the symbol (if necessary also rescale the symbol counts). * * Return value: * decoded symbol diff --git a/converter/other/fiasco/lib/bit-io.c b/converter/other/fiasco/lib/bit-io.c index 364a1c05..1bfef598 100644 --- a/converter/other/fiasco/lib/bit-io.c +++ b/converter/other/fiasco/lib/bit-io.c @@ -20,9 +20,9 @@ #include "config.h" #include -#if STDC_HEADERS -# include -#endif /* not STDC_HEADERS */ +#include + +#include "nstring.h" #include "macros.h" #include "types.h" diff --git a/converter/other/fiasco/lib/dither.c b/converter/other/fiasco/lib/dither.c index a39afa3c..accd9dd6 100644 --- a/converter/other/fiasco/lib/dither.c +++ b/converter/other/fiasco/lib/dither.c @@ -38,14 +38,8 @@ #include "pm_config.h" #include "config.h" -#if HAVE_STRING_H -# include -#else /* not HAVE_STRING_H */ -# include -#endif /* not HAVE_STRING_H */ -#if STDC_HEADERS -# include -#endif /* not STDC_HEADERS */ +#include +#include #include "types.h" #include "macros.h" @@ -65,19 +59,22 @@ static int display_16_bit (const struct fiasco_renderer *this, unsigned char *ximage, const fiasco_image_t *fiasco_image); + static int display_24_bit_bgr (const struct fiasco_renderer *this, unsigned char *ximage, const fiasco_image_t *fiasco_image); + static int display_24_bit_rgb (const struct fiasco_renderer *this, unsigned char *ximage, const fiasco_image_t *fiasco_image); + static int display_32_bit (const struct fiasco_renderer *this, unsigned char *ximage, const fiasco_image_t *fiasco_image); + static int free_bits_at_bottom (unsigned long a); -static int -free_bits_at_top (unsigned long a); + static int number_of_bits_set (unsigned long a); @@ -344,21 +341,6 @@ number_of_bits_set (unsigned long a) return (number_of_bits_set (a >> 1)); } -static int -free_bits_at_top (unsigned long a) -/* - * How many 0 bits are there at most significant end of longword. - * Low performance, do not call often. - */ -{ - if(!a) /* assume char is 8 bits */ - return sizeof (unsigned long) * 8; - else if (((long) a) < 0l) /* assume twos complement */ - return 0; - else - return 1 + free_bits_at_top ( a << 1); -} - static int free_bits_at_bottom (unsigned long a) /* diff --git a/converter/other/fiasco/lib/error.c b/converter/other/fiasco/lib/error.c index b858badf..ee3afe1f 100644 --- a/converter/other/fiasco/lib/error.c +++ b/converter/other/fiasco/lib/error.c @@ -29,18 +29,9 @@ #include #include -#if STDC_HEADERS -# include -# define VA_START(args, lastarg) va_start(args, lastarg) -#else /* not STDC_HEADERS */ -# include -# define VA_START(args, lastarg) va_start(args) -#endif /* not STDC_HEADERS */ -#if HAVE_STRING_H -# include -#else /* not HAVE_STRING_H */ -# include -#endif /* not HAVE_STRING_H */ +#include +#define VA_START(args, lastarg) va_start(args, lastarg) +#include #if HAVE_SETJMP_H # include @@ -117,11 +108,7 @@ set_error (const char *format, ...) Free (error_message); error_message = Calloc (len, sizeof (char)); -#if HAVE_VPRINTF vsprintf (error_message, format, args); -#elif HAVE_DOPRNT - _doprnt (format, args, stderr); -#endif /* HAVE_DOPRNT */ va_end (args); } @@ -178,11 +165,7 @@ error (const char *format, ...) Free (error_message); error_message = Calloc (len, sizeof (char)); -#if HAVE_VPRINTF vsprintf (error_message, format, args); -#elif HAVE_DOPRNT - _doprnt (format, args, stderr); -#endif /* HAVE_DOPRNT */ va_end (args); @@ -236,11 +219,7 @@ warning (const char *format, ...) return; fprintf (stderr, "Warning: "); -#if HAVE_VPRINTF vfprintf (stderr, format, args); -#elif HAVE_DOPRNT - _doprnt (format, args, stderr); -#endif /* HAVE_DOPRNT */ fputc ('\n', stderr); va_end (args); @@ -259,11 +238,7 @@ message (const char *format, ...) if (verboselevel == FIASCO_NO_VERBOSITY) return; -#if HAVE_VPRINTF vfprintf (stderr, format, args); -#elif HAVE_DOPRNT - _doprnt (format, args, stderr); -#endif /* HAVE_DOPRNT */ fputc ('\n', stderr); va_end (args); } @@ -282,11 +257,7 @@ debug_message (const char *format, ...) return; fprintf (stderr, "*** "); -#if HAVE_VPRINTF vfprintf (stderr, format, args); -#elif HAVE_DOPRNT - _doprnt (format, args, stderr); -#endif /* HAVE_DOPRNT */ fputc ('\n', stderr); va_end (args); } @@ -304,11 +275,7 @@ info (const char *format, ...) if (verboselevel == FIASCO_NO_VERBOSITY) return; -#if HAVE_VPRINTF vfprintf (stderr, format, args); -#elif HAVE_DOPRNT - _doprnt (format, args, stderr); -#endif /* HAVE_DOPRNT */ fflush (stderr); va_end (args); } diff --git a/converter/other/fiasco/lib/image.c b/converter/other/fiasco/lib/image.c index 0168734c..fa3b2db5 100644 --- a/converter/other/fiasco/lib/image.c +++ b/converter/other/fiasco/lib/image.c @@ -18,6 +18,8 @@ #include +#include "nstring.h" + #include "types.h" #include "macros.h" #include "error.h" @@ -239,7 +241,7 @@ alloc_image (unsigned width, unsigned height, bool_t color, format_e format) image->format = format; image->reference_count = 1; - strcpy (image->id, "IFIASCO"); + STRSCPY(image->id, "IFIASCO"); for (band = first_band (color); band <= last_band (color); band++) if (format == FORMAT_4_2_0 && band != Y) @@ -447,7 +449,7 @@ write_image (const char *image_name, const image_t *image) if (image->format == FORMAT_4_2_0) { - warning ("Writing of images in 4:2:0 format not supported."); + warning ("We cannot write images in 4:2:0 format."); return; } diff --git a/converter/other/fiasco/lib/list.c b/converter/other/fiasco/lib/list.c index 9f516c2e..bb4efae1 100644 --- a/converter/other/fiasco/lib/list.c +++ b/converter/other/fiasco/lib/list.c @@ -16,11 +16,7 @@ #include "config.h" -#if HAVE_STRING_H -# include -#else /* not HAVE_STRING_H */ -# include -#endif /* not HAVE_STRING_H */ +#include #include "types.h" #include "macros.h" diff --git a/converter/other/fiasco/lib/macros.h b/converter/other/fiasco/lib/macros.h index 877abeea..9968110a 100644 --- a/converter/other/fiasco/lib/macros.h +++ b/converter/other/fiasco/lib/macros.h @@ -28,11 +28,6 @@ # define SEEK_CUR 1 #endif /* not SEEK_CUR */ -#ifdef WIN32 -#undef max -#undef min -#endif /* not WIN32 */ - /***************************************************************************** Various macros @@ -50,12 +45,6 @@ #define address_of_level(l) ((unsigned) (size_of_level (l) - 1)) #define size_of_tree(l) ((unsigned) (address_of_level ((l) + 1))) #define is_odd(n) (abs (n) % 2) -#ifndef max -#define max(a,b) ((a) < (b) ? (b) : (a)) -#endif -#ifndef min -#define min(a,b) ((a) > (b) ? (b) : (a)) -#endif #define _(x) (x) diff --git a/converter/other/fiasco/lib/misc.c b/converter/other/fiasco/lib/misc.c index 12b94e7a..782ed1e9 100644 --- a/converter/other/fiasco/lib/misc.c +++ b/converter/other/fiasco/lib/misc.c @@ -1,5 +1,5 @@ /* - * misc.c: Some usefull functions, that don't fit in one of + * misc.c: Some useful functions, that don't fit in one of * the other files and that are needed by at least * two modules. * @@ -33,15 +33,10 @@ # endif /* not HAVE_SYS_TIME_H */ #endif /* not TIME_WITH_SYS_TIME */ -#if STDC_HEADERS -# include -#endif /* not STDC_HEADERS */ +#include +#include -#if HAVE_STRING_H -# include -#else /* not HAVE_STRING_H */ -# include -#endif /* not HAVE_STRING_H */ +#include "pm_c_util.h" #include "types.h" #include "macros.h" @@ -401,22 +396,6 @@ memmove (void *v_dst, const void *v_src, size_t n) } #endif /* not HAVE_MEMMOVE */ -#ifndef HAVE_STRDUP -char * -strdup (const char *s) -/* - * Duplicate given string 's'. - * - * Return value: - * pointer to new string value - */ -{ - assert (s); - - return strcpy (Calloc (strlen (s) + 1, sizeof (char)), s); -} -#endif /* not HAVE_STRDUP */ - /* Note that some systems have a "log2()" in the math library and some have a "log2" macro. So we name ours Log2. But to avoid lots of differences from the original fiasco source code, we define a @@ -452,13 +431,13 @@ variance (const word_t *pixels, unsigned x0, unsigned y0, assert (pixels); for (average = 0, n = 0, y = y0; y < y0 + height; y++) - for (x = x0; x < min (x0 + width, cols); x++, n++) + for (x = x0; x < MIN(x0 + width, cols); x++, n++) average += pixels [y * cols + x] / 16; average /= n; for (variance = 0, y = y0; y < y0 + height; y++) - for (x = x0; x < min (x0 + width, cols); x++) + for (x = x0; x < MIN(x0 + width, cols); x++) variance += square ((pixels [y * cols + x] / 16) - average); return variance; diff --git a/converter/other/fiasco/lib/misc.h b/converter/other/fiasco/lib/misc.h index 29456590..28fd8b5a 100644 --- a/converter/other/fiasco/lib/misc.h +++ b/converter/other/fiasco/lib/misc.h @@ -72,10 +72,6 @@ memmove(void *dest, const void *src, size_t n); double Log2 (double x); -#ifndef HAVE_STRDUP -char * -strdup (const char *s); -#endif #ifndef HAVE_STRCASECMP bool_t strcaseeq (const char *s1, const char *s2); diff --git a/converter/other/fiasco/output/matrices.c b/converter/other/fiasco/output/matrices.c index fd8d31e2..01189669 100644 --- a/converter/other/fiasco/output/matrices.c +++ b/converter/other/fiasco/output/matrices.c @@ -20,9 +20,9 @@ #include "config.h" -#if STDC_HEADERS -# include -#endif /* not STDC_HEADERS */ +#include + +#include "pm_c_util.h" #include "types.h" #include "macros.h" @@ -144,7 +144,7 @@ delta_encoding (bool_t use_normal_domains, bool_t use_delta_domains, ; count [edge]++; edges++; - M = max (edge, M); + M = MAX(edge, M); } write_rice_code (M, 3, output); for (n = 0; n <= M; n++) diff --git a/converter/other/fiasco/output/weights.c b/converter/other/fiasco/output/weights.c index 085a1f00..5aa17674 100644 --- a/converter/other/fiasco/output/weights.c +++ b/converter/other/fiasco/output/weights.c @@ -16,6 +16,8 @@ #include "config.h" +#include "pm_c_util.h" + #include "types.h" #include "macros.h" #include "error.h" @@ -43,158 +45,159 @@ write_weights (unsigned total, const wfa_t *wfa, bitfile_t *output) * No return value. */ { - unsigned state, label; /* current label */ - unsigned offset1, offset2; /* model offsets. */ - unsigned offset3, offset4; /* model offsets. */ - unsigned *weights_array; /* array of weights to encode */ - unsigned *wptr; /* pointer to current weight */ - unsigned *level_array; /* array of corresponding levels */ - unsigned *lptr; /* pointer to current corr. level */ - int min_level, max_level; /* min and max range level */ - int d_min_level, d_max_level; /* min and max delta range level */ - bool_t dc, d_dc; /* true if dc or delta dc are used */ - bool_t delta_approx = NO; /* true if delta has been used */ - unsigned delta_count = 0; /* number of delta ranges */ - unsigned bits = bits_processed (output); + unsigned state, label; /* current label */ + unsigned offset1, offset2; /* model offsets. */ + unsigned offset3, offset4; /* model offsets. */ + unsigned *weights_array; /* array of weights to encode */ + unsigned *wptr; /* pointer to current weight */ + unsigned *level_array; /* array of corresponding levels */ + unsigned *lptr; /* pointer to current corr. level */ + int min_level, max_level; /* min and max range level */ + int d_min_level, d_max_level; /* min and max delta range level */ + bool_t dc, d_dc; /* true if dc or delta dc are used */ + bool_t delta_approx = NO; /* true if delta has been used */ + unsigned delta_count = 0; /* number of delta ranges */ + unsigned bits = bits_processed (output); - /* - * Check whether delta approximation has been used - */ - for (state = wfa->basis_states; state < wfa->states; state++) - if (wfa->delta_state [state]) - { - delta_approx = YES; - break; - } + /* + * Check whether delta approximation has been used + */ + for (state = wfa->basis_states; state < wfa->states; state++) + if (wfa->delta_state [state]) + { + delta_approx = YES; + break; + } - /* - * Generate array of corresponding levels (context of probability model) - */ - min_level = d_min_level = MAXLEVEL; - max_level = d_max_level = 0; - dc = d_dc = NO; + /* + * Generate array of corresponding levels (context of probability model) + */ + min_level = d_min_level = MAXLEVEL; + max_level = d_max_level = 0; + dc = d_dc = NO; - for (state = wfa->basis_states; state < wfa->states; state++) - for (label = 0; label < MAXLABELS; label++) - if (isrange (wfa->tree [state][label])) - { - if (delta_approx && wfa->delta_state [state]) /* delta approx. */ - { - d_min_level = min (d_min_level, - wfa->level_of_state [state] - 1); - d_max_level = max (d_max_level, - wfa->level_of_state [state] - 1); - if (wfa->into [state][label][0] == 0) - d_dc = YES; - } - else - { - min_level = min (min_level, wfa->level_of_state [state] - 1); - max_level = max (max_level, wfa->level_of_state [state] - 1); - if (wfa->into [state][label][0] == 0) - dc = YES; - } - } - if (min_level > max_level) /* no lc found */ - max_level = min_level - 1; - if (d_min_level > d_max_level) - d_max_level = d_min_level - 1; - - /* - * Context model: - * 0 DC weight - * 1 Delta DC weight - * 2-k normal weights per level - * k+1 - m Delta weights per level - */ - - offset1 = dc ? 1 : 0; - offset2 = offset1 + (d_dc ? 1 : 0); - offset3 = offset2 + (max_level - min_level + 1); - offset4 = offset3 + (d_max_level - d_min_level + 1); + for (state = wfa->basis_states; state < wfa->states; state++) + for (label = 0; label < MAXLABELS; label++) + if (isrange (wfa->tree [state][label])) + { + if (delta_approx && wfa->delta_state [state]) /* delta approx. */ + { + d_min_level = MIN(d_min_level, wfa->level_of_state [state] - 1); + d_max_level = MAX(d_max_level, wfa->level_of_state [state] - 1); + if (wfa->into [state][label][0] == 0) + d_dc = YES; + } + else + { + min_level = MIN(min_level, wfa->level_of_state [state] - 1); + max_level = MAX(max_level, wfa->level_of_state [state] - 1); + if (wfa->into [state][label][0] == 0) + dc = YES; + } + } + if (min_level > max_level) /* no lc found */ + max_level = min_level - 1; + if (d_min_level > d_max_level) + d_max_level = d_min_level - 1; + + /* + * Context model: + * 0 DC weight + * 1 Delta DC weight + * 2-k normal weights per level + * k+1 - m Delta weights per level + */ + + offset1 = dc ? 1 : 0; + offset2 = offset1 + (d_dc ? 1 : 0); + offset3 = offset2 + (max_level - min_level + 1); + offset4 = offset3 + (d_max_level - d_min_level + 1); - /* - * Weights are encoded as follows: - * all weights of state n - * sorted by label - * sorted by domain number - */ - - wptr = weights_array = Calloc (total, sizeof (unsigned)); - lptr = level_array = Calloc (total, sizeof (unsigned)); - - for (state = wfa->basis_states; state < wfa->states; state++) - for (label = 0; label < MAXLABELS; label++) - if (isrange (wfa->tree [state][label])) - { - int edge; /* current edge */ - int domain; /* current domain (context of model) */ - - for (edge = 0; isedge (domain = wfa->into [state][label][edge]); - edge++) + /* + * Weights are encoded as follows: + * all weights of state n + * sorted by label + * sorted by domain number + */ + + wptr = weights_array = Calloc (total, sizeof (unsigned)); + lptr = level_array = Calloc (total, sizeof (unsigned)); + + for (state = wfa->basis_states; state < wfa->states; state++) + for (label = 0; label < MAXLABELS; label++) + if (isrange (wfa->tree [state][label])) { - if (wptr - weights_array >= (int) total) - error ("Can't write more than %d weights.", total); - if (domain) /* not DC component */ - { - if (delta_approx && wfa->delta_state [state]) /* delta */ - { - *wptr++ = rtob (wfa->weight [state][label][edge], - wfa->wfainfo->d_rpf); - *lptr++ = offset3 - + wfa->level_of_state [state] - 1 - d_min_level; - delta_count++; - } - else - { - *wptr++ = rtob (wfa->weight [state][label][edge], - wfa->wfainfo->rpf); - *lptr++ = offset2 - + wfa->level_of_state [state] - 1 - min_level; - } - } - else /* DC component */ - { - if (delta_approx && wfa->delta_state [state]) /* delta */ - { - *wptr++ = rtob (wfa->weight [state][label][edge], - wfa->wfainfo->d_dc_rpf); - *lptr++ = offset1; - } - else - { - *wptr++ = rtob (wfa->weight [state][label][edge], - wfa->wfainfo->dc_rpf); - *lptr++ = 0; - } - } + int edge; /* current edge */ + int domain; /* current domain (context of model) */ + + for (edge = 0; isedge (domain = wfa->into [state][label][edge]); + edge++) + { + if (wptr - weights_array >= (int) total) + error ("Can't write more than %d weights.", total); + if (domain) /* not DC component */ + { + if (delta_approx && wfa->delta_state [state]) /* delta */ + { + *wptr++ = rtob (wfa->weight [state][label][edge], + wfa->wfainfo->d_rpf); + *lptr++ = offset3 + + wfa->level_of_state [state] - 1 - d_min_level; + delta_count++; + } + else + { + *wptr++ = rtob (wfa->weight [state][label][edge], + wfa->wfainfo->rpf); + *lptr++ = offset2 + + wfa->level_of_state [state] - 1 - min_level; + } + } + else /* DC component */ + { + if (delta_approx && wfa->delta_state [state]) /* delta */ + { + *wptr++ = rtob (wfa->weight [state][label][edge], + wfa->wfainfo->d_dc_rpf); + *lptr++ = offset1; + } + else + { + *wptr++ = rtob (wfa->weight [state][label][edge], + wfa->wfainfo->dc_rpf); + *lptr++ = 0; + } + } + } } - } - - { - unsigned i; - unsigned *c_symbols = Calloc (offset4, sizeof (int)); - const int scale = 500; /* scaling of probability model */ - - c_symbols [0] = 1 << (wfa->wfainfo->dc_rpf->mantissa_bits + 1); - if (offset1 != offset2) - c_symbols [offset1] = 1 << (wfa->wfainfo->d_dc_rpf->mantissa_bits - + 1); - for (i = offset2; i < offset3; i++) - c_symbols [i] = 1 << (wfa->wfainfo->rpf->mantissa_bits + 1); - for (; i < offset4; i++) - c_symbols [i] = 1 << (wfa->wfainfo->d_rpf->mantissa_bits + 1); + + { + unsigned i; + unsigned *c_symbols = Calloc (offset4, sizeof (int)); + const int scale = 500; /* scaling of probability model */ + + c_symbols [0] = 1 << (wfa->wfainfo->dc_rpf->mantissa_bits + 1); + if (offset1 != offset2) + c_symbols [offset1] = 1 << (wfa->wfainfo->d_dc_rpf->mantissa_bits + + 1); + for (i = offset2; i < offset3; i++) + c_symbols [i] = 1 << (wfa->wfainfo->rpf->mantissa_bits + 1); + for (; i < offset4; i++) + c_symbols [i] = 1 << (wfa->wfainfo->d_rpf->mantissa_bits + 1); - encode_array (output, weights_array, level_array, c_symbols, offset4, - total, scale); - Free (c_symbols); - } + encode_array (output, weights_array, level_array, c_symbols, offset4, + total, scale); + Free (c_symbols); + } - debug_message ("%d delta weights out of %d.", delta_count, total); - debug_message ("weights: %5d bits. (%5d symbols => %5.2f bps)", - bits_processed (output) - bits, total, - (bits_processed (output) - bits) / (double) total); + debug_message ("%d delta weights out of %d.", delta_count, total); + debug_message ("weights: %5d bits. (%5d symbols => %5.2f bps)", + bits_processed (output) - bits, total, + (bits_processed (output) - bits) / (double) total); - Free (weights_array); - Free (level_array); + Free (weights_array); + Free (level_array); } + + + diff --git a/converter/other/fiasco/params.c b/converter/other/fiasco/params.c index 7a302b82..afacbada 100644 --- a/converter/other/fiasco/params.c +++ b/converter/other/fiasco/params.c @@ -30,6 +30,7 @@ #include /* system or ../lib */ +#include "pm_c_util.h" #include "nstring.h" #include "types.h" @@ -631,6 +632,8 @@ read_parameter_file (param_t *params, FILE *file) } } + + static void usage (const param_t *params, const char *progname, const char *synopsis, const char *comment, const char *non_opt_string, @@ -647,82 +650,84 @@ usage (const param_t *params, const char *progname, const char *synopsis, * No return value. */ { - int i; - size_t width = 0; + int i; + size_t width = 0; - fprintf (stderr, "Usage: %s [OPTION]...%s\n", progname, - non_opt_string ? non_opt_string : " "); - if (synopsis != NULL) - fprintf (stderr, synopsis); - fprintf (stderr, "\n\n"); - fprintf (stderr, "Mandatory or optional arguments to long options " - "are mandatory or optional\nfor short options too. " - "Default values are surrounded by {}.\n"); - for (i = 0; params [i].name != NULL; i++) - if (params [i].optchar != '\0' || show_all_options) - { - if (params [i].type == POSTR) - width = max (width, (strlen (params [i].name) - + strlen (params [i].argument_name) + 2)); - else if (params [i].type != PFLAG) - width = max (width, (strlen (params [i].name) - + strlen (params [i].argument_name))); - else - width = max (width, (strlen (params [i].name)) - 1); - } + fprintf (stderr, "Usage: %s [OPTION]...%s\n", progname, + non_opt_string ? non_opt_string : " "); + if (synopsis != NULL) + fprintf (stderr, "%s", synopsis); + fprintf (stderr, "\n\n"); + fprintf (stderr, "Mandatory or optional arguments to long options " + "are mandatory or optional\nfor short options too. " + "Default values are surrounded by {}.\n"); + for (i = 0; params [i].name != NULL; i++) + if (params [i].optchar != '\0' || show_all_options) + { + if (params [i].type == POSTR) + width = MAX(width, (strlen (params [i].name) + + strlen (params [i].argument_name) + 2)); + else if (params [i].type != PFLAG) + width = MAX(width, (strlen (params [i].name) + + strlen (params [i].argument_name))); + else + width = MAX(width, (strlen (params [i].name)) - 1); + } - for (i = 0; params [i].name != NULL; i++) - if (params [i].optchar != '\0' || show_all_options) - { - if (params [i].optchar != '\0') - fprintf (stderr, " -%c, --", params [i].optchar); - else - fprintf (stderr, " --"); + for (i = 0; params [i].name != NULL; i++) + if (params [i].optchar != '\0' || show_all_options) + { + if (params [i].optchar != '\0') + fprintf (stderr, " -%c, --", params [i].optchar); + else + fprintf (stderr, " --"); - if (params [i].type == POSTR) - fprintf (stderr, "%s=[%s]%-*s ", params [i].name, - params [i].argument_name, - max (0, (width - 2 - strlen (params [i].name) - - strlen (params [i].argument_name))), ""); - else if (params [i].type != PFLAG) - fprintf (stderr, "%s=%-*s ", params [i].name, - width - strlen (params [i].name), - params [i].argument_name); - else - fprintf (stderr, "%-*s ", width + 1, params [i].name); - - fprintf (stderr, params [i].use, params [i].argument_name); + if (params [i].type == POSTR) + fprintf (stderr, "%s=[%s]%-*s ", params [i].name, + params [i].argument_name, + (unsigned) + MAX(0, (width - 2 - strlen (params [i].name) + - strlen (params [i].argument_name))), ""); + else if (params [i].type != PFLAG) + fprintf (stderr, "%s=%-*s ", params [i].name, + (unsigned)(width - strlen (params [i].name)), + params [i].argument_name); + else + fprintf (stderr, "%-*s ", + (unsigned)(width + 1), params [i].name); + + fprintf (stderr, params [i].use, params [i].argument_name); - switch (params [i].type) - { - case PFLAG: - break; - case PINT: - fprintf (stderr, "{%d}", params [i].value.i); - break; - case PFLOAT: - fprintf (stderr, "{%.2f}", (double) params [i].value.f); - break; - case PSTR: - case POSTR: - if (params [i].value.s) - fprintf (stderr, "{%s}", params [i].value.s); - break; - default: - error ("type %d for %s invalid", - params [i].type, params [i].name); - } - fprintf (stderr, "\n"); - } - fprintf (stderr, "\n"); - fprintf (stderr, "Parameter initialization order:\n"); - fprintf (stderr, - "1.) %s\n2.) $HOME/%s\t 3.) command line\t 4.) --config=file", - sys_file_name, usr_file_name); - fprintf (stderr, "\n\n"); - if (comment != NULL) - fprintf (stderr, "%s\n", comment); - - exit (1); + switch (params [i].type) + { + case PFLAG: + break; + case PINT: + fprintf (stderr, "{%d}", params [i].value.i); + break; + case PFLOAT: + fprintf (stderr, "{%.2f}", (double) params [i].value.f); + break; + case PSTR: + case POSTR: + if (params [i].value.s) + fprintf (stderr, "{%s}", params [i].value.s); + break; + default: + error ("type %d for %s invalid", + params [i].type, params [i].name); + } + fprintf (stderr, "\n"); + } + fprintf (stderr, "\n"); + fprintf (stderr, "Parameter initialization order:\n"); + fprintf (stderr, + "1.) %s\n2.) $HOME/%s\t 3.) command line\t 4.) --config=file", + sys_file_name, usr_file_name); + fprintf (stderr, "\n\n"); + if (comment != NULL) + fprintf (stderr, "%s\n", comment); + + exit (1); } diff --git a/converter/other/fiasco/pnmtofiasco.c b/converter/other/fiasco/pnmtofiasco.c index 2218256d..eebd09a9 100644 --- a/converter/other/fiasco/pnmtofiasco.c +++ b/converter/other/fiasco/pnmtofiasco.c @@ -1,8 +1,8 @@ /* - * cwfa.c: FIASCO coder + * cwfa.c: FIASCO coder * - * Written by: Ullrich Hafner - * + * Written by: Ullrich Hafner + * * This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec) * Copyright (C) 1994-2000 Ullrich Hafner */ @@ -15,18 +15,12 @@ */ #include "config.h" +#include "pm_c_util.h" #include "pnm.h" -#if STDC_HEADERS -# include -# include -#else /* not STDC_HEADERS */ -# if HAVE_STRING_H -# include -# else /* not HAVE_STRING_H */ -# include -# endif /* not HAVE_STRING_H */ -#endif /* not STDC_HEADERS */ +#include +#include +#include #include "types.h" #include "macros.h" @@ -38,7 +32,7 @@ /***************************************************************************** - local variables + local variables *****************************************************************************/ @@ -144,27 +138,27 @@ static param_t params [] = /***************************************************************************** - prototypes + prototypes *****************************************************************************/ static void checkargs (int argc, char **argv, char const ***image_template, - char **wfa_name, float *quality, fiasco_c_options_t **options); + char **wfa_name, float *quality, fiasco_c_options_t **options); /***************************************************************************** - public code + public code *****************************************************************************/ int main (int argc, char **argv) { - char const **image_template; /* template for input image files */ - char *wfa_name; /* filename of output WFA */ - float quality; /* approximation quality */ - fiasco_c_options_t *options; /* additional coder options */ + char const **image_template; /* template for input image files */ + char *wfa_name; /* filename of output WFA */ + float quality; /* approximation quality */ + fiasco_c_options_t *options; /* additional coder options */ pnm_init(&argc, argv); @@ -176,7 +170,7 @@ main (int argc, char **argv) return 0; else { - fprintf (stderr, fiasco_get_error_message ()); + fprintf (stderr, "%s", fiasco_get_error_message ()); fprintf (stderr, "\n"); return 1; } @@ -184,228 +178,228 @@ main (int argc, char **argv) /***************************************************************************** - private code + private code *****************************************************************************/ static void checkargs (int argc, char **argv, char const ***image_template, - char **wfa_name, float *quality, fiasco_c_options_t **options) + char **wfa_name, float *quality, fiasco_c_options_t **options) /* * Check validness of command line parameters and of the parameter files. * * Return value: - * 1 on success - * 0 otherwise + * 1 on success + * 0 otherwise * * * Side effects: - * 'image_template', 'wfa_name', 'quality' and 'options' are set. + * 'image_template', 'wfa_name', 'quality' and 'options' are set. */ { - int optind; /* last processed commandline param */ - char *image_name; /* filename given by option '-i' */ - int i; /* counter */ + int optind; /* last processed commandline param */ + char *image_name; /* filename given by option '--input_name' */ + int i; /* counter */ - optind = parseargs (params, argc, argv, - "Compress raw PPM/PGM image FILEs to a FIASCO file.", - "With no image FILE, or if FILE is -, " - "read standard input.\n" - "FILE must be either a filename" - " or an image template of the form:\n" - "`prefix[start-end{+,-}step]suffix'\n" - "e.g., img0[12-01-1].pgm is substituted by" - " img012.pgm ... img001.pgm\n\n" - "Environment:\n" - "FIASCO_DATA Search and save path for FIASCO files. " - "Default: ./\n" - "FIASCO_IMAGES Search path for image files. " - "Default: ./", " [FILE]...", - FIASCO_SHARE, "system.fiascorc", ".fiascorc"); + optind = parseargs (params, argc, argv, + "Compress raw PPM/PGM image FILEs to a FIASCO file.", + "With no image FILE, or if FILE is -, " + "read standard input.\n" + "FILE must be either a filename" + " or an image template of the form:\n" + "`prefix[start-end{+,-}step]suffix'\n" + "e.g., img0[12-01-1].pgm is substituted by" + " img012.pgm ... img001.pgm\n\n" + "Environment:\n" + "FIASCO_DATA Search and save path for FIASCO files. " + "Default: ./\n" + "FIASCO_IMAGES Search path for image files. " + "Default: ./", " [FILE]...", + FIASCO_SHARE, "system.fiascorc", ".fiascorc"); - /* - * Default options ... - */ - image_name = (char *) parameter_value (params, "image-name"); - *wfa_name = (char *) parameter_value (params, "output-name"); - for (;;) - { - *quality = * (float *) parameter_value (params, "quality"); - if (*quality > 100) - fprintf (stderr, "Typical range of quality: (0,100].\n" - "Expect some trouble on slow machines.\n"); - if (*quality > 0) - break; - ask_and_set (params, "quality", - "Please enter coding quality 'q' ('q' > 0): "); - } + /* + * Default options ... + */ + image_name = (char *) parameter_value (params, "image-name"); + *wfa_name = (char *) parameter_value (params, "output-name"); + for (;;) + { + *quality = * (float *) parameter_value (params, "quality"); + if (*quality > 100) + fprintf (stderr, "Typical range of quality: (0,100].\n" + "Expect some trouble on slow machines.\n"); + if (*quality > 0) + break; + ask_and_set (params, "quality", + "Please enter coding quality 'q' ('q' > 0): "); + } - if (optind < argc) /* Additional command line param */ - { - if (image_name) - error ("Multiple image_template arguments." - "\nOption -i %s already specified!", image_name); + if (optind < argc) /* Additional command line param */ + { + if (image_name) + error ("Multiple image_template arguments." + "\nOption --input-name %s already specified!", image_name); - *image_template = calloc (argc - optind + 1, sizeof (char *)); - if (!*image_template) - error ("Out of memory."); - for (i = 0; optind < argc; i++, optind++) - (*image_template) [i] = argv [optind]; - (*image_template) [i] = NULL; - } - else /* option -i image_name */ - { - *image_template = calloc (2, sizeof (char *)); - if (!*image_template) - error ("Out of memory."); - (*image_template) [0] = image_name; - (*image_template) [1] = NULL; - } - /* - * Additional options ... (have to be set with the fiasco_set_... methods) - */ - { - *options = fiasco_c_options_new (); + *image_template = calloc (argc - optind + 1, sizeof (char *)); + if (!*image_template) + error ("Out of memory."); + for (i = 0; optind < argc; i++, optind++) + (*image_template) [i] = argv [optind]; + (*image_template) [i] = NULL; + } + else /* option -i image_name */ + { + *image_template = calloc (2, sizeof (char *)); + if (!*image_template) + error ("Out of memory."); + (*image_template) [0] = image_name; + (*image_template) [1] = NULL; + } + /* + * Additional options ... (have to be set with the fiasco_set_... methods) + */ + { + *options = fiasco_c_options_new (); - { - char *pattern = (char *) parameter_value (params, "pattern"); + { + char *pattern = (char *) parameter_value (params, "pattern"); - if (!fiasco_c_options_set_frame_pattern (*options, pattern)) - error (fiasco_get_error_message ()); - } + if (!fiasco_c_options_set_frame_pattern (*options, pattern)) + error (fiasco_get_error_message ()); + } - { - char *basis = (char *) parameter_value (params, "basis-name"); - - if (!fiasco_c_options_set_basisfile (*options, basis)) - error (fiasco_get_error_message ()); - } + { + char *basis = (char *) parameter_value (params, "basis-name"); + + if (!fiasco_c_options_set_basisfile (*options, basis)) + error (fiasco_get_error_message ()); + } - { - int n = * (int *) parameter_value (params, "chroma-dictionary"); - float q = * (float *) parameter_value (params, "chroma-qfactor"); + { + int n = * (int *) parameter_value (params, "chroma-dictionary"); + float q = * (float *) parameter_value (params, "chroma-qfactor"); - if (!fiasco_c_options_set_chroma_quality (*options, q, max (0, n))) - error (fiasco_get_error_message ()); - } + if (!fiasco_c_options_set_chroma_quality (*options, q, MAX(0, n))) + error (fiasco_get_error_message ()); + } - { - int n = *((int *) parameter_value (params, "smooth")); - - if (!fiasco_c_options_set_smoothing (*options, max (0, n))) - error (fiasco_get_error_message ()); - } + { + int n = *((int *) parameter_value (params, "smooth")); + + if (!fiasco_c_options_set_smoothing (*options, MAX(0, n))) + error (fiasco_get_error_message ()); + } - { - int n = * (int *) parameter_value (params, "progress-meter"); - fiasco_progress_e type = (n < 0) ? - FIASCO_PROGRESS_NONE : (fiasco_progress_e) n; + { + int n = * (int *) parameter_value (params, "progress-meter"); + fiasco_progress_e type = (n < 0) ? + FIASCO_PROGRESS_NONE : (fiasco_progress_e) n; - if (!fiasco_c_options_set_progress_meter (*options, type)) - error (fiasco_get_error_message ()); - } + if (!fiasco_c_options_set_progress_meter (*options, type)) + error (fiasco_get_error_message ()); + } - { - char *t = (char *) parameter_value (params, "title"); - - if (strlen (t) > 0 && !fiasco_c_options_set_title (*options, t)) - error (fiasco_get_error_message ()); - } + { + char *t = (char *) parameter_value (params, "title"); + + if (strlen (t) > 0 && !fiasco_c_options_set_title (*options, t)) + error (fiasco_get_error_message ()); + } - { - char *c = (char *) parameter_value (params, "comment"); + { + char *c = (char *) parameter_value (params, "comment"); - if (strlen (c) > 0 && !fiasco_c_options_set_comment (*options, c)) - error (fiasco_get_error_message ()); - } + if (strlen (c) > 0 && !fiasco_c_options_set_comment (*options, c)) + error (fiasco_get_error_message ()); + } - { - fiasco_tiling_e method = FIASCO_TILING_VARIANCE_DSC; - int e = * (int *) parameter_value (params, "tiling-exponent"); - char *m = (char *) parameter_value (params, "tiling-method"); + { + fiasco_tiling_e method = FIASCO_TILING_VARIANCE_DSC; + int e = * (int *) parameter_value (params, "tiling-exponent"); + char *m = (char *) parameter_value (params, "tiling-method"); - if (strcaseeq (m, "desc-variance")) - method = FIASCO_TILING_VARIANCE_DSC; - else if (strcaseeq (m, "asc-variance")) - method = FIASCO_TILING_VARIANCE_ASC; - else if (strcaseeq (m, "asc-spiral")) - method = FIASCO_TILING_SPIRAL_ASC; - else if (strcaseeq (m, "dsc-spiral")) - method = FIASCO_TILING_SPIRAL_DSC; - else - error (_("Invalid tiling method `%s' specified."), m); + if (strcaseeq (m, "desc-variance")) + method = FIASCO_TILING_VARIANCE_DSC; + else if (strcaseeq (m, "asc-variance")) + method = FIASCO_TILING_VARIANCE_ASC; + else if (strcaseeq (m, "asc-spiral")) + method = FIASCO_TILING_SPIRAL_ASC; + else if (strcaseeq (m, "dsc-spiral")) + method = FIASCO_TILING_SPIRAL_DSC; + else + error (_("Invalid tiling method `%s' specified."), m); - if (!fiasco_c_options_set_tiling (*options, method, max (0, e))) - error (fiasco_get_error_message ()); - } + if (!fiasco_c_options_set_tiling (*options, method, MAX(0, e))) + error (fiasco_get_error_message ()); + } - { - int M/* = * (int *) parameter_value (params, "max-level") */; - int m/* = * (int *) parameter_value (params, "min-level") */; - int N/* = * (int *) parameter_value (params, "max-elements") */; - int D = * (int *) parameter_value (params, "dictionary-size"); - int o = * (int *) parameter_value (params, "optimize"); + { + int M/* = * (int *) parameter_value (params, "max-level") */; + int m/* = * (int *) parameter_value (params, "min-level") */; + int N/* = * (int *) parameter_value (params, "max-elements") */; + int D = * (int *) parameter_value (params, "dictionary-size"); + int o = * (int *) parameter_value (params, "optimize"); - if (o <= 0) - { - o = 0; - M = 10; - m = 6; - N = 3; - } - else - { - o -= 1; - M = 12; - m = 4; - N = 5; - } - - if (!fiasco_c_options_set_optimizations (*options, m, M, N, - max (0, D), o)) - error (fiasco_get_error_message ()); - } - { - int M = * (int *) parameter_value (params, "max-level"); - int m = * (int *) parameter_value (params, "min-level"); - int p = * (int *) parameter_value (params, "prediction"); - - if (!fiasco_c_options_set_prediction (*options, - p, max (0, m), max (0, M))) - error (fiasco_get_error_message ()); - } - { - float r = * (float *) parameter_value (params, "rpf-range"); - float dc_r = * (float *) parameter_value (params, "dc-rpf-range"); - int m = * (int *) parameter_value (params, "rpf-mantissa"); - int dc_m = * (int *) parameter_value (params, "dc-rpf-mantissa"); - fiasco_rpf_range_e range, dc_range; - - if (r < 1) - range = FIASCO_RPF_RANGE_0_75; - else if (r < 1.5) - range = FIASCO_RPF_RANGE_1_00; - else if (r < 2.0) - range = FIASCO_RPF_RANGE_1_50; - else - range = FIASCO_RPF_RANGE_2_00; - - if (dc_r < 1) - dc_range = FIASCO_RPF_RANGE_0_75; - else if (dc_r < 1.5) - dc_range = FIASCO_RPF_RANGE_1_00; - else if (dc_r < 2.0) - dc_range = FIASCO_RPF_RANGE_1_50; - else - dc_range = FIASCO_RPF_RANGE_2_00; - - if (!fiasco_c_options_set_quantization (*options, - max (0, m), range, - max (0, dc_m), dc_range)) - error (fiasco_get_error_message ()); - } + if (o <= 0) + { + o = 0; + M = 10; + m = 6; + N = 3; + } + else + { + o -= 1; + M = 12; + m = 4; + N = 5; + } + + if (!fiasco_c_options_set_optimizations (*options, m, M, N, + MAX(0, D), o)) + error (fiasco_get_error_message ()); + } + { + int M = * (int *) parameter_value (params, "max-level"); + int m = * (int *) parameter_value (params, "min-level"); + int p = * (int *) parameter_value (params, "prediction"); + + if (!fiasco_c_options_set_prediction (*options, + p, MAX(0, m), MAX(0, M))) + error (fiasco_get_error_message ()); + } + { + float r = * (float *)parameter_value(params, "rpf-range"); + float dc_r = * (float *)parameter_value(params, "dc-rpf-range"); + int m = * (int *) parameter_value(params, "rpf-mantissa"); + int dc_m = * (int *) parameter_value(params, "dc-rpf-mantissa"); + fiasco_rpf_range_e range, dc_range; + + if (r < 1) + range = FIASCO_RPF_RANGE_0_75; + else if (r < 1.5) + range = FIASCO_RPF_RANGE_1_00; + else if (r < 2.0) + range = FIASCO_RPF_RANGE_1_50; + else + range = FIASCO_RPF_RANGE_2_00; + + if (dc_r < 1) + dc_range = FIASCO_RPF_RANGE_0_75; + else if (dc_r < 1.5) + dc_range = FIASCO_RPF_RANGE_1_00; + else if (dc_r < 2.0) + dc_range = FIASCO_RPF_RANGE_1_50; + else + dc_range = FIASCO_RPF_RANGE_2_00; + + if (!fiasco_c_options_set_quantization (*options, + MAX(0, m), range, + MAX(0, dc_m), dc_range)) + error (fiasco_get_error_message ()); + } - if (fiasco_get_verbosity () == FIASCO_ULTIMATE_VERBOSITY) - write_parameters (params, stderr); - } -} + if (fiasco_get_verbosity () == FIASCO_ULTIMATE_VERBOSITY) + write_parameters (params, stderr); + } +} diff --git a/converter/other/fitstopnm.c b/converter/other/fitstopnm.c index 73564c4b..bdf5c78a 100644 --- a/converter/other/fitstopnm.c +++ b/converter/other/fitstopnm.c @@ -34,10 +34,16 @@ The official specification of FITS format (which is for more than just visual images) is at ftp://legacy.gsfc.nasa.gov/fits_info/fits_office/fits_standard.pdf + + An example FITS file is at + + http://fits.gsfc.nasa.gov/nrao_data/tests/incunabula/mndrll-8.fits + */ #include #include +#include #include "pm_config.h" #include "pm_c_util.h" @@ -48,7 +54,7 @@ -struct cmdlineInfo { +struct CmdlineInfo { const char * inputFileName; unsigned int image; /* zero if unspecified */ float max; @@ -69,8 +75,8 @@ struct cmdlineInfo { static void -parseCommandLine(int argc, char ** argv, - struct cmdlineInfo * const cmdlineP) { +parseCommandLine(int argc, const char ** argv, + struct CmdlineInfo * const cmdlineP) { /* -------------------------------------------------------------------------- Parse program command line described in Unix standard form by argc and argv. Return the information in the options as *cmdlineP. @@ -82,7 +88,7 @@ parseCommandLine(int argc, char ** argv, was passed to us as the argv array. We also trash *argv. --------------------------------------------------------------------------*/ optEntry * option_def; - /* Instructions to optParseOptions3 on how to parse our options. */ + /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; unsigned int imageSpec; @@ -114,7 +120,7 @@ parseCommandLine(int argc, char ** argv, /* Set some defaults the lazy way (using multiple setting of variables) */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, (char**)argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (imageSpec) { @@ -139,13 +145,17 @@ parseCommandLine(int argc, char ** argv, pm_error("Too many arguments (%u). The only non-option argument " "is the input file name.", argc-1); } + free(option_def); } struct FITS_Header { int simple; /* basic format or not */ - int bitpix; /* number of bits per pixel */ + int bitpix; + /* number of bits per pixel, positive for integer, negative + for floating point + */ int naxis; /* number of axes */ int naxis1; /* number of points on axis 1 */ int naxis2; /* number of points on axis 2 */ @@ -157,6 +167,16 @@ struct FITS_Header { }; +typedef enum { + VF_CHAR, VF_SHORT, VF_LONG, VF_FLOAT, VF_DOUBLE +} valFmt; + +struct fitsRasterInfo { + valFmt valFmt; + double bzer; + double bscale; +}; + /* This code deals properly with integers, no matter what the byte order or integer size of the host machine. We handle sign extension manually to prevent problems with signed/unsigned characters. We read floating point @@ -276,34 +296,56 @@ readFitsDouble(FILE * const ifP, +static valFmt +valFmtFromBitpix(int const bitpix) { +/*---------------------------------------------------------------------------- + Return the format of a "value" in the FITS file, given the value + of the BITPIX header in the FITS file. + + BITPIX has a stupid format wherein it is fundamentally the number + of bits per value, but its sign indicates whether it is integer + or floating point. +-----------------------------------------------------------------------------*/ + switch (bitpix) { + case +8: return VF_CHAR; + case +16: return VF_SHORT; + case +32: return VF_LONG; + case -32: return VF_FLOAT; + case -64: return VF_DOUBLE; + default: + /* Every possibility is covered above. */ + assert(false); + return 0; /* quiet compiler warning */ + } +} + + + static void readVal(FILE * const ifP, - int const bitpix, + valFmt const fmt, double * const vP) { - switch (bitpix) { - case 8: + switch (fmt) { + case VF_CHAR: readFitsChar(ifP, vP); break; - case 16: + case VF_SHORT: readFitsShort(ifP, vP); break; - case 32: + case VF_LONG: readFitsLong(ifP, vP); break; - case -32: + case VF_FLOAT: readFitsFloat(ifP, vP); break; - case -64: + case VF_DOUBLE: readFitsDouble(ifP, vP); break; - - default: - pm_error("Strange bitpix value %d in readVal()", bitpix); } } @@ -419,7 +461,7 @@ scanImageForMinMax(FILE * const ifP, unsigned int const images, int const cols, int const rows, - unsigned int const bitpix, + valFmt const valFmt, double const bscale, double const bzer, unsigned int const imagenum, @@ -427,6 +469,9 @@ scanImageForMinMax(FILE * const ifP, double * const dataminP, double * const datamaxP) { + /* Note that a value in the file might be Not-A-Number. We ignore + such entries in computing the minimum and maximum for the image. + */ double dmax, dmin; unsigned int image; pm_filepos rasterPos; @@ -436,14 +481,12 @@ scanImageForMinMax(FILE * const ifP, pm_message("Scanning file for scaling parameters"); - switch (bitpix) { - case 8: fmaxval = 255.0; break; - case 16: fmaxval = 65535.0; break; - case 32: fmaxval = 4294967295.0; break; - case -32: fmaxval = FLT_MAX; break; - case -64: fmaxval = DBL_MAX; break; - default: - pm_error("unusual bits per pixel (%u), can't read", bitpix); + switch (valFmt) { + case VF_CHAR: fmaxval = 255.0; break; + case VF_SHORT: fmaxval = 65535.0; break; + case VF_LONG: fmaxval = 4294967295.0; break; + case VF_FLOAT: fmaxval = FLT_MAX; break; + case VF_DOUBLE: fmaxval = DBL_MAX; break; } dmax = -fmaxval; @@ -454,10 +497,11 @@ scanImageForMinMax(FILE * const ifP, unsigned int col; for (col = 0; col < cols; ++col) { double val; - readVal(ifP, bitpix, &val); + readVal(ifP, valFmt, &val); if (image == imagenum || multiplane ) { - dmax = MAX(dmax, val); - dmin = MIN(dmin, val); + /* Note: if 'val' is NaN, result is 2nd operand */ + dmax = MAX(val, dmax); + dmin = MIN(val, dmin); } } } @@ -509,7 +553,8 @@ computeMinMax(FILE * const ifP, if (datamin == -DBL_MAX || datamax == DBL_MAX) { double scannedDatamin, scannedDatamax; - scanImageForMinMax(ifP, images, cols, rows, h.bitpix, h.bscale, h.bzer, + scanImageForMinMax(ifP, images, cols, rows, + valFmtFromBitpix(h.bitpix), h.bscale, h.bzer, imagenum, multiplane, &scannedDatamin, &scannedDatamax); @@ -525,8 +570,8 @@ computeMinMax(FILE * const ifP, static xelval -determineMaxval(struct cmdlineInfo const cmdline, - struct FITS_Header const fitsHeader, +determineMaxval(struct CmdlineInfo const cmdline, + valFmt const valFmt, double const datamax, double const datamin) { @@ -535,7 +580,7 @@ determineMaxval(struct cmdlineInfo const cmdline, if (cmdline.omaxvalSpec) retval = cmdline.omaxval; else { - if (fitsHeader.bitpix < 0) { + if (valFmt == VF_FLOAT || valFmt == VF_DOUBLE) { /* samples are floating point, which means the resolution could be anything. So we just pick a convenient maxval of 255. Before Netpbm 10.20 (January 2004), we did @@ -561,16 +606,16 @@ determineMaxval(struct cmdlineInfo const cmdline, static void -convertPgmRaster(FILE * const ifP, - unsigned int const cols, - unsigned int const rows, - xelval const maxval, - unsigned int const desiredImage, - unsigned int const imageCount, - struct FITS_Header const fitsHdr, - double const scale, - double const datamin, - xel ** const xels) { +convertPgmRaster(FILE * const ifP, + unsigned int const cols, + unsigned int const rows, + xelval const maxval, + unsigned int const desiredImage, + unsigned int const imageCount, + struct fitsRasterInfo const rasterInfo, + double const scale, + double const datamin, + xel ** const xels) { /* Note: the FITS specification does not give the association between file position and image position (i.e. is the first pixel in the @@ -581,8 +626,7 @@ convertPgmRaster(FILE * const ifP, */ unsigned int image; - pm_message("Writing PPM file " - "(Probably not what you want - consider an -image option)"); + pm_message("writing PGM file"); for (image = 1; image <= desiredImage; ++image) { unsigned int row; @@ -594,10 +638,10 @@ convertPgmRaster(FILE * const ifP, unsigned int col; for (col = 0; col < cols; ++col) { double val; - readVal(ifP, fitsHdr.bitpix, &val); + readVal(ifP, rasterInfo.valFmt, &val); { double const t = scale * - (val * fitsHdr.bscale + fitsHdr.bzer - datamin); + (val * rasterInfo.bscale + rasterInfo.bzer - datamin); xelval const tx = MAX(0, MIN(t, maxval)); if (image == desiredImage) PNM_ASSIGN1(xels[row][col], tx); @@ -610,14 +654,14 @@ convertPgmRaster(FILE * const ifP, static void -convertPpmRaster(FILE * const ifP, - unsigned int const cols, - unsigned int const rows, - xelval const maxval, - struct FITS_Header const fitsHdr, - double const scale, - double const datamin, - xel ** const xels) { +convertPpmRaster(FILE * const ifP, + unsigned int const cols, + unsigned int const rows, + xelval const maxval, + struct fitsRasterInfo const rasterInfo, + double const scale, + double const datamin, + xel ** const xels) { /*---------------------------------------------------------------------------- Read the FITS raster from file *ifP into xels[][]. Image dimensions are 'cols' by 'rows'. The FITS raster is 3 planes composing one @@ -625,7 +669,8 @@ convertPpmRaster(FILE * const ifP, -----------------------------------------------------------------------------*/ unsigned int plane; - pm_message("writing PPM file"); + pm_message("Writing PPM file " + "(Probably not what you want - consider an -image option)"); for (plane = 0; plane < 3; ++plane) { unsigned int row; @@ -635,10 +680,10 @@ convertPpmRaster(FILE * const ifP, unsigned int col; for (col = 0; col < cols; ++col) { double val; - readVal(ifP, fitsHdr.bitpix, &val); + readVal(ifP, rasterInfo.valFmt, &val); { double const t = scale * - (val * fitsHdr.bscale + fitsHdr.bzer - datamin); + (val * rasterInfo.bscale + rasterInfo.bzer - datamin); xelval const sample = MAX(0, MIN(t, maxval)); switch (plane) { @@ -655,17 +700,17 @@ convertPpmRaster(FILE * const ifP, static void -convertRaster(FILE * const ifP, - unsigned int const cols, - unsigned int const rows, - xelval const maxval, - bool const forceplain, - bool const multiplane, - unsigned int const desiredImage, - unsigned int const imageCount, - struct FITS_Header const fitsHdr, - double const scale, - double const datamin) { +convertRaster(FILE * const ifP, + unsigned int const cols, + unsigned int const rows, + xelval const maxval, + bool const forceplain, + bool const multiplane, + unsigned int const desiredImage, + unsigned int const imageCount, + struct fitsRasterInfo const rasterInfo, + double const scale, + double const datamin) { xel ** xels; int format; @@ -674,12 +719,12 @@ convertRaster(FILE * const ifP, if (multiplane) { format = PPM_FORMAT; - convertPpmRaster(ifP, cols, rows, maxval, fitsHdr, scale, datamin, + convertPpmRaster(ifP, cols, rows, maxval, rasterInfo, scale, datamin, xels); } else { format = PGM_FORMAT; convertPgmRaster(ifP, cols, rows, maxval, - desiredImage, imageCount, fitsHdr, scale, datamin, + desiredImage, imageCount, rasterInfo, scale, datamin, xels); } pnm_writepnm(stdout, xels, cols, rows, maxval, format, forceplain); @@ -689,15 +734,16 @@ convertRaster(FILE * const ifP, int -main(int argc, char * argv[]) { +main(int argc, const char * argv[]) { - struct cmdlineInfo cmdline; + struct CmdlineInfo cmdline; FILE * ifP; unsigned int cols, rows; xelval maxval; double scale; double datamin, datamax; struct FITS_Header fitsHeader; + struct fitsRasterInfo rasterInfo; unsigned int imageCount; unsigned int desiredImage; @@ -709,7 +755,7 @@ main(int argc, char * argv[]) { is undefined */ - pnm_init( &argc, argv ); + pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); @@ -726,6 +772,10 @@ main(int argc, char * argv[]) { cols = fitsHeader.naxis1; rows = fitsHeader.naxis2; + rasterInfo.bscale = fitsHeader.bscale; + rasterInfo.bzer = fitsHeader.bzer; + rasterInfo.valFmt = valFmtFromBitpix(fitsHeader.bitpix); + interpretPlanes(fitsHeader, cmdline.image, cmdline.verbose, &imageCount, &multiplane, &desiredImage); @@ -735,7 +785,7 @@ main(int argc, char * argv[]) { cmdline.min, cmdline.max, &datamin, &datamax); - maxval = determineMaxval(cmdline, fitsHeader, datamax, datamin); + maxval = determineMaxval(cmdline, rasterInfo.valFmt, datamax, datamin); if (datamax - datamin == 0) scale = 1.0; @@ -747,10 +797,13 @@ main(int argc, char * argv[]) { else convertRaster(ifP, cols, rows, maxval, cmdline.noraw, multiplane, desiredImage, imageCount, - fitsHeader, scale, datamin); + rasterInfo, scale, datamin); pm_close(ifP); pm_close(stdout); return 0; } + + + diff --git a/converter/other/giftopnm.c b/converter/other/giftopnm.c index 4b8b0487..2e6ae1d9 100644 --- a/converter/other/giftopnm.c +++ b/converter/other/giftopnm.c @@ -8,8 +8,9 @@ /* | provided "as is" without express or implied warranty. | */ /* +-------------------------------------------------------------------+ */ -/* There is a copy of the GIF89 specification, as defined by its - inventor, Compuserve, in 1989, at http://members.aol.com/royalef/gif89a.txt +/* There is a copy of the GIF89 specification, as defined by its inventor, + Compuserve, in 1990 at: + http://www.w3.org/Graphics/GIF/spec-gif89a.txt This covers the high level format, but does not cover how the "data" contents of a GIF image represent the raster of color table indices. @@ -18,8 +19,8 @@ describe the Lempel-Ziv base. */ -#define _BSD_SOURCE /* Make sure strcasecmp() is in string.h */ - +#define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */ +#define _BSD_SOURCE /* for strcaseeq */ #include #include @@ -38,28 +39,24 @@ #define MAX_LZW_BITS 12 -#define INTERLACE 0x40 -#define LOCALCOLORMAP 0x80 -#define BitSet(byte, bit) (((byte) & (bit)) == (bit)) - #if !defined(BYTE_ORDER) || !defined(LITTLE_ENDIAN) /* make sure (BYTE_ORDER == LITTLE_ENDIAN) is FALSE */ #define BYTE_ORDER 0 #define LITTLE_ENDIAN 1 #endif +#ifndef FASTPBMRENDER + #define FASTPBMRENDER TRUE +#endif -static __inline__ bool -ReadOK(FILE * const fileP, - unsigned char * const buffer, - size_t const len) { - - size_t bytesRead; +static const bool useFastPbmRender = FASTPBMRENDER; - bytesRead = fread(buffer, len, 1, fileP); +#ifndef REPORTLZWCODES + #define REPORTLZWCODES FALSE +#endif - return (bytesRead != 0); -} +static const bool wantLzwCodes = REPORTLZWCODES; + /* In verbose output, include all the LZW codes */ @@ -71,41 +68,37 @@ readFile(FILE * const ifP, size_t bytesRead; - bytesRead = fread(buffer, len, 1, ifP); + bytesRead = fread(buffer, 1, len, ifP); if (bytesRead == len) *errorP = NULL; else { if (ferror(ifP)) - asprintfN(errorP, "Error reading file. errno=%d (%s)", - errno, strerror(errno)); + pm_asprintf(errorP, "Error reading file. errno=%d (%s)", + errno, strerror(errno)); else if (feof(ifP)) - asprintfN(errorP, "End of file encountered"); + pm_asprintf(errorP, "End of file encountered"); else - asprintfN(errorP, "Short read -- %u bytes of %u", - (unsigned)bytesRead, (unsigned)len); + pm_asprintf(errorP, "Short read -- %u bytes of %u", + (unsigned)bytesRead, (unsigned)len); } } -#define LM_to_uint(a,b) (((b)<<8)|(a)) - -static int const maxnum_lzwCode = (1<repair, 0); OPTENT3(0, "image", OPT_STRING, &image, &imageSpec, 0); - OPTENT3(0, "alphaout", OPT_STRING, &cmdlineP->alpha_filename, + OPTENT3(0, "alphaout", OPT_STRING, &cmdlineP->alphaFileName, &alphaSpec, 0); opt.opt_table = option_def; opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3( &argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + free(option_def); + if (!imageSpec) { - cmdlineP->image_no = 0; - cmdlineP->all_images = FALSE; + cmdlineP->imageNum = 0; + cmdlineP->allImages = FALSE; } else { - if (strcasecmp(image, "all") == 0) - cmdlineP->all_images = TRUE; - else { + if (strcaseeq(image, "all")) { + cmdlineP->allImages = TRUE; + } else { char * tailptr; - long const imageNo = strtol(image, &tailptr, 10); + long const imageNum = strtol(image, &tailptr, 10); if (*tailptr != '\0') pm_error("Invalid value for '-image' option. Must be either " "a number or 'all'. You specified '%s'", image); - else if (imageNo < 0) + else if (imageNum < 0) pm_error("Invalid value for '-image' option. Must be " - "positive. You specified %ld", imageNo); - else if (imageNo == 0) + "positive. You specified %ld", imageNum); + else if (imageNum == 0) pm_error("Invalid value for 'image' option. You specified " "zero. The first image is 1."); - cmdlineP->all_images = FALSE; - cmdlineP->image_no = (unsigned int) imageNo - 1; + cmdlineP->allImages = FALSE; + cmdlineP->imageNum = (unsigned int) imageNum - 1; } } if (argc-1 == 0) - cmdlineP->input_filespec = "-"; + cmdlineP->inputFilespec = "-"; else if (argc-1 != 1) pm_error("Program takes zero or one argument (filename). You " "specified %d", argc-1); else - cmdlineP->input_filespec = argv[1]; + cmdlineP->inputFilespec = argv[1]; if (!alphaSpec) - cmdlineP->alpha_filename = NULL; + cmdlineP->alphaFileName = NULL; } -typedef unsigned char gifColorMap[3][MAXCOLORMAPSIZE]; -struct gifScreen { - unsigned int Width; - unsigned int Height; - gifColorMap ColorMap; - unsigned int ColorMapSize; - /* Number of colors in the color map. */ - unsigned int ColorResolution; - unsigned int Background; - unsigned int AspectRatio; +typedef struct { + unsigned char map[MAXCOLORMAPSIZE][3]; + unsigned int size; +} GifColorMap; + +/*---------------------------------------------------------------------- + On GIF color maps: + + The color map can have any number of colors up to 256. If the color map + size is not a power of 2 the table is padded up. The LZW "clear" control + code is always placed at a power of 2. + + The color map and code table of an image with three colors (black, white + and red) will look like this: + + 0: black + 1: white + 2: red + 3: (unused) + 4: clear code + 5: end code + 6: first LZW string code + 7: second LZW string code + ... + 4095: last LZW string code + + Some GIFs have odd color maps. + + (1) Some encoders use fixed color maps. A GIF image produced by this + kind of encoder may have colors in the table which never appear in + the image. + + Note that we make the decision on whether the output should be PBM, + PGM or PPM by scanning through the color map, not the entire image. + Any unused colors will influence our decision. + + (2) There are GIF editors which allow one to rewrite the color map. + These programs will produce color maps with multiple entries for the + same color. + + (3) Some encoders put the transparent code outside the color map. + (In the above example, the unused value 3.) Around 2000 there were + several encoders that did this, including "Animation Gif Maker + (GifAnim)". As of 2012, such images are rare. We reject them with + an error message unless -repair is specified. +-----------------------------------------------------------------------*/ + + +struct GifScreen { + unsigned int width; + unsigned int height; + bool hasGlobalColorMap; + /* The stream has a global color map, to wit 'colorMap'. + (If the stream doesn't have a global color map, the individual + images must each have a local color map) + */ + GifColorMap colorMap; + /* The global color map for the stream. Meaningful only if + 'hasGlobalColorMap' is true. + */ + unsigned int colorResolution; + unsigned int background; + unsigned int aspectRatio; /* Aspect ratio of each pixel, times 64, minus 15. (i.e. 1 => 1:4). But Zero means 1:1. */ - int hasGray; + bool hasGray; /* Boolean: global colormap has at least one gray color (not counting black and white) */ - int hasColor; + bool hasColor; /* Boolean: global colormap has at least one non-gray, non-black, non-white color */ }; -struct gif89 { - int transparent; - int delayTime; - int inputFlag; - int disposal; +struct Gif89 { + bool haveTransColor; + /* The GIF specifies a transparent background color */ + unsigned int transparentIndex; + /* The color index of the color which is the transparent + background color. + + Meaningful only when 'haveTransColor' is true + */ + bool haveDelayTime; + unsigned int delayTime; + bool haveInputFlag; + unsigned char inputFlag; + bool haveDisposal; + unsigned char disposal; }; static void -initGif89(struct gif89 * const gif89P) { - gif89P->transparent = -1; - gif89P->delayTime = -1; - gif89P->inputFlag = -1; - gif89P->disposal = -1; +initGif89(struct Gif89 * const gif89P) { + gif89P->haveTransColor = false; + gif89P->haveDelayTime = false; + gif89P->haveInputFlag = false; + gif89P->haveDisposal = false; } -static int verbose; -int showComment; +static bool verbose; +static bool showComment; static void -readColorMap(FILE *ifP, const int colormapsize, - unsigned char colormap[3][MAXCOLORMAPSIZE], - int *hasGrayP, int * const hasColorP) { +readColorMap(FILE * const ifP, + unsigned int const cmapSize, + GifColorMap * const cmapP, + bool * const hasGrayP, + bool * const hasColorP) { +/*---------------------------------------------------------------------------- + Read a color map from a GIF stream, where the stream is on *ifP, + which is positioned to a color map, which is 'cmapSize' bytes long. - int i; - unsigned char rgb[3]; + Return as *cmapP that color map. - assert(colormapsize <= MAXCOLORMAPSIZE); + Furthermore, analyze that color map and return *hasGrayP == true iff it + contains any gray (black and white don't count) and *hasColorP == true iff + it contains anything that is not gray or black or white. +-----------------------------------------------------------------------------*/ + unsigned int i; + unsigned char rgb[3]; + + assert(cmapSize <= MAXCOLORMAPSIZE); *hasGrayP = FALSE; /* initial assumption */ *hasColorP = FALSE; /* initial assumption */ - for (i = 0; i < colormapsize; ++i) { - if (! ReadOK(ifP, rgb, sizeof(rgb))) - pm_error("Unable to read Color %d from colormap", i); + for (i = 0; i < cmapSize; ++i) { + const char * error; + readFile(ifP, rgb, sizeof(rgb), &error); + if (error) + pm_error("Unable to read Color %u from colormap. %s", i, error); - colormap[CM_RED][i] = rgb[0] ; - colormap[CM_GRN][i] = rgb[1] ; - colormap[CM_BLU][i] = rgb[2] ; + cmapP->map[i][CM_RED] = rgb[0] ; + cmapP->map[i][CM_GRN] = rgb[1] ; + cmapP->map[i][CM_BLU] = rgb[2] ; if (rgb[0] == rgb[1] && rgb[1] == rgb[2]) { if (rgb[0] != 0 && rgb[0] != GIFMAXVAL) @@ -264,6 +335,7 @@ readColorMap(FILE *ifP, const int colormapsize, } else *hasColorP = TRUE; } + cmapP->size = cmapSize; } @@ -295,13 +367,17 @@ getDataBlock(FILE * const ifP, If we hit EOF or have an I/O error reading the data portion of the DataBlock, we exit the program with pm_error(). -----------------------------------------------------------------------------*/ + long const pos = ftell(ifP); + unsigned char count; - bool successfulRead; + const char * error; - long const pos = ftell(ifP); - successfulRead = ReadOK(ifP, &count, 1); - if (!successfulRead) { - pm_message("EOF or error in reading DataBlock size from file" ); + readFile(ifP, &count, sizeof(count), &error); + + if (error) { + pm_message("EOF or error in reading DataBlock size from file. %s", + error); + pm_strfree(error); *errorP = NULL; *eofP = TRUE; *lengthP = 0; @@ -315,17 +391,18 @@ getDataBlock(FILE * const ifP, *errorP = NULL; zeroDataBlock = TRUE; } else { - bool successfulRead; + const char * error; zeroDataBlock = FALSE; - successfulRead = ReadOK(ifP, buf, count); + readFile(ifP, buf, count, &error); - if (successfulRead) + if (error) { + pm_asprintf(errorP, + "Unable to read data portion of %u byte " + "DataBlock from file. %s", count, error); + pm_strfree(error); + } else *errorP = NULL; - else - asprintfN(errorP, - "EOF or error reading data portion of %u byte " - "DataBlock from file", count); } } } @@ -341,7 +418,7 @@ readThroughEod(FILE * const ifP) { If there is no EOD marker between the present file position and EOF, we read to EOF and issue warning message about a missing EOD marker. -----------------------------------------------------------------------------*/ - unsigned char buf[260]; + unsigned char buf[256]; bool eod; eod = FALSE; /* initial value */ @@ -363,6 +440,27 @@ readThroughEod(FILE * const ifP) { +static void +doPlainTextExtension(FILE * const ifP) { +#if 0 + /* incomplete code fragment, attempt to handle Plain Text Extension */ + GetDataBlock(ifP, (unsigned char*) buf, &eof, &length); + + lpos = LM_to_uint(buf[0], buf[1]); + tpos = LM_to_uint(buf[2], buf[3]); + width = LM_to_uint(buf[4], buf[5]); + height = LM_to_uint(buf[6], buf[7]); + cellw = buf[8]; + cellh = buf[9]; + foreground = buf[10]; + background = buf[11]; +#else + readThroughEod(ifP); +#endif +} + + + static void doCommentExtension(FILE * const ifP) { /*---------------------------------------------------------------------------- @@ -373,7 +471,7 @@ doCommentExtension(FILE * const ifP) { it could have nonprintable characters or embedded nulls. I don't know if the GIF spec requires regular text or not. -----------------------------------------------------------------------------*/ - char buf[255+1]; + char buf[256]; unsigned int blocklen; bool done; @@ -398,13 +496,22 @@ doCommentExtension(FILE * const ifP) { +static unsigned int +LM_to_uint(unsigned char const a, + unsigned char const b) { + + return ((unsigned int)b << 8) | ((unsigned int) a << 0); +} + + + static void doGraphicControlExtension(FILE * const ifP, - struct gif89 * const gif89P) { + struct Gif89 * const gif89P) { bool eof; unsigned int length; - static unsigned char buf[256]; + unsigned char buf[256]; const char * error; getDataBlock(ifP, buf, &eof, &length, &error); @@ -418,11 +525,16 @@ doGraphicControlExtension(FILE * const ifP, "It must be at least 4 bytes; it is %d bytes.", length); else { + gif89P->haveDisposal = true; gif89P->disposal = (buf[0] >> 2) & 0x7; + gif89P->haveInputFlag = true; gif89P->inputFlag = (buf[0] >> 1) & 0x1; - gif89P->delayTime = LM_to_uint(buf[1],buf[2]); - if ((buf[0] & 0x1) != 0) - gif89P->transparent = buf[3]; + gif89P->haveDelayTime = true; + gif89P->delayTime = LM_to_uint(buf[1], buf[2]); + if ((buf[0] & 0x1) != 0) { + gif89P->haveTransColor = true; + gif89P->transparentIndex = buf[3]; + } readThroughEod(ifP); } } @@ -430,34 +542,16 @@ doGraphicControlExtension(FILE * const ifP, static void -doExtension(FILE * const ifP, int const label, struct gif89 * const gif89P) { +doExtension(FILE * const ifP, + unsigned char const label, + struct Gif89 * const gif89P) { + const char * str; switch (label) { case 0x01: /* Plain Text Extension */ str = "Plain Text"; -#ifdef notdef - GetDataBlock(ifP, (unsigned char*) buf, &eof, &length); - - lpos = LM_to_uint(buf[0], buf[1]); - tpos = LM_to_uint(buf[2], buf[3]); - width = LM_to_uint(buf[4], buf[5]); - height = LM_to_uint(buf[6], buf[7]); - cellw = buf[8]; - cellh = buf[9]; - foreground = buf[10]; - background = buf[11]; - - while (GetDataBlock(ifP, (unsigned char*) buf) != 0) { - PPM_ASSIGN(xels[ypos][xpos], - cmap[CM_RED][v], - cmap[CM_GRN][v], - cmap[CM_BLU][v]); - ++index; - } -#else - readThroughEod(ifP); -#endif + doPlainTextExtension(ifP); break; case 0xff: /* Application Extension */ str = "Application"; @@ -472,21 +566,20 @@ doExtension(FILE * const ifP, int const label, struct gif89 * const gif89P) { doGraphicControlExtension(ifP, gif89P); break; default: { - static char buf[256]; - str = buf; + char buf[256]; sprintf(buf, "UNKNOWN (0x%02x)", label); + str = buf; pm_message("Ignoring unrecognized extension (type 0x%02x)", label); readThroughEod(ifP); - } - break; + } break; } if (verbose) - pm_message(" got a '%s' extension", str ); + pm_message(" got a '%s' extension", str); } -struct getCodeState { +struct GetCodeState { unsigned char buf[280]; /* This is the buffer through which we read the data from the stream. We must buffer it because we have to read whole data @@ -512,11 +605,11 @@ struct getCodeState { static void getAnotherBlock(FILE * const ifP, - struct getCodeState * const gsP, + struct GetCodeState * const gsP, const char ** const errorP) { unsigned int count; - unsigned int assumed_count; + unsigned int assumedCount; bool eof; /* Shift buffer down so last two bytes are now the @@ -541,22 +634,22 @@ getAnotherBlock(FILE * const ifP, "file is malformed, but we are proceeding " "anyway as if an EOD marker were at the end " "of the file."); - assumed_count = 0; + assumedCount = 0; } else - assumed_count = count; + assumedCount = count; - gsP->streamExhausted = (assumed_count == 0); + gsP->streamExhausted = (assumedCount == 0); - gsP->bufCount += assumed_count; + gsP->bufCount += assumedCount; } } -static struct getCodeState getCodeState; +static struct GetCodeState getCodeState; static void -getCode_init(struct getCodeState * const getCodeStateP) { +getCode_init(struct GetCodeState * const getCodeStateP) { /* Fake a previous data block */ getCodeStateP->buf[0] = 0; @@ -608,7 +701,7 @@ bitsOfLeBuffer(const unsigned char * const buf, static void -getCode_get(struct getCodeState * const gsP, +getCode_get(struct GetCodeState * const gsP, FILE * const ifP, int const codeSize, bool * const eofP, @@ -661,6 +754,9 @@ getCode_get(struct getCodeState * const gsP, } else { *codeP = bitsOfLeBuffer(gsP->buf, gsP->curbit, codeSize); + if (verbose && wantLzwCodes) + pm_message("LZW code=0x%03x [%d]", *codeP, codeSize); + gsP->curbit += codeSize; *eofP = FALSE; } @@ -669,18 +765,17 @@ getCode_get(struct getCodeState * const gsP, - -struct stack { +struct Stack { /* Stack grows from low addresses to high addresses */ - int * stack; /* malloc'ed array */ - int * sp; /* stack pointer */ - int * top; /* next word above top of stack */ + unsigned char * stack; /* malloc'ed array */ + unsigned char * sp; /* stack pointer */ + unsigned char * top; /* next word above top of stack */ }; static void -initStack(struct stack * const stackP, unsigned int const size) { +initStack(struct Stack * const stackP, unsigned int const size) { MALLOCARRAY(stackP->stack, size); if (stackP->stack == NULL) @@ -692,7 +787,7 @@ initStack(struct stack * const stackP, unsigned int const size) { static void -pushStack(struct stack * const stackP, int const value) { +pushStack(struct Stack * const stackP, unsigned char const value) { if (stackP->sp >= stackP->top) pm_error("stack overflow"); @@ -703,14 +798,14 @@ pushStack(struct stack * const stackP, int const value) { static bool -stackIsEmpty(const struct stack * const stackP) { +stackIsEmpty(const struct Stack * const stackP) { return stackP->sp == stackP->stack; } -static int -popStack(struct stack * const stackP) { +static unsigned char +popStack(struct Stack * const stackP) { if (stackP->sp <= stackP->stack) pm_error("stack underflow"); @@ -721,7 +816,7 @@ popStack(struct stack * const stackP) { static void -termStack(struct stack * const stackP) { +termStack(struct Stack * const stackP) { free(stackP->stack); stackP->stack = NULL; } @@ -767,98 +862,164 @@ termStack(struct stack * const stackP) { -----------------------------------------------------------------------------*/ +static int const maxLzwCodeCt = (1<codeSize = decompP->initCodeSize+1; + decompP->maxCodeCt = 1 << decompP->codeSize; + decompP->nextTableSlot = decompP->maxDataVal + 3; + decompP->fresh = TRUE; +} - decompP->codeSize = decompP->init_codeSize+1; - decompP->maxnum_code = 1 << decompP->codeSize; - decompP->next_tableSlot = decompP->max_dataVal + 3; - decompP->fresh = 1; + + +static void +validateTransparentIndex(unsigned int const transparentIndex, + bool const tolerateBadInput, + unsigned int const cmapSize, + unsigned int const maxDataVal) { + + if (transparentIndex >= cmapSize) { + if (tolerateBadInput) { + if (transparentIndex > maxDataVal) + pm_error("Invalid transparent index value: %d", + transparentIndex); + } else { + pm_error("Invalid transparent index value %d in image with " + "only %u colors. %s", + transparentIndex, cmapSize, + transparentIndex <= maxDataVal ? + "" : + "Use the -repair option to try to render the " + "image overriding this error."); + } + } } static void -lzwInit(struct decompressor * const decompP, +lzwInit(struct Decompressor * const decompP, FILE * const ifP, - int const init_codeSize) { + int const initCodeSize, + unsigned int const cmapSize, + bool const haveTransColor, + unsigned int const transparentIndex, + bool const tolerateBadInput) { + unsigned int const maxDataVal = (1 << initCodeSize) - 1; + if (verbose) pm_message("Image says the initial compression code size is " "%d bits", - init_codeSize); + initCodeSize); - decompP->ifP = ifP; - decompP->init_codeSize = init_codeSize; - - assert(decompP->init_codeSize < sizeof(decompP->max_dataVal) * 8); - - decompP->max_dataVal = (1 << init_codeSize) - 1; - decompP->clear_code = decompP->max_dataVal + 1; - decompP->end_code = decompP->max_dataVal + 2; + decompP->ifP = ifP; + decompP->initCodeSize = initCodeSize; + decompP->cmapSize = cmapSize; + decompP->tolerateBadInput = tolerateBadInput; + decompP->maxDataVal = maxDataVal; + decompP->clearCode = maxDataVal + 1; + decompP->endCode = maxDataVal + 2; if (verbose) - pm_message("Initial code size is %u bits; clear code = 0x%x, " - "end code = 0x%x", - decompP->init_codeSize, - decompP->clear_code, decompP->end_code); + pm_message("Initial code size is %u bits; clear code = 0x%03x, " + "end code = 0x%03x", + decompP->initCodeSize, + decompP->clearCode, decompP->endCode); /* The entries in the translation table for true data codes are - constant throughout the stream. We set them now and they never - change. + constant throughout the image. For PBM output we make an + adjustment later. Once set entries never change. */ { unsigned int i; - for (i = 0; i <= decompP->max_dataVal; ++i) { - decompP->table[0][i] = 0; - decompP->table[1][i] = i; + for (i = 0; i <= maxDataVal; ++i) { + decompP->table[i][0] = 0; + decompP->table[i][1] = i < cmapSize ? i : 0; } } + decompP->haveTransColor = haveTransColor; + decompP->transparentIndex = transparentIndex; + + if (haveTransColor) + validateTransparentIndex(transparentIndex, tolerateBadInput, + cmapSize, maxDataVal); + resetDecompressor(decompP); getCode_init(&getCodeState); decompP->fresh = TRUE; - initStack(&decompP->stack, maxnum_lzwCode * 2); + initStack(&decompP->stack, maxLzwCodeCt); + + assert(decompP->initCodeSize < sizeof(decompP->maxDataVal) * 8); +} + + + +static void +lzwAdjustForPBM(struct Decompressor * const decompP, + GifColorMap const cmap) { +/*---------------------------------------------------------------------------- + In the PBM case we use the table index value directly instead of looking up + the color map for each pixel. + + Note that cmap.size is not always 2. + + Similar logic should work for PGM. +----------------------------------------------------------------------------*/ + unsigned int i; + for (i = 0; i < cmap.size; ++i) + decompP->table[i][1] = cmap.map[i][0] == 0 ? PBM_BLACK : PBM_WHITE; } static void -lzwTerm(struct decompressor * const decompP) { +lzwTerm(struct Decompressor * const decompP) { termStack(&decompP->stack); } @@ -866,8 +1027,32 @@ lzwTerm(struct decompressor * const decompP) { static void -expandCodeOntoStack(struct decompressor * const decompP, - int const incode, +pushWholeStringOnStack(struct Decompressor * const decompP, + unsigned int const code0) { +/*---------------------------------------------------------------------------- + Get the whole string that compression code 'code0' represents and push + it onto the code stack so the leftmost code is on top. Set + decompP->firstcode to the first (leftmost) code in that string. +-----------------------------------------------------------------------------*/ + unsigned int code; + unsigned int stringCount; + + for (stringCount = 0, code = code0; + code > decompP->maxDataVal; + ++stringCount, code = decompP->table[code][0] + ) { + + pushStack(&decompP->stack, decompP->table[code][1]); + } + decompP->firstcode = decompP->table[code][1]; + pushStack(&decompP->stack, decompP->firstcode); +} + + + +static void +expandCodeOntoStack(struct Decompressor * const decompP, + unsigned int const incode, const char ** const errorP) { /*---------------------------------------------------------------------------- 'incode' is an LZW string code. It represents a string of true data @@ -882,105 +1067,125 @@ expandCodeOntoStack(struct decompressor * const decompP, from which it was built is invalid), fail (return text explanation as *errorP). -----------------------------------------------------------------------------*/ - int code; - const char * error; - - error = NULL; /* Initial value */ - - if (incode < decompP->next_tableSlot) - code = incode; - else { - /* It's a code that isn't in our translation table yet */ - pushStack(&decompP->stack, decompP->firstcode); - code = decompP->prevcode; + unsigned int code; + + *errorP = NULL; /* Initial value */ + + if (incode <= decompP->maxDataVal) { + if (incode < decompP->cmapSize) + code = incode; /* Direct index */ + else if (decompP->tolerateBadInput && + decompP->haveTransColor && + decompP->table[incode][1] == decompP->transparentIndex) + /* transparent code outside cmap exceptional case */ + code = incode; + else + pm_asprintf(errorP, "Error in GIF image: invalid color code %u. " + "Valid color values are 0 - %u", + incode, decompP->cmapSize - 1); } - - { - /* Get the whole string that this compression code - represents and push it onto the code stack so the - leftmost code is on top. Set decompP->firstcode to the - first (leftmost) code in that string. + else if (incode < decompP->nextTableSlot) + /* LZW string, defined */ + code = incode; + else if (incode == decompP->nextTableSlot && !decompP->fresh) { + /* It's a code that isn't in our translation table yet. + This does not happen with the decoder in a fresh state. */ + if (wantLzwCodes && verbose) + pm_message ("LZW code valid, but not in decoder table"); - unsigned int stringCount; - stringCount = 0; - - while (code > decompP->max_dataVal && !error) { - if (stringCount > maxnum_lzwCode) { - asprintfN(&error, - "Error in GIF image: contains LZW string loop"); - } else { - ++stringCount; - pushStack(&decompP->stack, decompP->table[1][code]); - code = decompP->table[0][code]; - } - } - decompP->firstcode = decompP->table[1][code]; pushStack(&decompP->stack, decompP->firstcode); - } + code = decompP->prevcode; + } else + pm_asprintf(errorP, "Error in GIF image: invalid LZW code"); - if (decompP->next_tableSlot < maxnum_lzwCode) { - decompP->table[0][decompP->next_tableSlot] = decompP->prevcode; - decompP->table[1][decompP->next_tableSlot] = decompP->firstcode; - ++decompP->next_tableSlot; - if (decompP->next_tableSlot >= decompP->maxnum_code) { - /* We've used up all the codes of the current code size. - Future codes in the stream will have codes one bit longer. - But there's an exception if we're already at the LZW - maximum, in which case the codes will simply continue - the same size. - */ - if (decompP->codeSize < MAX_LZW_BITS) { - ++decompP->codeSize; - decompP->maxnum_code = 1 << decompP->codeSize; + if (!*errorP) { + pushWholeStringOnStack(decompP, code); + + if (decompP->nextTableSlot < maxLzwCodeCt) { + decompP->table[decompP->nextTableSlot][0] = decompP->prevcode; + decompP->table[decompP->nextTableSlot][1] = decompP->firstcode; + ++decompP->nextTableSlot; + if (decompP->nextTableSlot >= decompP->maxCodeCt) { + /* We've used up all the codes of the current code size. + Future codes in the stream will have codes one bit longer. + But there's an exception if we're already at the LZW + maximum, in which case the codes will simply continue + the same size. + */ + if (decompP->codeSize < MAX_LZW_BITS) { + ++decompP->codeSize; + decompP->maxCodeCt = 1 << decompP->codeSize; + } } } + decompP->prevcode = incode; } - - *errorP = error; - - decompP->prevcode = incode; } static void -lzwReadByteFresh(struct getCodeState * const getCodeStateP, - struct decompressor * const decompP, +lzwReadByteFresh(struct GetCodeState * const getCodeStateP, + struct Decompressor * const decompP, bool * const endOfImageP, - unsigned int * const dataReadP, + unsigned char * const dataReadP, const char ** const errorP) { - - /* Read off all initial clear codes, read the first non-clear code, - and return it. There are no strings in the table yet, so the next - code must be a direct true data code. - */ +/*---------------------------------------------------------------------------- + Read off all initial clear codes, read the first non-clear code, and return + it as *dataReadP. + + Iff we hit end of image in so doing, return *endOfImageP true and nothing as + *dataReadP. One way we hit end of image is for that first non-clear code to + be an end code. + + Assume the decompressor is fresh, i.e. there are no strings in the table + yet, so the next code must be a direct true data code. +-----------------------------------------------------------------------------*/ + unsigned int code; bool eof; + + assert(decompP->fresh); /* Entry requirement */ + + decompP->fresh = FALSE; + do { getCode_get(getCodeStateP, decompP->ifP, decompP->codeSize, - &eof, &decompP->firstcode, errorP); - decompP->prevcode = decompP->firstcode; - } while (decompP->firstcode == decompP->clear_code && !*errorP && !eof); + &eof, &code, errorP); + } while (!*errorP && !eof && code == decompP->clearCode); if (!*errorP) { if (eof) *endOfImageP = TRUE; - else if (decompP->firstcode == decompP->end_code) { + else if (code == decompP->endCode) { if (!zeroDataBlock) readThroughEod(decompP->ifP); *endOfImageP = TRUE; - } else { + } else if (code >= decompP->cmapSize) { + pm_asprintf(errorP, "Error in GIF image: invalid color code %u. " + "Valid color values are: 0 - %u", + code, decompP->cmapSize-1); + /* Set these values in order to avoid errors in the -repair + case + */ + decompP->prevcode = decompP->firstcode = 0; + *endOfImageP = FALSE; + } else { /* valid code */ + decompP->prevcode = code; + decompP->firstcode = decompP->table[code][1]; *dataReadP = decompP->firstcode; + *endOfImageP = FALSE; } } } + static void -lzwReadByte(struct decompressor * const decompP, - unsigned int * const dataReadP, +lzwReadByte(struct Decompressor * const decompP, + unsigned char * const dataReadP, bool * const endOfImageP, const char ** const errorP) { /*---------------------------------------------------------------------------- @@ -1004,8 +1209,6 @@ lzwReadByte(struct decompressor * const decompP, *endOfImageP = FALSE; *dataReadP = popStack(&decompP->stack); } else if (decompP->fresh) { - decompP->fresh = FALSE; - lzwReadByteFresh(&getCodeState, decompP, endOfImageP, dataReadP, errorP); } else { @@ -1015,14 +1218,15 @@ lzwReadByte(struct decompressor * const decompP, &eof, &code, errorP); if (!*errorP) { if (eof) - asprintfN(errorP, - "Premature end of file; no proper GIF closing"); + pm_asprintf(errorP, + "Premature end of file; no proper GIF closing"); else { - if (code == decompP->clear_code) { + if (code == decompP->clearCode) { resetDecompressor(decompP); - lzwReadByte(decompP, dataReadP, endOfImageP, errorP); + lzwReadByteFresh(&getCodeState, decompP, endOfImageP, + dataReadP, errorP); } else { - if (code == decompP->end_code) { + if (code == decompP->endCode) { if (!zeroDataBlock) readThroughEod(decompP->ifP); *endOfImageP = TRUE; @@ -1044,8 +1248,8 @@ lzwReadByte(struct decompressor * const decompP, enum pass {MULT8PLUS0, MULT8PLUS4, MULT4PLUS2, MULT2PLUS1}; static void -bumpRowInterlace(unsigned int * const rowP, - unsigned int const rows, +bumpRowInterlace(unsigned int const rows, + unsigned int * const rowP, enum pass * const passP) { /*---------------------------------------------------------------------------- Move *pixelCursorP to the next row in the interlace pattern. @@ -1098,47 +1302,57 @@ bumpRowInterlace(unsigned int * const rowP, } +static void +renderRow(unsigned char * const cmapIndexRow, + unsigned int const cols, + GifColorMap const cmap, + bool const haveTransColor, + unsigned int const transparentIndex, + FILE * const imageOutfile, + int const format, + xel * const xelrow, + FILE * const alphaFileP, + bit * const alphabits) { +/*---------------------------------------------------------------------------- + Convert one row of cmap indexes to PPM/PGM/PBM output. + + Render the alpha row to *alphaFileP iff 'alphabits' is non-NULL. If + 'haveTransColor' is false, render all white (i.e. the row is + opaque). 'alphabits' is otherwise just a one-row buffer for us to use + in rendering the alpha row. + + imageOutfile is NULL if user wants only the alpha file. +----------------------------------------------------------------------------*/ + if (alphabits) { + unsigned int col; + + for (col=0; col < cols; ++col) { + alphabits[col] = + (haveTransColor && cmapIndexRow[col] == transparentIndex) ? + PBM_BLACK : PBM_WHITE; + } + pbm_writepbmrow(alphaFileP, alphabits, cols, false); + } -struct pnmBuffer { - xel ** xels; - unsigned int col; - unsigned int row; -}; + if (imageOutfile) { + if (useFastPbmRender && format == PBM_FORMAT && !haveTransColor) { -static void -addPixelToRaster(unsigned int const cmapIndex, - struct pnmBuffer * const pnmBufferP, - unsigned int const cols, - unsigned int const rows, - gifColorMap cmap, - unsigned int const cmapSize, - bool const interlace, - int const transparentIndex, - bit ** const alphabits, - enum pass * const passP) { - - if (cmapIndex >= cmapSize) - pm_error("Invalid color index %u in an image that has only " - "%u colors in the color map.", cmapIndex, cmapSize); - - assert(cmapIndex < MAXCOLORMAPSIZE); - - PPM_ASSIGN(pnmBufferP->xels[pnmBufferP->row][pnmBufferP->col], - cmap[CM_RED][cmapIndex], - cmap[CM_GRN][cmapIndex], - cmap[CM_BLU][cmapIndex]); - - if (alphabits) - alphabits[pnmBufferP->row][pnmBufferP->col] = - (cmapIndex == transparentIndex) ? PBM_BLACK : PBM_WHITE; - - ++pnmBufferP->col; - if (pnmBufferP->col == cols) { - pnmBufferP->col = 0; - if (interlace) - bumpRowInterlace(&pnmBufferP->row, rows, passP); - else - ++pnmBufferP->row; + bit * const bitrow = cmapIndexRow; + + pbm_writepbmrow(imageOutfile, bitrow, cols, false); + } else { + /* PPM, PGM and PBM with transparent */ + unsigned int col; + for (col = 0; col < cols; ++col) { + unsigned char const cmapIndex = cmapIndexRow[col]; + const unsigned char * const color = cmap.map[cmapIndex]; + assert(cmapIndex < cmap.size); + PPM_ASSIGN(xelrow[col], + color[CM_RED], color[CM_GRN],color[CM_BLU]); + } + pnm_writepnmrow(imageOutfile, xelrow, cols, + GIFMAXVAL, format, false); + } } } @@ -1149,19 +1363,18 @@ verifyPixelRead(bool const endOfImage, const char * const readError, unsigned int const cols, unsigned int const rows, - unsigned int const failedRowNum, const char ** const errorP) { if (readError) - *errorP = strdup(readError); + *errorP = pm_strdup(readError); else { if (endOfImage) - asprintfN(errorP, - "Error in GIF image: Not enough raster data to fill " - "%u x %u dimensions. Ran out of raster data in " - "row %u. The image has proper ending sequence, so " - "this is not just a truncated file.", - cols, rows, failedRowNum); + pm_asprintf(errorP, + "Error in GIF image: Not enough raster data to fill " + "%u x %u dimensions. " + "The image has proper ending sequence, so " + "this is not just a truncated file.", + cols, rows); else *errorP = NULL; } @@ -1169,130 +1382,302 @@ verifyPixelRead(bool const endOfImage, +static int +pnmFormat(bool const hasGray, + bool const hasColor) { +/*---------------------------------------------------------------------------- + The proper PNM format (PBM, PGM, or PPM) for an image described + by 'hasGray' and 'hasColor'. +-----------------------------------------------------------------------------*/ + int format; + const char * formatName; + + if (hasColor) { + format = PPM_FORMAT; + formatName = "PPM"; + } else if (hasGray) { + format = PGM_FORMAT; + formatName = "PGM"; + } else { + format = PBM_FORMAT; + formatName = "PBM"; + } + if (verbose) + pm_message("writing a %s file", formatName); + + return format; +} + + + static void -readRaster(struct decompressor * const decompP, - xel ** const xels, +makePnmRow(struct Decompressor * const decompP, unsigned int const cols, unsigned int const rows, - gifColorMap cmap, - unsigned int const cmapSize, - bool const interlace, - int const transparentIndex, - bit ** const alphabits, - bool const tolerateBadInput) { - - struct pnmBuffer pnmBuffer; - enum pass pass; - bool fillingMissingPixels; + bool const fillWithZero, + unsigned char * const cmapIndexRow, + const char ** const errorP) { - pass = MULT8PLUS0; - pnmBuffer.xels = xels; - pnmBuffer.col = 0; - pnmBuffer.row = 0; - fillingMissingPixels = false; /* initial value */ + bool fillingWithZero; + unsigned int col; - while (pnmBuffer.row < rows) { - unsigned int colorIndex; + *errorP = NULL; /* initial value */ - if (fillingMissingPixels) - colorIndex = 0; - else { - const char * error; + for (col = 0, fillingWithZero = fillWithZero; + col < cols; + ++col) { - const char * readError; - unsigned int readColorIndex; - bool endOfImage; + unsigned char colorIndex; + + if (fillingWithZero) + colorIndex = 0; + else { + const char * readError; + unsigned char readColorIndex; + bool endOfImage; lzwReadByte(decompP, &readColorIndex, &endOfImage, &readError); - verifyPixelRead(endOfImage, readError, cols, rows, pnmBuffer.row, - &error); + verifyPixelRead(endOfImage, readError, cols, rows, errorP); if (readError) - strfree(readError); - - if (error) { - if (tolerateBadInput) { - pm_message("WARNING: %s. " - "Filling bottom %u rows with arbitrary color", - error, rows - pnmBuffer.row); - fillingMissingPixels = true; - } else - pm_error("Unable to read input image. %s. Use the " - "-repair option to try to salvage some of " - "the image", - error); - + pm_strfree(readError); + + if (*errorP) { + /* Caller may want to try to ignore this error, so we + fill out the row with zeroes. Note that we can't possibly + have another error while doing that. + */ + fillingWithZero = true; colorIndex = 0; } else colorIndex = readColorIndex; } - addPixelToRaster(colorIndex, &pnmBuffer, cols, rows, cmap, cmapSize, - interlace, transparentIndex, alphabits, &pass); + cmapIndexRow[col] = colorIndex; } } static void -skipExtraneousData(struct decompressor * const decompP) { +convertRaster(struct Decompressor * const decompP, + unsigned int const cols, + unsigned int const rows, + GifColorMap const cmap, + bool const interlace, + FILE * const imageOutFileP, + FILE * const alphaFileP, + bool const hasGray, + bool const hasColor) { +/*---------------------------------------------------------------------------- + Read the raster from the GIF decompressor *decompP, and write it as a + complete PNM stream (starting with the header) on *imageOutFileP and + *alphaFileP. + + Assume that raster is 'cols' x 'rows', refers to colormap 'cmap', and is + interlaced iff 'interlace' is true. + + Assume the image has gray levels and/or color per 'hasGray' and 'hasColor'. +-----------------------------------------------------------------------------*/ + int const format = pnmFormat(hasGray, hasColor); - unsigned int byteRead; + enum pass pass; + bool fillingMissingPixels; + unsigned int row; + unsigned char ** cmapIndexArray; + bit * alphabits; + xel * xelrow; + unsigned int outrow; + /* Non-interlace: outrow is always 0: cmapIndexRow keeps pointing + to the single row in array. + + Interlace: outrow is modified with each call to bumpRowInterface(). + */ + + MALLOCARRAY2(cmapIndexArray, interlace ? rows : 1 , cols); + + if (imageOutFileP) + pnm_writepnminit(imageOutFileP, cols, rows, GIFMAXVAL, format, FALSE); + if (alphaFileP) + pbm_writepbminit(alphaFileP, cols, rows, FALSE); + + xelrow = pnm_allocrow(cols); + if (!xelrow) + pm_error("couldn't alloc space for image" ); + + if (alphaFileP) { + alphabits = pbm_allocrow(cols); + if (!alphabits) + pm_error("couldn't alloc space for alpha image" ); + } else + alphabits = NULL; + + fillingMissingPixels = false; /* initial value */ + pass = MULT8PLUS0; + outrow = 0; + + for (row = 0; row < rows; ++row) { + const char * problem; + makePnmRow(decompP, cols, rows, fillingMissingPixels, + cmapIndexArray[outrow], &problem); + + if (problem) { + /* makePnmRow() recovered from the problem and produced an output + row, stuffed with zeroes as necessary + */ + if (decompP->tolerateBadInput) { + pm_message("WARNING: %s. " + "Filling bottom %u rows with arbitrary color", + problem, rows - row); + fillingMissingPixels = true; + } else + pm_error("Unable to read input image. %s " + "(Output row: %u). " + "Use the -repair option to try to salvage " + "some of the image", + problem, interlace ? outrow : row); + } + + if (interlace) + bumpRowInterlace(rows, &outrow, &pass); + else + renderRow(cmapIndexArray[outrow], cols, cmap, + decompP->haveTransColor, decompP->transparentIndex, + imageOutFileP, format, xelrow, alphaFileP, alphabits); + } + /* All rows decompressed (and rendered and output if non-interlaced) */ + if (interlace) { + unsigned int row; + for (row = 0; row < rows; ++row) + renderRow(cmapIndexArray[row], cols, cmap, + decompP->haveTransColor, decompP->transparentIndex, + imageOutFileP, format, xelrow, alphaFileP, alphabits); + } + + pnm_freerow(xelrow); + if (alphabits) + pbm_freerow(alphabits); + pm_freearray2((void **)cmapIndexArray); +} + + + +static void +skipExtraneousData(struct Decompressor * const decompP) { + + unsigned char byteRead; bool endOfImage; const char * error; + endOfImage = FALSE; /* initial value */ + lzwReadByte(decompP, &byteRead, &endOfImage, &error); if (error) - strfree(error); - else if (!endOfImage) { - pm_message("Extraneous data at end of image. " - "Skipped to end of image"); + pm_strfree(error); + else { + if (!endOfImage) { + pm_message("Extraneous data at end of image. " + "Skipped to end of image"); - while (!endOfImage && !error) - lzwReadByte(decompP, &byteRead, &endOfImage, &error); + while (!endOfImage && !error) + lzwReadByte(decompP, &byteRead, &endOfImage, &error); - if (error) { - pm_message("Error encountered skipping to end of image: %s", - error); - strfree(error); + if (error) { + pm_message("Error encountered skipping to end of image: %s", + error); + pm_strfree(error); + } } } } +static void +issueTransparencyMessage(bool const haveTransColor, + unsigned int const transparentIndex, + GifColorMap const cmap) { +/*---------------------------------------------------------------------------- + If user wants verbose output, tell him whether there is a transparent + background color ('haveTransColor') and if so what it is + ('transparentIndex'). + + Some GIFs put transparentIndex outside the color map. Allow this only + with "-repair", checked in lzwInit(). Here we issue a warning and report + the substitute color. +-----------------------------------------------------------------------------*/ + if (verbose) { + if (haveTransColor) { + if (transparentIndex >= cmap.size) { + const unsigned char * const color = cmap.map[0]; + pm_message("WARNING: Transparent index %u " + "is outside color map. " + "substitute background color: rgb:%02x/%02x/%02x ", + transparentIndex, + color[CM_RED], + color[CM_GRN], + color[CM_BLU] + ); + } else { + const unsigned char * const color = cmap.map[transparentIndex]; + pm_message("transparent background color: rgb:%02x/%02x/%02x " + "Index %u", + color[CM_RED], + color[CM_GRN], + color[CM_BLU], + transparentIndex + ); + } + } else + pm_message("no transparency"); + } +} + + + static void readImageData(FILE * const ifP, - xel ** const xels, unsigned int const cols, unsigned int const rows, - gifColorMap cmap, - unsigned int const cmapSize, + GifColorMap const cmap, bool const interlace, - int const transparentIndex, - bit ** const alphabits, + bool const haveTransColor, + unsigned int const transparentIndex, + FILE * const imageOutFileP, + FILE * const alphaFileP, + bool const hasGray, + bool const hasColor, bool const tolerateBadInput) { unsigned char lzwMinCodeSize; - struct decompressor decomp; - bool gotMinCodeSize; + struct Decompressor decomp; + const char * error; - gotMinCodeSize = ReadOK(ifP, &lzwMinCodeSize, 1); - if (!gotMinCodeSize) - pm_error("GIF stream ends (or read error) " + readFile(ifP, &lzwMinCodeSize, sizeof(lzwMinCodeSize), &error); + if (error) + pm_error("Can't read GIF stream " "right after an image separator; no " - "image data follows."); + "image data follows. %s", error); if (lzwMinCodeSize > MAX_LZW_BITS) pm_error("Invalid minimum code size value in image data: %u. " "Maximum allowable code size in GIF is %u", lzwMinCodeSize, MAX_LZW_BITS); - lzwInit(&decomp, ifP, lzwMinCodeSize); + lzwInit(&decomp, ifP, lzwMinCodeSize, cmap.size, + haveTransColor, transparentIndex, tolerateBadInput); + + issueTransparencyMessage(haveTransColor, transparentIndex, cmap); - readRaster(&decomp, xels, cols, rows, cmap, cmapSize, interlace, - transparentIndex, alphabits, tolerateBadInput); + if (useFastPbmRender && !hasGray && ! hasColor && !haveTransColor) { + if (verbose) + pm_message("Using fast PBM rendering"); + lzwAdjustForPBM(&decomp, cmap); + } + convertRaster(&decomp, cols, rows, cmap, interlace, + imageOutFileP, alphaFileP, + hasGray, hasColor); skipExtraneousData(&decomp); @@ -1302,80 +1687,47 @@ readImageData(FILE * const ifP, static void -writePnm(FILE * const outfileP, - xel ** const xels, - int const cols, - int const rows, - int const hasGray, - int const hasColor) { -/*---------------------------------------------------------------------------- - Write a PNM image to the current position of file *outfileP with - dimensions 'cols' x 'rows' and raster 'xels'. - - Make it PBM, PGM, or PBM according to 'hasGray' and 'hasColor'. ------------------------------------------------------------------------------*/ - int format; - const char * formatName; - - if (hasColor) { - format = PPM_FORMAT; - formatName = "PPM"; - } else if (hasGray) { - format = PGM_FORMAT; - formatName = "PGM"; - } else { - format = PBM_FORMAT; - formatName = "PBM"; - } - if (verbose) - pm_message("writing a %s file", formatName); - - if (outfileP) - pnm_writepnm(outfileP, xels, cols, rows, - (xelval) GIFMAXVAL, format, FALSE); -} +warnUserNotSquare(unsigned int const aspectRatio) { + const char * baseMsg = + "warning - input pixels are not square, " + "but we are rendering them as square pixels " + "in the output"; + if (pm_have_float_format()) { + float const r = ((float)aspectRatio + 15.0 ) / 64.0; -static void -transparencyMessage(int const transparentIndex, - gifColorMap cmap) { -/*---------------------------------------------------------------------------- - If user wants verbose output, tell him that the color with index - 'transparentIndex' is supposed to be a transparent background color. - - If transparentIndex == -1, tell him there is no transparent background - color. ------------------------------------------------------------------------------*/ - if (verbose) { - if (transparentIndex == -1) - pm_message("no transparency"); - else - pm_message("transparent background color: rgb:%02x/%02x/%02x " - "Index %d", - cmap[CM_RED][transparentIndex], - cmap[CM_GRN][transparentIndex], - cmap[CM_BLU][transparentIndex], - transparentIndex - ); - } + pm_message("%s. To fix the output, run it through " + "'pamscale -%cscale %g'", + baseMsg, + r < 1.0 ? 'x' : 'y', + r < 1.0 ? 1.0 / r : r ); + } else + pm_message("%s", baseMsg); } + + static void -readGifHeader(FILE * const gifFile, struct gifScreen * const gifScreenP) { +readGifHeader(FILE * const gifFileP, + struct GifScreen * const gifScreenP) { /*---------------------------------------------------------------------------- - Read the GIF stream header off the file gifFile, which is present + Read the GIF stream header off the file *gifFileP, which is present positioned to the beginning of a GIF stream. Return the info from it as *gifScreenP. -----------------------------------------------------------------------------*/ - unsigned char buf[16]; - char version[4]; +#define GLOBALCOLORMAP 0x80 + unsigned char buf[16]; + char version[4]; + unsigned int cmapSize; + const char * error; - if (! ReadOK(gifFile,buf,6)) - pm_error("error reading magic number" ); + readFile(gifFileP, buf, 6, &error); + if (error) + pm_error("Error reading magic number. %s", error); - if (strncmp((char *)buf,"GIF",3) != 0) + if (!strneq((char *)buf, "GIF", 3)) pm_error("File does not contain a GIF stream. It does not start " "with 'GIF'."); @@ -1386,56 +1738,52 @@ readGifHeader(FILE * const gifFile, struct gifScreen * const gifScreenP) { pm_message("GIF format version is '%s'", version); if ((!streq(version, "87a")) && (!streq(version, "89a"))) - pm_error("bad version number, not '87a' or '89a'" ); + pm_error("Bad version number, not '87a' or '89a'" ); - if (! ReadOK(gifFile,buf,7)) - pm_error("failed to read screen descriptor" ); + readFile(gifFileP, buf, 7, &error); + if (error) + pm_error("Failed to read screen descriptor. %s", error); - gifScreenP->Width = LM_to_uint(buf[0],buf[1]); - gifScreenP->Height = LM_to_uint(buf[2],buf[3]); - gifScreenP->ColorMapSize = 1 << ((buf[4] & 0x07) + 1); - gifScreenP->ColorResolution = (buf[4] & 0x70 >> 3) + 1; - gifScreenP->Background = buf[5]; - gifScreenP->AspectRatio = buf[6]; + gifScreenP->width = LM_to_uint(buf[0],buf[1]); + gifScreenP->height = LM_to_uint(buf[2],buf[3]); + cmapSize = 1 << ((buf[4] & 0x07) + 1); + gifScreenP->colorResolution = (buf[4] & 0x70 >> 3) + 1; + gifScreenP->background = buf[5]; + gifScreenP->aspectRatio = buf[6]; if (verbose) { - pm_message("GIF Width = %d GIF Height = %d " - "Pixel aspect ratio = %d (%f:1)", - gifScreenP->Width, gifScreenP->Height, - gifScreenP->AspectRatio, - gifScreenP->AspectRatio == 0 ? - 1 : (gifScreenP->AspectRatio + 15) / 64.0); - pm_message("Colors = %d Color Resolution = %d", - gifScreenP->ColorMapSize, gifScreenP->ColorResolution); + pm_message("GIF Width = %u GIF Height = %u " + "Pixel aspect ratio = %u (%f:1)", + gifScreenP->width, gifScreenP->height, + gifScreenP->aspectRatio, + gifScreenP->aspectRatio == 0 ? + 1 : (gifScreenP->aspectRatio + 15) / 64.0); + pm_message("Global color count = %u Color Resolution = %u", + cmapSize, gifScreenP->colorResolution); } - if (BitSet(buf[4], LOCALCOLORMAP)) { /* Global Colormap */ - readColorMap(gifFile, gifScreenP->ColorMapSize, gifScreenP->ColorMap, + if (buf[4] & GLOBALCOLORMAP) { + gifScreenP->hasGlobalColorMap = true; + readColorMap(gifFileP, cmapSize, &gifScreenP->colorMap, &gifScreenP->hasGray, &gifScreenP->hasColor); if (verbose) { - pm_message("Color map %s grays, %s colors", + pm_message("Global color map %s grays, %s colors", gifScreenP->hasGray ? "contains" : "doesn't contain", gifScreenP->hasColor ? "contains" : "doesn't contain"); } - } + } else + gifScreenP->hasGlobalColorMap = false; - if (gifScreenP->AspectRatio != 0 && gifScreenP->AspectRatio != 49) { - float r; - r = ( (float) gifScreenP->AspectRatio + 15.0 ) / 64.0; - pm_message("warning - input pixels are not square, " - "but we are rendering them as square pixels " - "in the output. " - "To fix the output, run it through " - "'pnmscale -%cscale %g'", - r < 1.0 ? 'x' : 'y', - r < 1.0 ? 1.0 / r : r ); - } + if (gifScreenP->aspectRatio != 0 && gifScreenP->aspectRatio != 49) + warnUserNotSquare(gifScreenP->aspectRatio); + +#undef GLOBALCOLORMAP } static void readExtensions(FILE* const ifP, - struct gif89 * const gif89P, + struct Gif89 * const gif89P, bool * const eodP, const char ** const errorP) { /*---------------------------------------------------------------------------- @@ -1461,13 +1809,13 @@ readExtensions(FILE* const ifP, unsigned char c; const char * error; - readFile(ifP, &c, 1, &error); + readFile(ifP, &c, sizeof(c), &error); if (error) { - asprintfN(errorP, "File read error where start of image " - "descriptor or end of GIF expected. %s", - error); - strfree(error); + pm_asprintf(errorP, "File read error where start of image " + "descriptor or end of GIF expected. %s", + error); + pm_strfree(error); } else { if (c == ';') { /* GIF terminator */ eod = TRUE; @@ -1478,17 +1826,18 @@ readExtensions(FILE* const ifP, readFile(ifP, &functionCode, 1, &error); if (error) { - asprintfN(errorP, "Failed to read function code " - "of GIF extension (immediately after the '!' " - "extension delimiter) from input. %s", error); - strfree(error); + pm_asprintf(errorP, "Failed to read function code " + "of GIF extension (immediately after the '!' " + "extension delimiter) from input. %s", error); + pm_strfree(error); } else { doExtension(ifP, functionCode, gif89P); } } else if (c == ',') imageStart = TRUE; else - pm_message("bogus character 0x%02x, ignoring", (int)c); + pm_message("Encountered invalid character 0x%02x while " + "seeking extension block, ignoring", (int)c); } } *eodP = eod; @@ -1496,20 +1845,111 @@ readExtensions(FILE* const ifP, +struct GifImageHeader { +/*---------------------------------------------------------------------------- + Information in the header (first 9 bytes) of a GIF image. +-----------------------------------------------------------------------------*/ + bool hasLocalColormap; + /* The image has its own color map. Its size is 'localColorMapSize' */ + /* (If an image does not have its own color map, the image uses the + global color map for the GIF stream) + */ + unsigned int localColorMapSize; + /* Meaningful only if 'hasLocalColormap' is true. */ + + /* Position of the image (max 65535) */ + unsigned int lpos; + unsigned int tpos; + + /* Dimensions of the image (max 65535) */ + unsigned int cols; + unsigned int rows; + + bool interlaced; +}; + + + static void -reportImageInfo(unsigned int const cols, - unsigned int const rows, - bool const useGlobalColormap, - unsigned int const localColorMapSize, - bool const interlaced) { +reportImageHeader(struct GifImageHeader const imageHeader) { pm_message("reading %u by %u%s GIF image", - cols, rows, interlaced ? " interlaced" : "" ); + imageHeader.cols, imageHeader.rows, + imageHeader.interlaced ? " interlaced" : "" ); - if (useGlobalColormap) - pm_message(" Uses global colormap"); + if (imageHeader.lpos > 0 || imageHeader.tpos > 0) + pm_message(" Image left position: %u top position: %u", + imageHeader.lpos, imageHeader.tpos); + + if (imageHeader.hasLocalColormap) + pm_message(" Uses local colormap of %u colors", + imageHeader.localColorMapSize); else - pm_message(" Uses local colormap of %u colors", localColorMapSize); + pm_message(" Uses global colormap"); +} + + + +static void +readImageHeader(FILE * const ifP, + struct GifImageHeader * const imageHeaderP) { + +#define LOCALCOLORMAP 0x80 +#define INTERLACE 0x40 + + unsigned char buf[16]; + const char * error; + + readFile(ifP, buf, 9, &error); + if (error) + pm_error("couldn't read left/top/width/height. %s", error); + + imageHeaderP->hasLocalColormap = !!(buf[8] & LOCALCOLORMAP); + imageHeaderP->localColorMapSize = 1u << ((buf[8] & 0x07) + 1); + imageHeaderP->lpos = LM_to_uint(buf[0], buf[1]); + imageHeaderP->tpos = LM_to_uint(buf[2], buf[3]); + imageHeaderP->cols = LM_to_uint(buf[4], buf[5]); + imageHeaderP->rows = LM_to_uint(buf[6], buf[7]); + imageHeaderP->interlaced = !!(buf[8] & INTERLACE); + + if (verbose) + reportImageHeader(*imageHeaderP); + +#undef INTERLACE +#undef LOCALCOLORMAP +} + + + +static void +validateWithinGlobalScreen(struct GifImageHeader const imageHeader, + struct GifScreen const gifScreen) { + + unsigned long int const rpos = imageHeader.lpos + imageHeader.cols; + unsigned long int const bpos = imageHeader.tpos + imageHeader.rows; + + if (rpos > gifScreen.width) + pm_error("Image right end (%lu) is outside global screen: %u x %u", + rpos, gifScreen.width, gifScreen.height); + if (bpos > gifScreen.height) + pm_error("Image bottom end (%lu) is outside global screen: " + "%u x %u", + bpos, gifScreen.width, gifScreen.height); +} + + + +static void +skipImageData(FILE * const ifP) { + unsigned char lzwMinCodeSize; + const char * error; + + readFile(ifP, &lzwMinCodeSize, sizeof(lzwMinCodeSize), &error); + if (error) { + pm_message("Unable to read file to skip image DataBlock. %s", error); + pm_strfree(error); + } + readThroughEod(ifP); } @@ -1517,85 +1957,51 @@ reportImageInfo(unsigned int const cols, static void convertImage(FILE * const ifP, bool const skipIt, - FILE * const imageout_file, - FILE * const alphafile, - struct gifScreen gifScreen, - struct gif89 const gif89, + FILE * const imageoutFileP, + FILE * const alphafileP, + struct GifScreen const gifScreen, + struct Gif89 const gif89, bool const tolerateBadInput) { /*---------------------------------------------------------------------------- Read a single GIF image from the current position of file 'ifP'. If 'skipIt' is TRUE, don't do anything else. Otherwise, write the - image to the current position of files 'imageout_file' and 'alphafile'. - If 'alphafile' is NULL, though, don't write any alpha information. + image to the current position of files *imageoutFileP and *alphafileP. + If *alphafileP is NULL, though, don't write any alpha information. -----------------------------------------------------------------------------*/ - unsigned char buf[16]; - bool useGlobalColormap; - xel **xels; /* The image raster, in libpnm format */ - bit **alphabits; - /* The image alpha mask, in libpbm format. NULL if we aren't computing - an alpha mask. - */ - unsigned int cols, rows; /* Dimensions of the image */ - gifColorMap localColorMap; - unsigned int localColorMapSize; - bool interlaced; + struct GifImageHeader imageHeader; + GifColorMap localColorMap; + const GifColorMap * currentColorMapP; + bool hasGray, hasColor; - if (! ReadOK(ifP,buf,9)) - pm_error("couldn't read left/top/width/height"); + readImageHeader(ifP, &imageHeader); - useGlobalColormap = ! BitSet(buf[8], LOCALCOLORMAP); - localColorMapSize = 1u << ((buf[8] & 0x07) + 1); - cols = LM_to_uint(buf[4], buf[5]); - rows = LM_to_uint(buf[6], buf[7]); - interlaced = !!BitSet(buf[8], INTERLACE); + validateWithinGlobalScreen(imageHeader, gifScreen); - if (verbose) - reportImageInfo(cols, rows, useGlobalColormap, localColorMapSize, - interlaced); - - xels = pnm_allocarray(cols, rows); - if (!xels) - pm_error("couldn't alloc space for image" ); - - if (alphafile) { - alphabits = pbm_allocarray(cols, rows); - if (!alphabits) - pm_error("couldn't alloc space for alpha image" ); - } else - alphabits = NULL; - - if (!useGlobalColormap) { - int hasGray, hasColor; - - readColorMap(ifP, localColorMapSize, localColorMap, + if (imageHeader.hasLocalColormap) { + readColorMap(ifP, imageHeader.localColorMapSize, &localColorMap, &hasGray, &hasColor); - transparencyMessage(gif89.transparent, localColorMap); - readImageData(ifP, xels, cols, rows, localColorMap, localColorMapSize, - interlaced, gif89.transparent, alphabits, - tolerateBadInput); - if (!skipIt) { - writePnm(imageout_file, xels, cols, rows, - hasGray, hasColor); - } + currentColorMapP = &localColorMap; + } else if (gifScreen.hasGlobalColorMap) { + currentColorMapP = &gifScreen.colorMap; + hasGray = gifScreen.hasGray; + hasColor = gifScreen.hasColor; } else { - transparencyMessage(gif89.transparent, gifScreen.ColorMap); - readImageData(ifP, xels, cols, rows, - gifScreen.ColorMap, gifScreen.ColorMapSize, - interlaced, gif89.transparent, alphabits, - tolerateBadInput); - if (!skipIt) { - writePnm(imageout_file, xels, cols, rows, - gifScreen.hasGray, gifScreen.hasColor); - } + pm_error("Invalid GIF: " + "Image has no local color map and stream has no global " + "color map either."); } - if (!skipIt && alphafile && alphabits) - pbm_writepbm(alphafile, alphabits, cols, rows, FALSE); - - pnm_freearray(xels, rows); - if (alphabits) - pbm_freearray(alphabits, rows); + if (!skipIt) { + readImageData(ifP, imageHeader.cols, imageHeader.rows, + *currentColorMapP, + imageHeader.interlaced, + gif89.haveTransColor, gif89.transparentIndex, + imageoutFileP, alphafileP, + hasGray, hasColor, + tolerateBadInput); + } else + skipImageData(ifP); } @@ -1613,7 +2019,7 @@ disposeOfReadExtensionsError(const char * const error, else pm_error("Error accessing Image %u of stream. %s", imageSeq, error); - strfree(error); + pm_strfree(error); *eodP = TRUE; } } @@ -1621,17 +2027,17 @@ disposeOfReadExtensionsError(const char * const error, static void -convertImages(FILE * const ifP, - bool const allImages, - int const requestedImageSeq, - bool const drainStream, - FILE * const imageout_file, - FILE * const alphafile, - bool const tolerateBadInput) { +convertImages(FILE * const ifP, + bool const allImages, + unsigned int const requestedImageSeq, + bool const drainStream, + FILE * const imageOutFileP, + FILE * const alphaFileP, + bool const tolerateBadInput) { /*---------------------------------------------------------------------------- Read a GIF stream from file 'ifP' and write one or more images from - it as PNM images to file 'imageout_file'. If the images have transparency - and 'alphafile' is non-NULL, write PGM alpha masks to file 'alphafile'. + it as PNM images to file 'imageOutFileP'. If the images have transparency + and 'alphafile' is non-NULL, write PGM alpha masks to file 'alphaFileP'. 'allImages' means Caller wants all the images in the stream. @@ -1645,21 +2051,24 @@ convertImages(FILE * const ifP, format in the tail of the stream and there may yet be more stuff in the file when we return. -----------------------------------------------------------------------------*/ - int imageSeq; + unsigned int imageSeq; /* Sequence within GIF stream of image we are currently processing. First is 0. */ - struct gifScreen gifScreen; - struct gif89 gif89; + struct GifScreen gifScreen; + struct Gif89 gif89; bool eod; /* We've read through the GIF terminator character */ + /* Set 'gif89' to initial values, to be updated as we encounter the + relevant extensions in the GIF stream. + */ initGif89(&gif89); readGifHeader(ifP, &gifScreen); for (imageSeq = 0, eod = FALSE; - !eod && (imageSeq <= requestedImageSeq || allImages || drainStream); + !eod && (allImages || imageSeq <= requestedImageSeq || drainStream); ++imageSeq) { const char * error; @@ -1677,9 +2086,10 @@ convertImages(FILE * const ifP, imageSeq, imageSeq > 1 ? "s" : ""); } else { if (verbose) - pm_message("Reading Image Sequence %d", imageSeq); + pm_message("Reading Image Sequence %u", imageSeq); + convertImage(ifP, !allImages && (imageSeq != requestedImageSeq), - imageout_file, alphafile, gifScreen, gif89, + imageOutFileP, alphaFileP, gifScreen, gif89, tolerateBadInput); } } @@ -1690,9 +2100,10 @@ convertImages(FILE * const ifP, int main(int argc, char **argv) { - struct cmdlineInfo cmdline; - FILE *ifP; - FILE *alpha_file, *imageout_file; + struct CmdlineInfo cmdline; + FILE * ifP; + FILE * alphaFileP; + FILE * imageOutFileP; pnm_init(&argc, argv); @@ -1700,27 +2111,30 @@ main(int argc, char **argv) { verbose = cmdline.verbose; showComment = cmdline.comments; - ifP = pm_openr(cmdline.input_filespec); + ifP = pm_openr(cmdline.inputFilespec); - if (cmdline.alpha_filename == NULL) - alpha_file = NULL; + if (cmdline.alphaFileName == NULL) + alphaFileP = NULL; else - alpha_file = pm_openw(cmdline.alpha_filename); + alphaFileP = pm_openw(cmdline.alphaFileName); - if (alpha_file && streq(cmdline.alpha_filename, "-")) - imageout_file = NULL; + if (alphaFileP && streq(cmdline.alphaFileName, "-")) + imageOutFileP = NULL; else - imageout_file = stdout; + imageOutFileP = stdout; - convertImages(ifP, cmdline.all_images, cmdline.image_no, - !cmdline.quitearly, imageout_file, alpha_file, + convertImages(ifP, cmdline.allImages, cmdline.imageNum, + !cmdline.quitearly, imageOutFileP, alphaFileP, cmdline.repair); pm_close(ifP); - if (imageout_file != NULL) - pm_close(imageout_file); - if (alpha_file != NULL) - pm_close(alpha_file); + if (imageOutFileP != NULL) + pm_close(imageOutFileP); + if (alphaFileP != NULL) + pm_close(alphaFileP); return 0; } + + + diff --git a/converter/other/hdifftopam.c b/converter/other/hdifftopam.c index 7bfeed9b..c9363040 100644 --- a/converter/other/hdifftopam.c +++ b/converter/other/hdifftopam.c @@ -33,7 +33,7 @@ parseCommandLine(int argc, char ** argv, was passed to us as the argv array. -----------------------------------------------------------------------------*/ optEntry *option_def = malloc( 100*sizeof( optEntry ) ); - /* Instructions to optParseOptions3 on how to parse our options. + /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; @@ -47,7 +47,7 @@ parseCommandLine(int argc, char ** argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (argc-1 < 1) diff --git a/converter/other/infotopam.c b/converter/other/infotopam.c index 21fa8ee2..f2e35827 100644 --- a/converter/other/infotopam.c +++ b/converter/other/infotopam.c @@ -114,7 +114,7 @@ typedef struct DiskObject_ { /* 78 bytes (including Gadget struct) */ unsigned char version[2]; /* Object version number */ unsigned char gadget[44]; /* Copy of in memory gadget (44 by */ unsigned char type; /* ??? */ - unsigned char pad; /* Pad it out to the next word boundry */ + unsigned char pad; /* Pad it out to the next word boundary */ unsigned char pDefaultTool[4]; /* Pointer to default tool */ unsigned char ppToolTypes[4]; /* Pointer pointer to tool types */ unsigned char currentX[4]; /* Current X position (?) */ @@ -175,7 +175,7 @@ parseCommandLine( int argc, opt.allowNegNum = FALSE; /* No negative number parameters */ /* Parse the command line */ - optParseOptions3( &argc, argv, opt, sizeof( opt ), 0 ); + pm_optParseOptions3( &argc, argv, opt, sizeof( opt ), 0 ); infoP->forceColor = forceColorSpec; infoP->selected = selectedSpec; @@ -233,33 +233,33 @@ getDiskObject( IconInfo * const infoP ) { /* Read the disk object header */ bytesRead = fread( &dobj, 1, sizeof(dobj), infoP->fp ); if (ferror(infoP->fp)) - pm_error( "Cannot read disk object header for file '%s'. " - "fread() errno = %d (%s)", - infoP->name, errno, strerror( errno ) ); - else if ( bytesRead != sizeof(dobj) ) - pm_error( "Cannot read entire disk object header for file '%s'. " - "Only read 0x%X of 0x%X bytes", - infoP->name, bytesRead, sizeof(dobj) ); + pm_error("Cannot read disk object header for file '%s'. " + "fread() errno = %d (%s)", + infoP->name, errno, strerror(errno)); + else if (bytesRead != sizeof(dobj)) + pm_error("Cannot read entire disk object header for file '%s'. " + "Only read 0x%X of 0x%X bytes", + infoP->name, (unsigned)bytesRead, (unsigned)sizeof(dobj)); /* Check magic number */ - if ( ( dobj.magic[0] != 0xE3 ) && ( dobj.magic[1] != 0x10 ) ) - pm_error( "Wrong magic number for file '%s'. " - "Expected 0xE310, but got 0x%X%X", - infoP->name, dobj.magic[0], dobj.magic[1] ); + if ((dobj.magic[0] != 0xE3) && (dobj.magic[1] != 0x10)) + pm_error("Wrong magic number for file '%s'. " + "Expected 0xE310, but got 0x%X%X", + infoP->name, dobj.magic[0], dobj.magic[1]); /* Set version info and have drawer data flag */ - infoP->version = ( dobj.version[0] << 8 ) + - ( dobj.version[1] ); - infoP->drawerData = ( dobj.pDrawerData[0] << 24 ) + - ( dobj.pDrawerData[1] << 16 ) + - ( dobj.pDrawerData[2] << 8 ) + - ( dobj.pDrawerData[3] ) ? TRUE : FALSE; + infoP->version = (dobj.version[0] << 8) + + (dobj.version[1] ); + infoP->drawerData = (dobj.pDrawerData[0] << 24) + + (dobj.pDrawerData[1] << 16) + + (dobj.pDrawerData[2] << 8) + + (dobj.pDrawerData[3] ) ? TRUE : FALSE; } static void -getIconHeader( IconInfo * const infoP ) { +getIconHeader(IconInfo * const infoP) { /*------------------------------------------------------------------------- * Get fields from icon header portion of info file *-------------------------------------------------------------------------*/ @@ -267,25 +267,25 @@ getIconHeader( IconInfo * const infoP ) { size_t bytesRead; /* Read icon header */ - bytesRead = fread( &ihead, 1, sizeof(ihead), infoP->fp ); - if ( ferror(infoP->fp ) ) - pm_error( "Cannot read icon header for file '%s'. " - "fread() errno = %d (%s)", - infoP->name, errno, strerror( errno ) ); - else if ( bytesRead != sizeof(ihead) ) - pm_error( "Cannot read the entire icon header for file '%s'. " - "Only read 0x%X of 0x%X bytes", - infoP->name, bytesRead, sizeof(ihead) ); + bytesRead = fread(&ihead, 1, sizeof(ihead), infoP->fp); + if (ferror(infoP->fp)) + pm_error("Cannot read icon header for file '%s'. " + "fread() errno = %d (%s)", + infoP->name, errno, strerror(errno)); + else if (bytesRead != sizeof(ihead)) + pm_error("Cannot read the entire icon header for file '%s'. " + "Only read 0x%X of 0x%X bytes", + infoP->name, (unsigned)bytesRead, (unsigned)sizeof(ihead)); /* Get icon width, heigh, and bitplanes */ - infoP->width = ( ihead.iconWidth[0] << 8 ) + ihead.iconWidth[1]; - infoP->height = ( ihead.iconHeight[0] << 8 ) + ihead.iconHeight[1]; - infoP->depth = ( ihead.bpp[0] << 8 ) + ihead.bpp[1]; + infoP->width = (ihead.iconWidth[0] << 8) + ihead.iconWidth[1]; + infoP->height = (ihead.iconHeight[0] << 8) + ihead.iconHeight[1]; + infoP->depth = (ihead.bpp[0] << 8) + ihead.bpp[1]; /* Check number of bit planes */ - if ( ( infoP->depth > 2 ) || ( infoP->depth < 1 ) ) - pm_error( "We don't know how to interpret %u bitplanes file '%s'. ", - infoP->depth, infoP->name ); + if ((infoP->depth > 2) || (infoP->depth < 1)) + pm_error("We don't know how to interpret %u bitplanes file '%s'. ", + infoP->depth, infoP->name); } diff --git a/converter/other/ipdb.c b/converter/other/ipdb.c new file mode 100644 index 00000000..d6bd6ef5 --- /dev/null +++ b/converter/other/ipdb.c @@ -0,0 +1,384 @@ +/* + * + * Copyright (C) 1997 Eric A. Howe + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors: Eric A. Howe (mu@trends.net) + * Bryan Henderson, 2010 + */ +#define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */ +#define _BSD_SOURCE /* Ensure strdup() is in */ +#include +#include +#include + +#include "mallocvar.h" +#include "nstring.h" +#include "ipdb.h" + +typedef uint32_t pilot_time_t; + + + + +static unsigned int +imgPpb(IMAGE * const imgP) { +/*---------------------------------------------------------------------------- + Pixels per byte +-----------------------------------------------------------------------------*/ + return + imgP->type == IMG_GRAY ? 4 : + imgP->type == IMG_GRAY16 ? 2 : + 8; +} + + + +unsigned int +ipdb_img_ppb(IMAGE * const imgP) { +/*---------------------------------------------------------------------------- + Pixels per byte +-----------------------------------------------------------------------------*/ + return imgPpb(imgP); +} + + + +size_t +ipdb_img_size(IMAGE * const imgP) { +/*---------------------------------------------------------------------------- + Size (in bytes) of an image's data. +-----------------------------------------------------------------------------*/ + return (size_t)(imgP->width / imgPpb(imgP) * imgP->height); +} + + + +/* + * Return the start of row `r'. + */ + uint8_t * + ipdb_img_row(IMAGE * const imgP, + unsigned int const row) { + + return &imgP->data[(row) * imgP->width / imgPpb(imgP)]; + } + + + + #define img_row(i, r) + + static pilot_time_t const unixepoch = (66*365+17)*24*3600; + /* The unix epoch in Mac time (the Mac epoch is 00:00 UTC 1904.01.01). + The 17 is the number of leap years. + */ + + static const char * const errorDesc[] = { + /* E_BADCOLORS */ + "Invalid palette, only {0x00, 0x55, 0xAA, 0xFF} allowed.", + + /* E_NOTIMAGE */ + "Not an image file.", + + /* E_IMAGETHERE */ + "Image record already present, logic error.", + + /* E_IMAGENOTTHERE */ + "Image record required before text record, logic error.", + + /* E_TEXTTHERE */ + "Text record already present, logic error.", + + /* E_NOTRECHDR */ + "Invalid record header encountered.", + + /* E_UNKNOWNRECHDR */ + "Unknown record header.", + + /* E_TOOBIGG */ + "Image too big, maximum size approx. 640*400 gray pixels.", + + /* E_TOOBIGM */ + "Image too big, maximum size approx. 640*800 monochrome pixels.", + }; + + + + const char * + ipdb_err(int const e) { + + if (e < 0) + return e >= E_LAST ? errorDesc[-e - 1] : "unknown error"; + else + return strerror(e); + } + + + + static void + rechdr_free(RECHDR * const recP) { + + if (recP) { + free(recP->extra); + free(recP); + } + } + + + + void + ipdb_image_free(IMAGE * const imgP) { + + if (imgP) { + rechdr_free(imgP->r); + free(imgP->data); + free(imgP); + } + } + + + + void + ipdb_text_free(TEXT * const textP) { + + if (textP) { + rechdr_free(textP->r); + free(textP->data); + free(textP); + } + } + + + + void + ipdb_pdbhead_free(PDBHEAD * const headP) { + + free(headP); + } + + + + void + ipdb_clear(IPDB * const pdbP) { + + if (pdbP) { + ipdb_image_free(pdbP->i); + ipdb_text_free(pdbP->t); + ipdb_pdbhead_free(pdbP->p); + } +} + + + +void +ipdb_free(IPDB * const pdbP) { + + ipdb_clear(pdbP); + free(pdbP); +} + + + +PDBHEAD * +ipdb_pdbhead_alloc(const char * const name) { + + PDBHEAD * pdbHeadP; + + MALLOCVAR(pdbHeadP); + + if (pdbHeadP) { + MEMSZERO(pdbHeadP); + + STRSCPY(pdbHeadP->name, name == NULL ? "unnamed" : name); + + /* + * All of the Image Viewer pdb files that I've come across have + * 3510939142U (1997.08.16 14:38:22 UTC) here. I don't know where + * this bizarre date comes from but the real date works fine so + * I'm using it. + */ + pdbHeadP->ctime = + pdbHeadP->mtime = (pilot_time_t)time(NULL) + unixepoch; + + MEMSCPY(&pdbHeadP->type, IPDB_vIMG); + MEMSCPY(&pdbHeadP->id, IPDB_View); + } + return pdbHeadP; +} + + + +static RECHDR * +rechdr_alloc(int const type, + uint32_t const offset) { + + /* + * We never produce the `extra' bytes (we only read them from a file) + * so there is no point allocating them here. + */ + + RECHDR * recHdrP; + + MALLOCVAR(recHdrP); + + if (recHdrP) { + MEMSSET(recHdrP, 0); + + recHdrP->offset = offset; + recHdrP->rec_type = (uint8_t)(0xff & type); + MEMSCPY(&recHdrP->unknown, IPDB_MYST); + } + return recHdrP; +} + + + +/* + * The offset will be patched up as needed elsewhere. + */ +#define IMGOFFSET (PDBHEAD_SIZE + 8) + + + +IMAGE * +ipdb_image_alloc(const char * const name, + int const type, + int const w, + int const h) { + + bool failed; + IMAGE * imgP; + + failed = false; + + MALLOCVAR(imgP); + + if (imgP) { + MEMSZERO(imgP); + + STRSCPY(imgP->name, name == NULL ? "unnamed" : name); + imgP->type = type; + imgP->x_anchor = 0xffff; + imgP->y_anchor = 0xffff; + imgP->width = w; + imgP->height = h; + + imgP->r = rechdr_alloc(IMG_REC, IMGOFFSET); + + if (imgP->r) { + if (w != 0 && h != 0) { + MALLOCARRAY(imgP->data, w * h); + + if (imgP->data) { + MEMSZERO(imgP->data); + } else + failed = true; + } + if (failed) + rechdr_free(imgP->r); + } else + failed = true; + + if (failed) + ipdb_image_free(imgP); + } else + failed = true; + + return failed ? NULL : imgP; +} + + + +TEXT * +ipdb_text_alloc(const char * const content) { + + TEXT * textP; + bool failed; + + failed = false; + /* + * The offset will be patched up later on when we know what it + * should be. + */ + + MALLOCVAR(textP); + + if (textP) { + MEMSZERO(textP); + + textP->r = rechdr_alloc(TEXT_REC, 0); + + if (textP->r) { + if (content) { + textP->data = strdup(content); + + if (!textP->data) + failed = true; + } + if (failed) + rechdr_free(textP->r); + } else + failed = true; + + if (failed) + ipdb_text_free(textP); + } else + failed = true; + + return failed ? NULL : textP; +} + + + +IPDB * +ipdb_alloc(const char * const name) { + + IPDB * pdbP; + bool failed; + + failed = false; + + MALLOCVAR(pdbP); + + if (pdbP) { + MEMSZERO(pdbP); + + if (name) { + pdbP->p = ipdb_pdbhead_alloc(name); + + if (!pdbP->p) + failed = true; + } + if (failed) + ipdb_free(pdbP); + } else + failed = true; + + return failed ? NULL : pdbP; +} + + + +const char * +ipdb_typeName(uint8_t const type) { + + switch (type) { + case IMG_GRAY16: return "16 Bit Grayscale"; break; + case IMG_GRAY: return "Grayscale"; break; + case IMG_MONO: return "Monochrome"; break; + default: return "???"; + } +} diff --git a/converter/other/ipdb.h b/converter/other/ipdb.h new file mode 100644 index 00000000..6af5fc44 --- /dev/null +++ b/converter/other/ipdb.h @@ -0,0 +1,243 @@ +/* + * ipdb.h + * Image Viewer PDB file functions. + * + * Copyright (C) 1997 Eric A. Howe + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors: Eric A. Howe (mu@trends.net) + * Bryan Henderson 2010 + */ +#ifndef IPDB_H_INCLUDED +#define IPDB_H_INCLUDED + +#include +#include + +/* + * Extra error numbers, feed these (or errno values) to ipdb_err() + * to get strings. + */ +#define E_BADCOLORS -1 +#define E_NOTIMAGE -2 +#define E_IMAGETHERE -3 +#define E_IMAGENOTTHERE -4 +#define E_TEXTTHERE -5 +#define E_NOTRECHDR -6 +#define E_UNKNOWNRECHDR -7 +#define E_TOOBIGG -8 +#define E_TOOBIGM -9 +#define E_LAST -9 + +/* + * The standard pdb header. + */ +typedef struct { + char name[32]; /* nul terminated */ + uint16_t flags; /* 0 */ + uint16_t version; /* 0 */ + uint32_t ctime; /* mac time */ + uint32_t mtime; /* mac time */ + uint32_t btime; /* mac time */ + uint32_t mod_num; /* 0 */ + uint32_t app_info; /* 0 */ + uint32_t sort_info; /* 0 */ + uint8_t type[4]; /* vIMG */ + uint8_t id[4]; /* View */ + uint32_t uniq_seed; /* 0 */ + uint32_t next_rec; /* 0 */ + uint16_t num_recs; /* 1 */ +} PDBHEAD; +#define PDBHEAD_SIZE (32 + 2*2 + 6*4 + 4 + 4 + 2*4 + 2) + +/* + * Between the pdb header and the image header we find some "mystery" bytes, + * these are supposed to be eight byte record headers but sometimes there + * are ten bytes. Version zero files use eight bytes, version 1 files appear + * to use ten bytes, files with attached notes (version 2?) use two sets of + * eight bytes. Note that this version isn't the same as the `version' field + * in IMAGE, that version only indicates if the file is compressed or not. + * + * The first four bytes of each piece are a four byte offset to the start + * of the corresponding image header or text record; the next three bytes + * (40 6f 80) are some kind of magic (they are always the same); the next + * byte is zero for image records and 1 for text records; any remaining + * mystery bytes (zero or two) are always zero. + */ +typedef struct { + uint32_t offset; /* offset, from zero, to the image */ + uint8_t unknown[3]; /* 40 6f 80 */ + uint8_t rec_type; /* byte seven, TEXT_REC || IMG_REC */ + size_t n_extra; /* bytes in extra */ + uint8_t *extra; /* extra unknown end bytes */ +} RECHDR; +#define IMG_REC (uint8_t)(0x00) +#define TEXT_REC (uint8_t)(0x01) + +/* + * The image headers. + */ +typedef struct { + RECHDR * r; + + /* + * Whether the image was originally compressed. Since compressed + * data can cross row boundaries we have to uncompress the whole + * thing during reads so `data' is always in the uncompressed + * (but packed) format. I think we can just use the `version' + * field for this but a little extra paranoia is worth a couple + * of bytes. This is also set after a write to indicate if + * compression was used. + */ + int compressed; + + /* + * The actual image header, this starts at `m->offset'. + */ + char name[32]; /* nul terminated */ + uint8_t version; /* 0 => uncompressed, 1 => compressed */ + uint8_t type; /* GRAYSCALE || MONOCHROME */ + uint8_t reserved1[4]; /* zero */ + uint8_t note[4]; /* zero */ + uint16_t x_last; /* zero */ + uint16_t y_last; /* zero */ + uint8_t reserved2[4]; /* zero */ + uint16_t x_anchor; /* 0xffff */ + uint16_t y_anchor; /* 0xffff */ + uint16_t width; /* pixels (must be 0 mod 16) */ + uint16_t height; /* pixels */ + + /* + * And finally, the actual image data. We always store the + * image data as 4 pixels per byte uncompressed. Any compression + * or decompression is done at I/O time. + */ + uint8_t * data; +} IMAGE; + +#define IMAGESIZE (32 + 1 + 1 + 4 + 4 + 2*2 + 4 + 2*2 + 2*2) + +/* + * Image types for IMAGE.type. + */ +#define IMG_GRAY16 ((uint8_t)2) +#define IMG_GRAY ((uint8_t)0) +#define IMG_MONO ((uint8_t)0xff) + +const char * +ipdb_typeName(uint8_t const type); + + +/* + * Compression constants for IMAGE.version. + */ +#define IMG_COMPRESSED ((uint8_t)0x01) +#define IMG_UNCOMPRESSED ((uint8_t)0x00) + +/* + * The notes record. If this exists, it will follow the image record. + */ +typedef struct { + RECHDR *r; + char *data; /* the actual text as a normal string */ +} TEXT; + +/* + * One PDB file. The `t' field will be NULL if there is no note. + */ +typedef struct { + PDBHEAD * p; + IMAGE * i; + TEXT * t; +} IPDB; + +/* + * Only use four bytes of these. + */ +#define IPDB_vIMG "vIMG" +#define IPDB_View "View" +/* + * Only use three bytes of this. + */ +#define IPDB_MYST "\x40\x6f\x80" + +/* + * Flags for ipdb_write(). + */ +#define IPDB_COMPMAYBE 0 /* compress if it does any good */ +#define IPDB_NOCOMPRESS (1 << 1) /* don't compress */ +#define IPDB_COMPRESS (1 << 2) /* compress */ + +#define ipdb_width(pdb) ((pdb)->i->width) +#define ipdb_height(pdb) ((pdb)->i->height) +#define ipdb_text(pdb) ((pdb)->t == NULL ? NULL : (pdb)->t->data) +#define ipdb_compressed(pdb) ((pdb)->i->compressed) +#define ipdb_ctime(pdb) ((time_t)((pdb)->p->ctime - UNIXEPOCH)) +#define ipdb_mtime(pdb) ((time_t)((pdb)->p->mtime - UNIXEPOCH)) +#define ipdb_btime(pdb) ((time_t)((pdb)->p->btime - UNIXEPOCH)) +#define ipdb_iname(pdb) ((pdb)->i->name) +#define ipdb_pname(pdb) ((pdb)->p->name) +#define ipdb_version(pdb) ((pdb)->i->version) +#define ipdb_type(pdb) ((pdb)->i->type) +#define ipdb_xlast(pdb) ((pdb)->i->x_last) +#define ipdb_ylast(pdb) ((pdb)->i->y_last) +#define ipdb_xanchor(pdb) ((pdb)->i->x_anchor) +#define ipdb_yanchor(pdb) ((pdb)->i->y_anchor) + +const char * +ipdb_err(int error); + +size_t +ipdb_img_size(IMAGE * const imgP); + +unsigned int +ipdb_img_ppb(IMAGE * const imgP); + +uint8_t * +ipdb_img_row(IMAGE * const imgP, + unsigned int const row); + +void +ipdb_free(IPDB *); + +IPDB * +ipdb_alloc(const char *); + +void +ipdb_clear(IPDB * const pdbP); + +PDBHEAD * +ipdb_pdbhead_alloc(const char * const name); + +void +ipdb_pdbhead_free(PDBHEAD * const headP); + +IMAGE * +ipdb_image_alloc(const char * const name, + int const type, + int const w, + int const h); + +void +ipdb_image_free(IMAGE * const imgP); + +void +ipdb_text_free(TEXT * const textP); + +TEXT * +ipdb_text_alloc(const char * const content); + +#endif diff --git a/converter/other/jbig/ANNOUNCE b/converter/other/jbig/ANNOUNCE deleted file mode 100644 index edbcc3f8..00000000 --- a/converter/other/jbig/ANNOUNCE +++ /dev/null @@ -1,243 +0,0 @@ - -Version 1.2 of the JBIG-KIT lossless image compression library available ------------------------------------------------------------------------- - -Markus Kuhn -- 2000-04-08 - - -The latest release of JBIG-KIT can be downloaded over the Internet -with anonymous ftp from - - ftp://ftp.informatik.uni-erlangen.de/pub/doc/ISO/JBIG/jbigkit-1.2.tar.gz - http://www.cl.cam.ac.uk/~mgk25/download/jbigkit-1.2.tar.gz - -and from a number of other servers. - -JBIG-KIT implements a highly effective data compression algorithm for -bi-level high-resolution images such as fax pages or scanned -documents. - -JBIG-KIT provides a portable library of compression and decompression -functions with a documented interface that you can very easily include -into your image or document processing software. In addition, JBIG-KIT -provides ready-to-use compression and decompression programs with a -simple command line interface (similar to the converters found in Jef -Poskanzer's PBM graphics file conversion package). - -JBIG-KIT implements the specification - - International Standard ISO/IEC 11544:1993 and ITU-T Recommendation - T.82(1993), "Information technology - Coded representation of picture - and audio information - progressive bi-level image compression", - , - -which is commonly referred to as the "JBIG standard". JBIG (Joint -Bi-level Image experts Group) is the committee which developed this -international standard for the lossless compression of images using -arithmetic coding. Like the well-known compression algorithms JPEG and -MPEG, also JBIG has been developed and published by the International -Organization for Standardization (ISO) and the International -Telecommunication Union (ITU). See also - - http://www.jpeg.org/public/jbighomepage.htm - http://www.iso.ch/ - http://www.itu.ch/ - -The JBIG compression algorithm offers the following features: - - - Close to state-of-the-art lossless compression ratio for high - resolution bi-level images. - - - Around 1.1 to 1.5 times better compression ratio on typical - scanned documents compared to G4 fax compression (ITU-T T.6), - which has been the best compression algorithm for scanned - documents available prior to JBIG. - - - Up to 30 times better compression of scanned images with dithered - images compared to G4 fax compression. - - - Around 2 times better compression on typical 300 dpi documents - compared to 'gzip -9' on raw bitmaps. - - - Around 3-4 times better compression than GIF on typical 300 dpi - documents. - - - Even much better competitive compression results on computer - generated images which are free of scanning distortions. - - - JBIG supports hierarchical "progressive" encoding, that means it is - possible to encode a low resolution image first, followed by - resolution enhancement data. This allows for instance a document - browser to display already a good 75 dpi low resolution version of - an image, while the data necessary to reconstruct the full 300 dpi - version for laser printer reproduction is still arriving (say - over a slow network link or mass storage medium). - - - The various resolution layers of a JBIG image in progressive - encoding mode together require not much more space than a - normal non-progressive mode encoded image (which JBIG also - supports). - - - The progressive encoding mode utilizes a very sophisticated - resolution reduction algorithm which offers highest quality - low resolution versions that preserve the shape of characters as - well as the integrity of thin lines and dithered images. - - - JBIG supports multiple bit planes and can this way also be used - for greyscale and color images, although the main field of - application is compression of bi-level images, i.e. images with - only two different pixel values. For greyscale images with up to - 6 bit per pixel, JBIG performs superior to JPEG's lossless - mode. - -JBIG-KIT is free software under the GNU General Public License. For -other license arrangements contact the author. JBIG-KIT provides a -portable library implemented in ANSI/ISO C for encoding and decoding -JBIG data streams together with documentation. The library is not -intended for 8-bit or 16-bit machine architectures (e.g., old MS-DOS C -compilers) on which a number of very efficient optimization techniques -used in this software are not possible. For maximum performance, a -32-bit processor is required (64-bit systems work too, of course). On -architectures with 16-bit pointer arithmetic, only very small images -can be processed. - -Special features of the JBIG-KIT implementation are: - - - Fully reentrant multithread-capable design (no global or static - variables, isolated malloc()/free() calls, etc.). - - - Capable of handling incomplete and growing JBIG data streams in - order to allow earliest display of low resolution versions. - - - Capable of handling several incoming data streams simultaneously - in one single process and task. - - - Especially designed with applications in mind that want to display - incoming data as early as possible (e.g., similar to the way in - which Netscape Navigator handles incoming GIF images). - - - Implements all JBIG features and options including progressive and - sequential encoding, multiple bit planes, user specified - resolution reduction and deterministic prediction tables, adaptive - template changes for optimal performance on half-tone images, - deterministic prediction, typical prediction in lowest and - differential layers, various stripe orderings, etc. Only the SEQ - and HITOLO options are currently not supported by the decoder - (they are normally never required, but could be added later in - case of user requirements). - - - Efficient code, optimized utilization of 32-bit processor - registers. - - - Very easy to use documented C library interface. - - - Included Gray code conversion routines for efficient encoding - of greyscale images. - - - Ready-to-use pbmtojbg and jbgtopbm converters. - - -Changes in version 1.2 (2000-04-08): - - - bug in the decoder fixed, which caused the rest of the input file - to be skipped whenever a comment marker was encountered (special - thanks to Ben Rudiak-Gould for - reporting this one) - -Changes in version 1.1 (1999-11-16): - - - serious bug in the encoder fixed, which for a very small - percentage of images has caused an unterminated linked list to be - created internally that could have been responsible for - segmentation violations or non-terminating encoders - (special thanks to Hisashi Saiga for - tracking that one down) - - - minor bug in the "jbgtopbm -d" diagnostic output fixed - -Changes in version 1.0 (1998-04-11): - - - two bugs fixed that caused the encoder and decoder to fail - under certain modes of operation with several bit planes - - - added new functions jbg_split_planes(), jbg_dec_merge_planes(), - and jbg_dec_getsize_merged() for easy handling of greyscale - images - - - added support for compressing greyscale PGM files to pbmtojbg - and jbgtopbm - - - more changes to avoid paranoid compiler warnings - -Changes in version 0.9 (1996-01-09): - - - encoder won't break any more on input bitmap data with incorrect - zero padding - - - pbmtojbg displays a warning if input file has incorrect zero - padding - - - various minor improvements suggested by Stefan Willer - - - - many minor changes in order to avoid warnings from paranoid - compilers - -Changes in version 0.8 (1995-09-20): - - - namespace cleared up, all names externally visible from the library - start now with jbg_ or JBG_ - - - minor non-critical bug fixed which caused library to fail compatibility - test and showed up especially on DEC Alpha systems - - - jbg_dec_gethight() is now called jbg_dec_getheight() - - - filenames conform now to MS-DOS limits - - - Bug in pbmtojbg fixed (handling of ASCII PBM files) - -Changes in version 0.7 (1995-06-10): - - - more problems on 16-bit int systems and on Macintosh systems fixed - (special thanks to Jean-Pierre Gachen ) - - - global Makefile - -Changes in version 0.6 (1995-06-08): - - - memory leak fixed - - - should now also work on systems where int is only 16-bit large - - - changes of the JBIG "Technical Corrigendum 1" included (special - thanks to Dr. Sebestyen from Siemens AG for sending me a copy - of the draft) - -First release: version 0.5 (1995-05-28) - - -Please send all questions, problem reports, patches, suggestions, -success stories, comments, etc. to - - mkuhn at acm.org - -I will try to provide free support and maintenance for this software -at least for the next few months depending on my available time. - -Y2K statement: JBIG-KIT does not handle any date and time related -data, therefore if JBIG-KIT causes you any problems related to date -and time overflows, this would indeed be most surprising. - -This library has been published in the hope that it will encourage the -development of good freely available scanned document handling and -transmission systems for the Internet so that large amounts of scanned -text can be made available to the global village easily. - -Happy compressing ... - -Markus Kuhn - --- -Markus G. Kuhn, Security Group, Computer Lab, Cambridge University, UK -email: mkuhn at acm.org, home page: diff --git a/converter/other/jbig/Makefile b/converter/other/jbig/Makefile index b5f4e14a..c4d7e9d6 100644 --- a/converter/other/jbig/Makefile +++ b/converter/other/jbig/Makefile @@ -5,43 +5,54 @@ endif SUBDIR = converter/other/jbig VPATH=.:$(SRCDIR)/$(SUBDIR) +SUBDIRS = + include $(BUILDDIR)/config.mk -LIBJBIG_OBJECTS = jbig.o jbig_tab.o +# INTERNAL_JBIGLIB must be relative to the current directory, because it +# may end up in MERGE_OBJECTS, which must be relative. +INTERNAL_JBIGLIB = libjbig/libjbig.a +INTERNAL_JBIGHDR_DIR = $(SRCDIR)/$(SUBDIR)/libjbig/include EXTERN_INCLUDES = ifneq ($(JBIGHDR_DIR),NONE) - EXTERN_INCLUDES += -I$(JBIGHDR_DIR) + ifneq ($(JBIGHDR_DIR)x,x) + EXTERN_INCLUDES += -I$(JBIGHDR_DIR) + endif endif ifneq ($(JBIGHDR_DIR),NONE) ifneq ($(JBIGLIB),NONE) - BINARIES = jbigtopnm pnmtojbig + PORTBINARIES = jbigtopnm pnmtojbig endif endif +BINARIES = $(PORTBINARIES) + +MERGEBINARIES = $(BINARIES) + SCRIPTS = -ifeq ($(JBIGLIB),$(BUILDDIR)/$(SUBDIR)/libjbig.a) +ifeq ($(JBIGLIB),$(INTERNAL_JBIGLIB)) JBIGLIB_DEP = $(JBIGLIB) + SUBDIRS += libjbig else # It's not our internal version; user's on his own to make sure it's built endif -OBJECTS = $(BINARIES:%=%.o) $(LIBJBIG_OBJECTS) -MERGE_OBJECTS = $(BINARIES:%=%.o2) $(LIBJBIG_OBJECTS) +OBJECTS = $(BINARIES:%=%.o) +MERGE_OBJECTS = $(BINARIES:%=%.o2) all: $(BINARIES) include $(SRCDIR)/common.mk -$(BINARIES): %: %.o $(JBIGLIB_DEP) $(NETPBMLIB) $(LIBOPT) - $(LD) -o $@ $< \ - $(shell $(LIBOPT) $(NETPBMLIB) $(JBIGLIB)) $(MATHLIB) \ - $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD) - +$(BINARIES): %: %.o $(JBIGLIB_DEP) $(LIBOPT) +$(BINARIES): LDFLAGS_TARGET = $(shell $(LIBOPT) $(JBIGLIB)) -$(BUILDDIR)/$(SUBDIR)/libjbig.a: $(LIBJBIG_OBJECTS) - $(AR) -rc $@ $^ - $(RANLIB) $@ +$(INTERNAL_JBIGLIB): $(BUILDDIR)/$(SUBDIR)/libjbig FORCE + $(MAKE) -f $(SRCDIR)/$(SUBDIR)/libjbig/Makefile \ + -C $(dir $@) $(notdir $@) +.PHONY: FORCE +FORCE: diff --git a/converter/other/jbig/README b/converter/other/jbig/README new file mode 100644 index 00000000..bd7a4745 --- /dev/null +++ b/converter/other/jbig/README @@ -0,0 +1,20 @@ +The jbig tools are derived from the JBIG-KIT package by Marcus Kuhn, +by Bryan Henderson on 2000.05.11. + +The file ANNOUNCE in the 'libjbig' subdirectory is from that package and gives +details. + +The Netpbm tools jbigtopbm and pbmtojbig were adapted from JBIG-KIT's +jbgtopbm and pbmtojbg. The main difference is that the Netpbm +versions use the Netpbm libraries. + +The code in subdirectory 'libjbig' is straight from the JBIG_KIT package and +generates essentially the same libjbig.a that one gets from that package. + +The code is based on JBIG-KIT version 2.1, adapted to Netpbm by Bryan +Henderson in June 2014. + +The reason Netpbm contains a copy of the library is convenience of users. For +many people, the only reason to have a jbig library is to be able to convert +images to and from the format, which they do with Netpbm. Requiring a Netpbm +user to find and install this esoteric library is impractical. \ No newline at end of file diff --git a/converter/other/jbig/README.Netpbm b/converter/other/jbig/README.Netpbm deleted file mode 100644 index 3d593b92..00000000 --- a/converter/other/jbig/README.Netpbm +++ /dev/null @@ -1,12 +0,0 @@ -The jbig tools are derived from the JBIG-KIT package by Marcus Kuhn, -by Bryan Henderson on 2000.05.11. - -The file ANNOUNCE in this directory is from that package and gives -details. - -The Netpbm tools jbigtopbm and pbmtojbig were adapted from JBIG-KIT's -jbgtopbm and pbmtojbg. The main difference is that the Netpbm -versions use the Netpbm libraries. - -The jbig.c and jbig_table.c modules are straight from the JBIG_KIT -package. They are what normally are packaged as libjbig.a. diff --git a/converter/other/jbig/jbig.c b/converter/other/jbig/jbig.c deleted file mode 100644 index ebd7c08f..00000000 --- a/converter/other/jbig/jbig.c +++ /dev/null @@ -1,2905 +0,0 @@ -/* - * Portable Free JBIG image compression library - * - * Markus Kuhn -- mkuhn@acm.org - * - * $Id: jbig.c,v 1.12 2000-04-08 11:42:18+01 mgk25 Rel $ - * - * This module implements a portable standard C encoder and decoder - * using the JBIG lossless bi-level image compression algorithm as - * specified in International Standard ISO 11544:1993 or equivalently - * as specified in ITU-T Recommendation T.82. See the file jbig.doc - * for usage instructions and application examples. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * If you want to use this program under different license conditions, - * then contact the author for an arrangement. - * - * It is possible that certain products which can be built using this - * software module might form inventions protected by patent rights in - * some countries (e.g., by patents about arithmetic coding algorithms - * owned by IBM and AT&T in the USA). Provision of this software by the - * author does NOT include any licences for any patents. In those - * countries where a patent licence is required for certain applications - * of this software module, you will have to obtain such a licence - * yourself. - */ - -#ifdef DEBUG -#include -#endif - -#include -#include - -#include "jbig.h" - - -/* optional export of arithmetic coder functions for test purposes */ -#ifdef TEST_CODEC -#define ARITH -#define ARITH_INL -#else -#define ARITH static -#ifdef __GNUC__ -#define ARITH_INL static __inline__ -#else -#define ARITH_INL static -#endif -#endif - -#define MX_MAX 23 /* maximal supported mx offset for - * adaptive template in the encoder */ - -#define TPB2CX 0x195 /* contexts for TP special pixels */ -#define TPB3CX 0x0e5 -#define TPDCX 0xc3f - -/* marker codes */ -#define MARKER_STUFF 0x00 -#define MARKER_RESERVE 0x01 -#define MARKER_SDNORM 0x02 -#define MARKER_SDRST 0x03 -#define MARKER_ABORT 0x04 -#define MARKER_NEWLEN 0x05 -#define MARKER_ATMOVE 0x06 -#define MARKER_COMMENT 0x07 -#define MARKER_ESC 0xff - -/* loop array indices */ -#define STRIPE 0 -#define LAYER 1 -#define PLANE 2 - -/* special jbg_buf pointers (instead of NULL) */ -#define SDE_DONE ((struct jbg_buf *) -1) -#define SDE_TODO ((struct jbg_buf *) 0) - -/* object code version id */ - -const char jbg_version[] = -" JBIG-KIT " JBG_VERSION " -- Markus Kuhn -- " -"$Id: jbig.c,v 1.12 2000-04-08 11:42:18+01 mgk25 Rel $ "; - -/* - * the following array specifies for each combination of the 3 - * ordering bits, which ii[] variable represents which dimension - * of s->sde. - */ -static const int index[8][3] = { - { 2, 1, 0 }, /* no ordering bit set */ - { -1, -1, -1}, /* SMID -> illegal combination */ - { 2, 0, 1 }, /* ILEAVE */ - { 1, 0, 2 }, /* SMID + ILEAVE */ - { 0, 2, 1 }, /* SEQ */ - { 1, 2, 0 }, /* SEQ + SMID */ - { 0, 1, 2 }, /* SEQ + ILEAVE */ - { -1, -1, -1 } /* SEQ + SMID + ILEAVE -> illegal combination */ -}; - - -/* - * Array [language][message] with text string error messages that correspond - * to return values from public functions in this library. - */ -#define NEMSG 9 /* number of error codes */ -#define NEMSG_LANG 3 /* number of supported languages */ -static const char *errmsg[NEMSG_LANG][NEMSG] = { - /* English (JBG_EN) */ - { - "Everything is ok", /* JBG_EOK */ - "Reached specified maximum size", /* JBG_EOK_INTR */ - "Unexpected end of data", /* JBG_EAGAIN */ - "Not enough memory available", /* JBG_ENOMEM */ - "ABORT marker found", /* JBG_EABORT */ - "Unknown marker segment encountered", /* JBG_EMARKER */ - "Incremental BIE does not fit to previous one", /* JBG_ENOCONT */ - "Invalid data encountered", /* JBG_EINVAL */ - "Unimplemented features used" /* JBG_EIMPL */ - }, - /* German (JBG_DE_8859_1) */ - { - "Kein Problem aufgetreten", /* JBG_EOK */ - "Angegebene maximale Bildgr\366\337e erreicht", /* JBG_EOK_INTR */ - "Unerwartetes Ende der Daten", /* JBG_EAGAIN */ - "Nicht gen\374gend Speicher vorhanden", /* JBG_ENOMEM */ - "Es wurde eine Abbruch-Sequenz gefunden", /* JBG_EABORT */ - "Eine unbekannte Markierungssequenz wurde gefunden", /* JBG_EMARKER */ - "Neue Daten passen nicht zu vorangegangenen Daten", /* JBG_ENOCONT */ - "Es wurden ung\374ltige Daten gefunden", /* JBG_EINVAL */ - "Noch nicht implementierte Optionen wurden benutzt" /* JBG_EIMPL */ - }, - /* German (JBG_DE_UTF_8) */ - { - "Kein Problem aufgetreten", /* JBG_EOK */ - "Angegebene maximale Bildgr\303\266\303\237e erreicht", /* JBG_EOK_INTR */ - "Unerwartetes Ende der Daten", /* JBG_EAGAIN */ - "Nicht gen\303\274gend Speicher vorhanden", /* JBG_ENOMEM */ - "Es wurde eine Abbruch-Sequenz gefunden", /* JBG_EABORT */ - "Eine unbekannte Markierungssequenz wurde gefunden", /* JBG_EMARKER */ - "Neue Daten passen nicht zu vorangegangenen Daten", /* JBG_ENOCONT */ - "Es wurden ung\303\274ltige Daten gefunden", /* JBG_EINVAL */ - "Noch nicht implementierte Optionen wurden benutzt" /* JBG_EIMPL */ - } -}; - - - -/* - * The following three functions are the only places in this code, were - * C library memory management functions are called. The whole JBIG - * library has been designed in order to allow multi-threaded - * execution. no static or global variables are used, so all fuctions - * are fully reentrant. However if you want to use this multi-thread - * capability and your malloc, realloc and free are not reentrant, - * then simply add the necessary semaphores or mutex primitives below. - */ - -static void *checked_malloc(size_t size) -{ - void *p; - - p = malloc(size); - /* Full manual exception handling is ugly here for performance - * reasons. If an adequate handling of lack of memory is required, - * then use C++ and throw a C++ exception here. */ - if (!p) - abort(); - -#if 0 - fprintf(stderr, "%p = malloc(%ld)\n", p, (long) size); -#endif - - return p; -} - - -static void *checked_realloc(void *ptr, size_t size) -{ - void *p; - - p = realloc(ptr, size); - /* Full manual exception handling is ugly here for performance - * reasons. If an adequate handling of lack of memory is required, - * then use C++ and throw a C++ exception here. */ - if (!p) - abort(); - -#if 0 - fprintf(stderr, "%p = realloc(%p, %ld)\n", p, ptr, (long) size); -#endif - - return p; -} - - -static void checked_free(void *ptr) -{ - free(ptr); - -#if 0 - fprintf(stderr, "free(%p)\n", ptr); -#endif - -} - - - -/* - * The next functions implement the arithmedic encoder and decoder - * required for JBIG. The same algorithm is also used in the arithmetic - * variant of JPEG. - */ - -#ifdef DEBUG -static long encoded_pixels = 0; -#endif - -ARITH void arith_encode_init(struct jbg_arenc_state *s, int reuse_st) -{ - int i; - - if (!reuse_st) - for (i = 0; i < 4096; s->st[i++] = 0); - s->c = 0; - s->a = 0x10000L; - s->sc = 0; - s->ct = 11; - s->buffer = -1; /* empty */ - - return; -} - - -ARITH void arith_encode_flush(struct jbg_arenc_state *s) -{ - unsigned long temp; - -#ifdef DEBUG - fprintf(stderr, " encoded pixels = %ld, a = %05lx, c = %08lx\n", - encoded_pixels, s->a, s->c); -#endif - - /* find the s->c in the coding interval with the largest - * number of trailing zero bits */ - if ((temp = (s->a - 1 + s->c) & 0xffff0000L) < s->c) - s->c = temp + 0x8000; - else - s->c = temp; - /* send remaining bytes to output */ - s->c <<= s->ct; - if (s->c & 0xf8000000L) { - /* one final overflow has to be handled */ - if (s->buffer >= 0) { - s->byte_out(s->buffer + 1, s->file); - if (s->buffer + 1 == MARKER_ESC) - s->byte_out(MARKER_STUFF, s->file); - } - /* output 0x00 bytes only when more non-0x00 will follow */ - if (s->c & 0x7fff800L) - for (; s->sc; --s->sc) - s->byte_out(0x00, s->file); - } else { - if (s->buffer >= 0) - s->byte_out(s->buffer, s->file); - /* T.82 figure 30 says buffer+1 for the above line! Typo? */ - for (; s->sc; --s->sc) { - s->byte_out(0xff, s->file); - s->byte_out(MARKER_STUFF, s->file); - } - } - /* output final bytes only if they are not 0x00 */ - if (s->c & 0x7fff800L) { - s->byte_out((s->c >> 19) & 0xff, s->file); - if (((s->c >> 19) & 0xff) == MARKER_ESC) - s->byte_out(MARKER_STUFF, s->file); - if (s->c & 0x7f800L) { - s->byte_out((s->c >> 11) & 0xff, s->file); - if (((s->c >> 11) & 0xff) == MARKER_ESC) - s->byte_out(MARKER_STUFF, s->file); - } - } - - return; -} - - -ARITH_INL void arith_encode(struct jbg_arenc_state *s, int cx, int pix) -{ - extern short jbg_lsz[]; - extern unsigned char jbg_nmps[], jbg_nlps[]; - register unsigned lsz, ss; - register unsigned char *st; - long temp; - -#ifdef DEBUG - ++encoded_pixels; -#endif - - assert(cx >= 0 && cx < 4096); - st = s->st + cx; - ss = *st & 0x7f; - assert(ss < 113); - lsz = jbg_lsz[ss]; - -#if 0 - fprintf(stderr, "pix = %d, cx = %d, mps = %d, st = %3d, lsz = 0x%04x, " - "a = 0x%05lx, c = 0x%08lx, ct = %2d, buf = 0x%02x\n", - pix, cx, !!(s->st[cx] & 0x80), ss, lsz, s->a, s->c, s->ct, - s->buffer); -#endif - - if (((pix << 7) ^ s->st[cx]) & 0x80) { - /* encode the less probable symbol */ - if ((s->a -= lsz) >= lsz) { - /* If the interval size (lsz) for the less probable symbol (LPS) - * is larger than the interval size for the MPS, then exchange - * the two symbols for coding efficiency, otherwise code the LPS - * as usual: */ - s->c += s->a; - s->a = lsz; - } - /* Check whether MPS/LPS exchange is necessary - * and chose next probability estimator status */ - *st &= 0x80; - *st ^= jbg_nlps[ss]; - } else { - /* encode the more probable symbol */ - if ((s->a -= lsz) & 0xffff8000L) - return; /* A >= 0x8000 -> ready, no renormalization required */ - if (s->a < lsz) { - /* If the interval size (lsz) for the less probable symbol (LPS) - * is larger than the interval size for the MPS, then exchange - * the two symbols for coding efficiency: */ - s->c += s->a; - s->a = lsz; - } - /* chose next probability estimator status */ - *st &= 0x80; - *st |= jbg_nmps[ss]; - } - - /* renormalization of coding interval */ - do { - s->a <<= 1; - s->c <<= 1; - --s->ct; - if (s->ct == 0) { - /* another byte is ready for output */ - temp = s->c >> 19; - if (temp & 0xffffff00L) { - /* handle overflow over all buffered 0xff bytes */ - if (s->buffer >= 0) { - ++s->buffer; - s->byte_out(s->buffer, s->file); - if (s->buffer == MARKER_ESC) - s->byte_out(MARKER_STUFF, s->file); - } - for (; s->sc; --s->sc) - s->byte_out(0x00, s->file); - s->buffer = temp & 0xff; /* new output byte, might overflow later */ - assert(s->buffer != 0xff); - /* can s->buffer really never become 0xff here? */ - } else if (temp == 0xff) { - /* buffer 0xff byte (which might overflow later) */ - ++s->sc; - } else { - /* output all buffered 0xff bytes, they will not overflow any more */ - if (s->buffer >= 0) - s->byte_out(s->buffer, s->file); - for (; s->sc; --s->sc) { - s->byte_out(0xff, s->file); - s->byte_out(MARKER_STUFF, s->file); - } - s->buffer = temp; /* buffer new output byte (can still overflow) */ - } - s->c &= 0x7ffffL; - s->ct = 8; - } - } while (s->a < 0x8000); - - return; -} - - -ARITH void arith_decode_init(struct jbg_ardec_state *s, int reuse_st) -{ - int i; - - if (!reuse_st) - for (i = 0; i < 4096; s->st[i++] = 0); - s->c = 0; - s->a = 1; - s->ct = 0; - s->result = JBG_OK; - s->startup = 1; - return; -} - - -ARITH_INL int arith_decode(struct jbg_ardec_state *s, int cx) -{ - extern short jbg_lsz[]; - extern unsigned char jbg_nmps[], jbg_nlps[]; - register unsigned lsz, ss; - register unsigned char *st; - int pix; - - /* renormalization */ - while (s->a < 0x8000 || s->startup) { - if (s->ct < 1 && s->result != JBG_READY) { - /* first we have to move a new byte into s->c */ - if (s->pscd_ptr >= s->pscd_end) { - s->result = JBG_MORE; - return -1; - } - if (*s->pscd_ptr == 0xff) - if (s->pscd_ptr + 1 >= s->pscd_end) { - s->result = JBG_MARKER; - return -1; - } else { - if (*(s->pscd_ptr + 1) == MARKER_STUFF) { - s->c |= 0xffL << (8 - s->ct); - s->ct += 8; - s->pscd_ptr += 2; - s->result = JBG_OK; - } else - s->result = JBG_READY; - } - else { - s->c |= (long)*(s->pscd_ptr++) << (8 - s->ct); - s->ct += 8; - s->result = JBG_OK; - } - } - s->c <<= 1; - s->a <<= 1; - --s->ct; - if (s->a == 0x10000L) - s->startup = 0; - } - - st = s->st + cx; - ss = *st & 0x7f; - assert(ss < 113); - lsz = jbg_lsz[ss]; - -#if 0 - fprintf(stderr, "cx = %d, mps = %d, st = %3d, lsz = 0x%04x, a = 0x%05lx, " - "c = 0x%08lx, ct = %2d\n", - cx, !!(s->st[cx] & 0x80), ss, lsz, s->a, s->c, s->ct); -#endif - - if ((s->c >> 16) < (s->a -= lsz)) - if (s->a & 0xffff8000L) - return *st >> 7; - else { - /* MPS_EXCHANGE */ - if (s->a < lsz) { - pix = 1 - (*st >> 7); - /* Check whether MPS/LPS exchange is necessary - * and chose next probability estimator status */ - *st &= 0x80; - *st ^= jbg_nlps[ss]; - } else { - pix = *st >> 7; - *st &= 0x80; - *st |= jbg_nmps[ss]; - } - } - else { - /* LPS_EXCHANGE */ - if (s->a < lsz) { - s->c -= s->a << 16; - s->a = lsz; - pix = *st >> 7; - *st &= 0x80; - *st |= jbg_nmps[ss]; - } else { - s->c -= s->a << 16; - s->a = lsz; - pix = 1 - (*st >> 7); - /* Check whether MPS/LPS exchange is necessary - * and chose next probability estimator status */ - *st &= 0x80; - *st ^= jbg_nlps[ss]; - } - } - - return pix; -} - - - -/* - * Memory management for buffers which are used for temporarily - * storing SDEs by the encoder. - * - * The following functions manage a set of struct jbg_buf storage - * containers were each can keep JBG_BUFSIZE bytes. The jbg_buf - * containers can be linked to form linear double-chained lists for - * which a number of operations are provided. Blocks which are - * tempoarily not used any more are returned to a freelist which each - * encoder keeps. Only the destructor of the encoder actually returns - * the block via checked_free() to the stdlib memory management. - */ - - -/* - * Allocate a new buffer block and initialize it. Try to get it from - * the free_list, and if it is empty, call checked_malloc(). - */ -static struct jbg_buf *jbg_buf_init(struct jbg_buf **free_list) -{ - struct jbg_buf *new_block; - - /* Test whether a block from the free list is available */ - if (*free_list) { - new_block = *free_list; - *free_list = new_block->next; - } else { - /* request a new memory block */ - new_block = (struct jbg_buf *) checked_malloc(sizeof(struct jbg_buf)); - } - new_block->len = 0; - new_block->next = NULL; - new_block->previous = NULL; - new_block->last = new_block; - new_block->free_list = free_list; - - return new_block; -} - - -/* - * Return an entire free_list to the memory management of stdlib. - * This is only done by jbg_enc_free(). - */ -static void jbg_buf_free(struct jbg_buf **free_list) -{ - struct jbg_buf *tmp; - - while (*free_list) { - tmp = (*free_list)->next; - checked_free(*free_list); - *free_list = tmp; - } - - return; -} - - -/* - * Append a single byte to a single list that starts with the block - * *(struct jbg_buf *) head. The type of *head is void here in order to - * keep the interface of the arithmetic encoder gereric, which uses this - * function as a call-back function in order to deliver single bytes - * for a PSCD. - */ -static void jbg_buf_write(int b, void *head) -{ - struct jbg_buf *now; - - now = ((struct jbg_buf *) head)->last; - if (now->len < JBG_BUFSIZE - 1) { - now->d[now->len++] = b; - return; - } - now->next = jbg_buf_init(((struct jbg_buf *) head)->free_list); - now->next->previous = now; - now->next->d[now->next->len++] = b; - ((struct jbg_buf *) head)->last = now->next; - - return; -} - - -/* - * Remove any trailing zero bytes from the end of a linked jbg_buf list, - * however make sure that no zero byte is removed which directly - * follows a 0xff byte (i.e., keep MARKER_ESC MARKER_STUFF sequences - * intact). This function is used to remove any redundant final zero - * bytes from a PSCD. - */ -static void jbg_buf_remove_zeros(struct jbg_buf *head) -{ - struct jbg_buf *last; - - while (1) { - /* remove trailing 0x00 in last block of list until this block is empty */ - last = head->last; - while (last->len && last->d[last->len - 1] == 0) - last->len--; - /* if block became really empty, remove it in case it is not the - * only remaining block and then loop to next block */ - if (last->previous && !last->len) { - head->last->next = *head->free_list; - *head->free_list = head->last; - head->last = last->previous; - head->last->next = NULL; - } else - break; - } - - /* - * If the final non-zero byte is 0xff (MARKER_ESC), then we just have - * removed a MARKER_STUFF and we will append it again now in order - * to preserve PSCD status of byte stream. - */ - if (head->last->len && head->last->d[head->last->len - 1] == MARKER_ESC) - jbg_buf_write(MARKER_STUFF, head); - - return; -} - - -/* - * The jbg_buf list which starts with block *new_prefix is concatenated - * with the list which starts with block **start and *start will then point - * to the first block of the new list. - */ -static void jbg_buf_prefix(struct jbg_buf *new_prefix, struct jbg_buf **start) -{ - new_prefix->last->next = *start; - new_prefix->last->next->previous = new_prefix->last; - new_prefix->last = new_prefix->last->next->last; - *start = new_prefix; - - return; -} - - -/* - * Send the contents of a jbg_buf list that starts with block **head to - * the call back function data_out and return the blocks of the jbg_buf - * list to the freelist from which these jbg_buf blocks have been taken. - * After the call, *head == NULL. - */ -static void jbg_buf_output(struct jbg_buf **head, - void (*data_out)(unsigned char *start, - size_t len, void *file), - void *file) -{ - struct jbg_buf *tmp; - - while (*head) { - data_out((*head)->d, (*head)->len, file); - tmp = (*head)->next; - (*head)->next = *(*head)->free_list; - *(*head)->free_list = *head; - *head = tmp; - } - - return; -} - - -/* - * Calculate y = ceil(x/2) applied n times. This function is used to - * determine the number of pixels per row or column after n resolution - * reductions. E.g. X[d-1] = jbg_ceil_half(X[d], 1) and X[0] = - * jbg_ceil_half(X[d], d) as defined in clause 6.2.3 of T.82. - */ -unsigned long jbg_ceil_half(unsigned long x, int n) -{ - unsigned long mask; - - mask = (1UL << n) - 1; /* the lowest n bits are 1 here */ - return (x >> n) + ((mask & x) != 0); -} - - -/* - * Initialize the status struct for the encoder. - */ -void jbg_enc_init(struct jbg_enc_state *s, unsigned long x, unsigned long y, - int planes, unsigned char **p, - void (*data_out)(unsigned char *start, size_t len, - void *file), - void *file) -{ - unsigned long l, lx; - int i; - size_t bufsize; - - extern char jbg_resred[], jbg_dptable[]; - - s->xd = x; - s->yd = y; - s->planes = planes; - s->data_out = data_out; - s->file = file; - - s->d = 0; - s->dl = 0; - s->dh = s->d; - s->l0 = jbg_ceil_half(s->yd, s->d) / 35; /* 35 stripes/image */ - while ((s->l0 << s->d) > 128) /* but <= 128 lines/stripe */ - --s->l0; - if (s->l0 < 2) s->l0 = 2; - s->mx = 8; - s->my = 0; - s->order = JBG_ILEAVE | JBG_SMID; - s->options = JBG_TPBON | JBG_TPDON | JBG_DPON; - s->dppriv = jbg_dptable; - s->res_tab = jbg_resred; - - s->highres = checked_malloc(planes * sizeof(int)); - s->lhp[0] = p; - s->lhp[1] = checked_malloc(planes * sizeof(unsigned char *)); - bufsize = ((jbg_ceil_half(x, 1) + 7) / 8) * jbg_ceil_half(y, 1); - for (i = 0; i < planes; i++) { - s->highres[i] = 0; - s->lhp[1][i] = checked_malloc(sizeof(unsigned char) * bufsize); - } - - s->free_list = NULL; - s->s = (struct jbg_arenc_state *) - checked_malloc(s->planes * sizeof(struct jbg_arenc_state)); - s->tx = (int *) checked_malloc(s->planes * sizeof(int)); - lx = jbg_ceil_half(x, 1); - s->tp = (char *) checked_malloc(lx * sizeof(char)); - for (l = 0; l < lx; s->tp[l++] = 2); - s->sde = NULL; - - return; -} - - -/* - * This function selects the number of differential layers based on - * the maximum size requested for the lowest resolution layer. If - * possible, a number of differential layers is selected, which will - * keep the size of the lowest resolution layer below or equal to the - * given width x and height y. However not more than 6 differential - * resolution layers will be used. In addition, a reasonable value for - * l0 (height of one stripe in the lowest resolution layer) is - * selected, which obeys the recommended limitations for l0 in annex A - * and C of the JBIG standard. The selected number of resolution layers - * is returned. - */ -int jbg_enc_lrlmax(struct jbg_enc_state *s, unsigned long x, - unsigned long y) -{ - for (s->d = 0; s->d < 6; s->d++) - if (jbg_ceil_half(s->xd, s->d) <= x && jbg_ceil_half(s->yd, s->d) <= y) - break; - s->dl = 0; - s->dh = s->d; - - s->l0 = jbg_ceil_half(s->yd, s->d) / 35; /* 35 stripes/image */ - while ((s->l0 << s->d) > 128) /* but <= 128 lines/stripe */ - --s->l0; - if (s->l0 < 2) s->l0 = 2; - - return s->d; -} - - -/* - * As an alternative to jbg_enc_lrlmax(), the following function allows - * to specify the number of layers directly. The stripe height and layer - * range is also adjusted automatically here. - */ -void jbg_enc_layers(struct jbg_enc_state *s, int d) -{ - if (d < 0 || d > 255) - return; - s->d = d; - s->dl = 0; - s->dh = s->d; - - s->l0 = jbg_ceil_half(s->yd, s->d) / 35; /* 35 stripes/image */ - while ((s->l0 << s->d) > 128) /* but <= 128 lines/stripe */ - --s->l0; - if (s->l0 < 2) s->l0 = 2; - - return; -} - - -/* - * Specify the highest and lowest resolution layers which will be - * written to the output file. Call this function not before - * jbg_enc_layers() or jbg_enc_lrlmax(), because these two functions - * reset the lowest and highest resolution layer to default values. - * Negative values are ignored. The total number of layers is returned. - */ -int jbg_enc_lrange(struct jbg_enc_state *s, int dl, int dh) -{ - if (dl >= 0 && dl <= s->d) s->dl = dl; - if (dh >= s->dl && dh <= s->d) s->dh = dh; - - return s->d; -} - - -/* - * The following function allows to specify the bits describing the - * options of the format as well as the maximum AT movement window and - * the number of layer 0 lines per stripes. - */ -void jbg_enc_options(struct jbg_enc_state *s, int order, int options, - long l0, int mx, int my) -{ - if (order >= 0 && order <= 0x0f) s->order = order; - if (options >= 0) s->options = options; - if (l0 >= 0) s->l0 = l0; - if (mx >= 0 && my < 128) s->mx = mx; - if (my >= 0 && my < 256) s->my = my; - - return; -} - - -/* - * This function actually does all the tricky work involved in producing - * a SDE, which is stored in the appropriate s->sde[][][] element - * for later output in the correct order. - */ -static void encode_sde(struct jbg_enc_state *s, - long stripe, int layer, int plane) -{ - unsigned char *hp, *lp1, *lp2, *p0, *p1, *q1, *q2; - unsigned long hl, ll, hx, hy, lx, ly, hbpl, lbpl; - unsigned long line_h0 = 0, line_h1 = 0; - unsigned long line_h2, line_h3, line_l1, line_l2, line_l3; - struct jbg_arenc_state *se; - unsigned long i, j, y; - unsigned t; - int ltp, ltp_old, cx; - unsigned long c_all, c[MX_MAX + 1], cmin, cmax, clmin, clmax; - int tmax, at_determined; - int new_tx; - long new_tx_line = -1; - struct jbg_buf *new_jbg_buf; - -#ifdef DEBUG - static long tp_lines, tp_exceptions, tp_pixels, dp_pixels; - static long encoded_pixels; -#endif - - /* return immediately if this stripe has already been encoded */ - if (s->sde[stripe][layer][plane] != SDE_TODO) - return; - -#ifdef DEBUG - if (stripe == 0) - tp_lines = tp_exceptions = tp_pixels = dp_pixels = encoded_pixels = 0; - fprintf(stderr, "encode_sde: s/d/p = %2ld/%2d/%2d\n", - stripe, layer, plane); -#endif - - /* number of lines per stripe in highres image */ - hl = s->l0 << layer; - /* number of lines per stripe in lowres image */ - ll = hl >> 1; - /* current line number in highres image */ - y = stripe * hl; - /* number of pixels in highres image */ - hx = jbg_ceil_half(s->xd, s->d - layer); - hy = jbg_ceil_half(s->yd, s->d - layer); - /* number of pixels in lowres image */ - lx = jbg_ceil_half(hx, 1); - ly = jbg_ceil_half(hy, 1); - /* bytes per line in highres and lowres image */ - hbpl = (hx + 7) / 8; - lbpl = (lx + 7) / 8; - /* pointer to first image byte of highres stripe */ - hp = s->lhp[s->highres[plane]][plane] + stripe * hl * hbpl; - lp2 = s->lhp[1 - s->highres[plane]][plane] + stripe * ll * lbpl; - lp1 = lp2 + lbpl; - - /* initialize arithmetic encoder */ - se = s->s + plane; - arith_encode_init(se, stripe != 0); - s->sde[stripe][layer][plane] = jbg_buf_init(&s->free_list); - se->byte_out = jbg_buf_write; - se->file = s->sde[stripe][layer][plane]; - - /* initialize adaptive template movement algorithm */ - c_all = 0; - for (t = 0; t <= s->mx; t++) - c[t] = 0; - if (stripe == 0) - s->tx[plane] = 0; - new_tx = -1; - at_determined = 0; /* we haven't yet decided the template move */ - if (s->mx == 0) - at_determined = 1; - - /* initialize typical prediction */ - ltp = 0; - if (stripe == 0) - ltp_old = 0; - else { - ltp_old = 1; - p1 = hp - hbpl; - if (y > 1) { - q1 = p1 - hbpl; - while (p1 < hp && (ltp_old = (*p1++ == *q1++)) != 0); - } else - while (p1 < hp && (ltp_old = (*p1++ == 0)) != 0); - } - - if (layer == 0) { - - /* - * Encode lowest resolution layer - */ - - for (i = 0; i < hl && y < hy; i++, y++) { - - /* check whether it is worth to perform an ATMOVE */ - if (!at_determined && c_all > 2048) { - cmin = clmin = 0xffffffffL; - cmax = clmax = 0; - tmax = 0; - for (t = (s->options & JBG_LRLTWO) ? 5 : 3; t <= s->mx; t++) { - if (c[t] > cmax) cmax = c[t]; - if (c[t] < cmin) cmin = c[t]; - if (c[t] > c[tmax]) tmax = t; - } - clmin = (c[0] < cmin) ? c[0] : cmin; - clmax = (c[0] > cmax) ? c[0] : cmax; - if (c_all - cmax < (c_all >> 3) && - cmax - c[s->tx[plane]] > c_all - cmax && - cmax - c[s->tx[plane]] > (c_all >> 4) && - /* ^ T.82 says here < !!! Typo ? */ - cmax - (c_all - c[s->tx[plane]]) > c_all - cmax && - cmax - (c_all - c[s->tx[plane]]) > (c_all >> 4) && - cmax - cmin > (c_all >> 2) && - (s->tx[plane] || clmax - clmin > (c_all >> 3))) { - /* we have decided to perform an ATMOVE */ - new_tx = tmax; - if (!(s->options & JBG_DELAY_AT)) { - new_tx_line = i; - s->tx[plane] = new_tx; - } - } - at_determined = 1; - } - - /* typical prediction */ - if (s->options & JBG_TPBON) { - ltp = 1; - p1 = hp; - if (y > 0) { - q1 = hp - hbpl; - while (q1 < hp && (ltp = (*p1++ == *q1++)) != 0); - } else - while (p1 < hp + hbpl && (ltp = (*p1++ == 0)) != 0); - arith_encode(se, (s->options & JBG_LRLTWO) ? TPB2CX : TPB3CX, - ltp == ltp_old); -#ifdef DEBUG - tp_lines += ltp; -#endif - ltp_old = ltp; - if (ltp) { - /* skip next line */ - hp += hbpl; - continue; - } - } - - /* - * Layout of the variables line_h1, line_h2, line_h3, which contain - * as bits the neighbour pixels of the currently coded pixel X: - * - * 76543210765432107654321076543210 line_h3 - * 76543210765432107654321076543210 line_h2 - * 76543210765432107654321X76543210 line_h1 - */ - - line_h1 = line_h2 = line_h3 = 0; - if (y > 0) line_h2 = (long)*(hp - hbpl) << 8; - if (y > 1) line_h3 = (long)*(hp - hbpl - hbpl) << 8; - - /* encode line */ - for (j = 0; j < hx; hp++) { - line_h1 |= *hp; - if (j < hbpl * 8 - 8 && y > 0) { - line_h2 |= *(hp - hbpl + 1); - if (y > 1) - line_h3 |= *(hp - hbpl - hbpl + 1); - } - if (s->options & JBG_LRLTWO) { - /* two line template */ - do { - line_h1 <<= 1; line_h2 <<= 1; line_h3 <<= 1; - if (s->tx[plane]) - arith_encode(se, (((line_h2 >> 10) & 0x3e0) | - ((line_h1 >> (4 + s->tx[plane])) & 0x010) | - ((line_h1 >> 9) & 0x00f)), - (line_h1 >> 8) & 1); - else - arith_encode(se, (((line_h2 >> 10) & 0x3f0) | - ((line_h1 >> 9) & 0x00f)), - (line_h1 >> 8) & 1); -#ifdef DEBUG - encoded_pixels++; -#endif - /* statistics for adaptive template changes */ - if (!at_determined && j >= s->mx && j < hx-2) { - c[0] += !(((line_h2 >> 6) ^ line_h1) & 0x100); - for (t = 5; t <= s->mx; t++) - c[t] += !(((line_h1 >> t) ^ line_h1) & 0x100); - ++c_all; - } - } while (++j & 7 && j < hx); - } else { - /* three line template */ - do { - line_h1 <<= 1; line_h2 <<= 1; line_h3 <<= 1; - if (s->tx[plane]) - arith_encode(se, (((line_h3 >> 8) & 0x380) | - ((line_h2 >> 12) & 0x078) | - ((line_h1 >> (6 + s->tx[plane])) & 0x004) | - ((line_h1 >> 9) & 0x003)), - (line_h1 >> 8) & 1); - else - arith_encode(se, (((line_h3 >> 8) & 0x380) | - ((line_h2 >> 12) & 0x07c) | - ((line_h1 >> 9) & 0x003)), - (line_h1 >> 8) & 1); -#ifdef DEBUG - encoded_pixels++; -#endif - /* statistics for adaptive template changes */ - if (!at_determined && j >= s->mx && j < hx-2) { - c[0] += !(((line_h2 >> 6) ^ line_h1) & 0x100); - for (t = 3; t <= s->mx; t++) - c[t] += !(((line_h1 >> t) ^ line_h1) & 0x100); - ++c_all; - } - } while (++j & 7 && j < hx); - } /* if (s->options & JBG_LRLTWO) */ - } /* for (j = ...) */ - } /* for (i = ...) */ - - } else { - - /* - * Encode differential layer - */ - - for (i = 0; i < hl && y < hy; i++, y++) { - - /* check whether it is worth to perform an ATMOVE */ - if (!at_determined && c_all > 2048) { - cmin = clmin = 0xffffffffL; - cmax = clmax = 0; - tmax = 0; - for (t = 3; t <= s->mx; t++) { - if (c[t] > cmax) cmax = c[t]; - if (c[t] < cmin) cmin = c[t]; - if (c[t] > c[tmax]) tmax = t; - } - clmin = (c[0] < cmin) ? c[0] : cmin; - clmax = (c[0] > cmax) ? c[0] : cmax; - if (c_all - cmax < (c_all >> 3) && - cmax - c[s->tx[plane]] > c_all - cmax && - cmax - c[s->tx[plane]] > (c_all >> 4) && - /* ^ T.82 says here < !!! Typo ? */ - cmax - (c_all - c[s->tx[plane]]) > c_all - cmax && - cmax - (c_all - c[s->tx[plane]]) > (c_all >> 4) && - cmax - cmin > (c_all >> 2) && - (s->tx[plane] || clmax - clmin > (c_all >> 3))) { - /* we have decided to perform an ATMOVE */ - new_tx = tmax; - if (!(s->options & JBG_DELAY_AT)) { - new_tx_line = i; - s->tx[plane] = new_tx; - } -#ifdef DEBUG - fprintf(stderr, "ATMOVE: line=%ld, tx=%d, c_all=%ld\n", - i, new_tx, c_all); -#endif - } - at_determined = 1; - } - - if ((i >> 1) >= ll - 1 || (y >> 1) >= ly - 1) - lp1 = lp2; - - /* typical prediction */ - if (s->options & JBG_TPDON && (i & 1) == 0) { - q1 = lp1; q2 = lp2; - p0 = p1 = hp; - if (i < hl - 1 && y < hy - 1) - p0 = hp + hbpl; - if (y > 1) - line_l3 = (long)*(q2 - lbpl) << 8; - else - line_l3 = 0; - line_l2 = (long)*q2 << 8; - line_l1 = (long)*q1 << 8; - ltp = 1; - for (j = 0; j < lx && ltp; q1++, q2++) { - if (j < lbpl * 8 - 8) { - if (y > 1) - line_l3 |= *(q2 - lbpl + 1); - line_l2 |= *(q2 + 1); - line_l1 |= *(q1 + 1); - } - do { - if ((j >> 2) < hbpl) { - line_h1 = *(p1++); - line_h0 = *(p0++); - } - do { - line_l3 <<= 1; - line_l2 <<= 1; - line_l1 <<= 1; - line_h1 <<= 2; - line_h0 <<= 2; - cx = (((line_l3 >> 15) & 0x007) | - ((line_l2 >> 12) & 0x038) | - ((line_l1 >> 9) & 0x1c0)); - if (cx == 0x000) - if ((line_h1 & 0x300) == 0 && (line_h0 & 0x300) == 0) - s->tp[j] = 0; - else { - ltp = 0; -#ifdef DEBUG - tp_exceptions++; -#endif - } - else if (cx == 0x1ff) - if ((line_h1 & 0x300) == 0x300 && (line_h0 & 0x300) == 0x300) - s->tp[j] = 1; - else { - ltp = 0; -#ifdef DEBUG - tp_exceptions++; -#endif - } - else - s->tp[j] = 2; - } while (++j & 3 && j < lx); - } while (j & 7 && j < lx); - } /* for (j = ...) */ - arith_encode(se, TPDCX, !ltp); -#ifdef DEBUG - tp_lines += ltp; -#endif - } - - - /* - * Layout of the variables line_h1, line_h2, line_h3, which contain - * as bits the high resolution neighbour pixels of the currently coded - * highres pixel X: - * - * 76543210 76543210 76543210 76543210 line_h3 - * 76543210 76543210 76543210 76543210 line_h2 - * 76543210 76543210 7654321X 76543210 line_h1 - * - * Layout of the variables line_l1, line_l2, line_l3, which contain - * the low resolution pixels near the currently coded pixel as bits. - * The lowres pixel in which the currently coded highres pixel is - * located is marked as Y: - * - * 76543210 76543210 76543210 76543210 line_l3 - * 76543210 7654321Y 76543210 76543210 line_l2 - * 76543210 76543210 76543210 76543210 line_l1 - */ - - - line_h1 = line_h2 = line_h3 = line_l1 = line_l2 = line_l3 = 0; - if (y > 0) line_h2 = (long)*(hp - hbpl) << 8; - if (y > 1) { - line_h3 = (long)*(hp - hbpl - hbpl) << 8; - line_l3 = (long)*(lp2 - lbpl) << 8; - } - line_l2 = (long)*lp2 << 8; - line_l1 = (long)*lp1 << 8; - - /* encode line */ - for (j = 0; j < hx; lp1++, lp2++) { - if ((j >> 1) < lbpl * 8 - 8) { - if (y > 1) - line_l3 |= *(lp2 - lbpl + 1); - line_l2 |= *(lp2 + 1); - line_l1 |= *(lp1 + 1); - } - do { - - assert(hp - (s->lhp[s->highres[plane]][plane] + - (stripe * hl + i) * hbpl) - == (ptrdiff_t) j >> 3); - - assert(lp2 - (s->lhp[1-s->highres[plane]][plane] + - (stripe * ll + (i>>1)) * lbpl) - == (ptrdiff_t) j >> 4); - - line_h1 |= *(hp++); - if (j < hbpl * 8 - 8) { - if (y > 0) { - line_h2 |= *(hp - hbpl); - if (y > 1) - line_h3 |= *(hp - hbpl - hbpl); - } - } - do { - line_l1 <<= 1; line_l2 <<= 1; line_l3 <<= 1; - if (ltp && s->tp[j >> 1] < 2) { - /* pixel are typical and have not to be encoded */ - line_h1 <<= 2; line_h2 <<= 2; line_h3 <<= 2; -#ifdef DEBUG - do { - ++tp_pixels; - } while (++j & 1 && j < hx); -#else - j += 2; -#endif - } else - do { - line_h1 <<= 1; line_h2 <<= 1; line_h3 <<= 1; - - /* deterministic prediction */ - if (s->options & JBG_DPON) { - if ((y & 1) == 0) { - if ((j & 1) == 0) { - /* phase 0 */ - if (s->dppriv[((line_l3 >> 16) & 0x003) | - ((line_l2 >> 14) & 0x00c) | - ((line_h1 >> 5) & 0x010) | - ((line_h2 >> 10) & 0x0e0)] < 2) { -#ifdef DEBUG - ++dp_pixels; -#endif - continue; - } - } else { - /* phase 1 */ - if (s->dppriv[(((line_l3 >> 16) & 0x003) | - ((line_l2 >> 14) & 0x00c) | - ((line_h1 >> 5) & 0x030) | - ((line_h2 >> 10) & 0x1c0)) + 256] < 2) { -#ifdef DEBUG - ++dp_pixels; -#endif - continue; - } - } - } else { - if ((j & 1) == 0) { - /* phase 2 */ - if (s->dppriv[(((line_l3 >> 16) & 0x003) | - ((line_l2 >> 14) & 0x00c) | - ((line_h1 >> 5) & 0x010) | - ((line_h2 >> 10) & 0x0e0) | - ((line_h3 >> 7) & 0x700)) + 768] < 2) { -#ifdef DEBUG - ++dp_pixels; -#endif - continue; - } - } else { - /* phase 3 */ - if (s->dppriv[(((line_l3 >> 16) & 0x003) | - ((line_l2 >> 14) & 0x00c) | - ((line_h1 >> 5) & 0x030) | - ((line_h2 >> 10) & 0x1c0) | - ((line_h3 >> 7) & 0xe00)) + 2816] < 2) { -#ifdef DEBUG - ++dp_pixels; -#endif - continue; - } - } - } - } - - /* determine context */ - if (s->tx[plane]) - cx = (((line_h1 >> 9) & 0x003) | - ((line_h1 >> (4 + s->tx[plane])) & 0x010) | - ((line_h2 >> 13) & 0x00c) | - ((line_h3 >> 11) & 0x020)); - else - cx = (((line_h1 >> 9) & 0x003) | - ((line_h2 >> 13) & 0x01c) | - ((line_h3 >> 11) & 0x020)); - if (j & 1) - cx |= (((line_l2 >> 9) & 0x0c0) | - ((line_l1 >> 7) & 0x300)) | (1UL << 10); - else - cx |= (((line_l2 >> 10) & 0x0c0) | - ((line_l1 >> 8) & 0x300)); - cx |= (y & 1) << 11; - - arith_encode(se, cx, (line_h1 >> 8) & 1); -#ifdef DEBUG - encoded_pixels++; -#endif - - /* statistics for adaptive template changes */ - if (!at_determined && j >= s->mx) { - c[0] += !(((line_h2 >> 6) ^ line_h1) & 0x100); - for (t = 3; t <= s->mx; t++) - c[t] += !(((line_h1 >> t) ^ line_h1) & 0x100); - ++c_all; - } - - } while (++j & 1 && j < hx); - } while (j & 7 && j < hx); - } while (j & 15 && j < hx); - } /* for (j = ...) */ - - /* low resolution pixels are used twice */ - if ((i & 1) == 0) { - lp1 -= lbpl; - lp2 -= lbpl; - } - - } /* for (i = ...) */ - } - - arith_encode_flush(se); - jbg_buf_remove_zeros(s->sde[stripe][layer][plane]); - jbg_buf_write(MARKER_ESC, s->sde[stripe][layer][plane]); - jbg_buf_write(MARKER_SDNORM, s->sde[stripe][layer][plane]); - - /* add ATMOVE */ - if (new_tx != -1) { - if (s->options & JBG_DELAY_AT) { - /* ATMOVE will become active at the first line of the next stripe */ - s->tx[plane] = new_tx; - jbg_buf_write(MARKER_ESC, s->sde[stripe][layer][plane]); - jbg_buf_write(MARKER_ATMOVE, s->sde[stripe][layer][plane]); - jbg_buf_write(0, s->sde[stripe][layer][plane]); - jbg_buf_write(0, s->sde[stripe][layer][plane]); - jbg_buf_write(0, s->sde[stripe][layer][plane]); - jbg_buf_write(0, s->sde[stripe][layer][plane]); - jbg_buf_write(s->tx[plane], s->sde[stripe][layer][plane]); - jbg_buf_write(0, s->sde[stripe][layer][plane]); - } else { - /* ATMOVE has already become active during this stripe - * => we have to prefix the SDE data with an ATMOVE marker */ - new_jbg_buf = jbg_buf_init(&s->free_list); - jbg_buf_write(MARKER_ESC, new_jbg_buf); - jbg_buf_write(MARKER_ATMOVE, new_jbg_buf); - jbg_buf_write((new_tx_line >> 24) & 0xff, new_jbg_buf); - jbg_buf_write((new_tx_line >> 16) & 0xff, new_jbg_buf); - jbg_buf_write((new_tx_line >> 8) & 0xff, new_jbg_buf); - jbg_buf_write(new_tx_line & 0xff, new_jbg_buf); - jbg_buf_write(new_tx, new_jbg_buf); - jbg_buf_write(0, new_jbg_buf); - jbg_buf_prefix(new_jbg_buf, &s->sde[stripe][layer][plane]); - } - } - -#if 0 - if (stripe == s->stripes - 1) - fprintf(stderr, "tp_lines = %ld, tp_exceptions = %ld, tp_pixels = %ld, " - "dp_pixels = %ld, encoded_pixels = %ld\n", - tp_lines, tp_exceptions, tp_pixels, dp_pixels, encoded_pixels); -#endif - - return; -} - - -/* - * Create the next lower resolution version of an image - */ -static void resolution_reduction(struct jbg_enc_state *s, int plane, - int higher_layer) -{ - unsigned long hx, hy, lx, ly, hbpl, lbpl; - unsigned char *hp1, *hp2, *hp3, *lp; - unsigned long line_h1, line_h2, line_h3, line_l2; - unsigned long i, j; - int pix, k, l; - - /* number of pixels in highres image */ - hx = jbg_ceil_half(s->xd, s->d - higher_layer); - hy = jbg_ceil_half(s->yd, s->d - higher_layer); - /* number of pixels in lowres image */ - lx = jbg_ceil_half(hx, 1); - ly = jbg_ceil_half(hy, 1); - /* bytes per line in highres and lowres image */ - hbpl = (hx + 7) / 8; - lbpl = (lx + 7) / 8; - /* pointers to first image bytes */ - hp2 = s->lhp[s->highres[plane]][plane]; - hp1 = hp2 + hbpl; - hp3 = hp2 - hbpl; - lp = s->lhp[1 - s->highres[plane]][plane]; - -#ifdef DEBUG - fprintf(stderr, "resolution_reduction: plane = %d, higher_layer = %d\n", - plane, higher_layer); -#endif - - /* - * Layout of the variables line_h1, line_h2, line_h3, which contain - * as bits the high resolution neighbour pixels of the currently coded - * lowres pixel /\: - * \/ - * - * 76543210 76543210 76543210 76543210 line_h3 - * 76543210 76543210 765432/\ 76543210 line_h2 - * 76543210 76543210 765432\/ 76543210 line_h1 - * - * Layout of the variable line_l2, which contains the low resolution - * pixels near the currently coded pixel as bits. The lowres pixel - * which is currently coded is marked as X: - * - * 76543210 76543210 76543210 76543210 line_l2 - * X - */ - - for (i = 0; i < ly; i++) { - if (2*i + 1 >= hy) - hp1 = hp2; - pix = 0; - line_h1 = line_h2 = line_h3 = line_l2 = 0; - for (j = 0; j < lbpl * 8; j += 8) { - *lp = 0; - line_l2 |= i ? lp[-lbpl] : 0; - for (k = 0; k < 8 && j + k < lx; k += 4) { - if (((j + k) >> 2) < hbpl) { - line_h3 |= i ? *hp3 : 0; - ++hp3; - line_h2 |= *(hp2++); - line_h1 |= *(hp1++); - } - for (l = 0; l < 4 && j + k + l < lx; l++) { - line_h3 <<= 2; - line_h2 <<= 2; - line_h1 <<= 2; - line_l2 <<= 1; - pix = s->res_tab[((line_h1 >> 8) & 0x007) | - ((line_h2 >> 5) & 0x038) | - ((line_h3 >> 2) & 0x1c0) | - (pix << 9) | ((line_l2 << 2) & 0xc00)]; - *lp = (*lp << 1) | pix; - } - } - ++lp; - } - *(lp - 1) <<= lbpl * 8 - lx; - hp1 += hbpl; - hp2 += hbpl; - hp3 += hbpl; - } - -#ifdef DEBUG - { - FILE *f; - char fn[50]; - - sprintf(fn, "dbg_d=%02d.pbm", higher_layer - 1); - f = fopen(fn, "wb"); - fprintf(f, "P4\n%lu %lu\n", lx, ly); - fwrite(s->lhp[1 - s->highres[plane]][plane], 1, lbpl * ly, f); - fclose(f); - } -#endif - - return; -} - - -/* - * This function is called inside the three loops of jbg_enc_out() in - * order to write the next SDE. It has first to generate the required - * SDE and all SDEs which have to be encoded before this SDE can be - * created. The problem here is that if we want to output a lower - * resolution layer, we have to allpy the resolution reduction - * algorithm in order to get it. As we try to safe as much memory as - * possible, the resolution reduction will overwrite previous higher - * resolution bitmaps. Consequently, we have to encode and buffer SDEs - * which depend on higher resolution layers before we can start the - * resolution reduction. All this logic about which SDE has to be - * encoded before resolution reduction is allowed is handled here. - * This approach might be a little bit more complex than alternative - * ways to do it, but it allows us to do the encoding with the minimal - * possible amount of temporary memory. - */ -static void output_sde(struct jbg_enc_state *s, - unsigned long stripe, int layer, int plane) -{ - int lfcl; /* lowest fully coded layer */ - long i; - unsigned long u; - - assert(s->sde[stripe][layer][plane] != SDE_DONE); - - if (s->sde[stripe][layer][plane] != SDE_TODO) { -#ifdef DEBUG - fprintf(stderr, "writing SDE: s/d/p = %2lu/%2d/%2d\n", - stripe, layer, plane); -#endif - jbg_buf_output(&s->sde[stripe][layer][plane], s->data_out, s->file); - s->sde[stripe][layer][plane] = SDE_DONE; - return; - } - - /* Determine the smallest resolution layer in this plane for which - * not yet all stripes have been encoded into SDEs. This layer will - * have to be completely coded, before we can apply the next - * resolution reduction step. */ - lfcl = 0; - for (i = s->d; i >= 0; i--) - if (s->sde[s->stripes - 1][i][plane] == SDE_TODO) { - lfcl = i + 1; - break; - } - if (lfcl > s->d && s->d > 0 && stripe == 0) { - /* perform the first resolution reduction */ - resolution_reduction(s, plane, s->d); - } - /* In case HITOLO is not used, we have to encode and store the higher - * resolution layers first, although we do not need them right now. */ - while (lfcl - 1 > layer) { - for (u = 0; u < s->stripes; u++) - encode_sde(s, u, lfcl - 1, plane); - --lfcl; - s->highres[plane] ^= 1; - if (lfcl > 1) - resolution_reduction(s, plane, lfcl - 1); - } - - encode_sde(s, stripe, layer, plane); - -#ifdef DEBUG - fprintf(stderr, "writing SDE: s/d/p = %2lu/%2d/%2d\n", stripe, layer, plane); -#endif - jbg_buf_output(&s->sde[stripe][layer][plane], s->data_out, s->file); - s->sde[stripe][layer][plane] = SDE_DONE; - - if (stripe == s->stripes - 1 && layer > 0 && - s->sde[0][layer-1][plane] == SDE_TODO) { - s->highres[plane] ^= 1; - if (layer > 1) - resolution_reduction(s, plane, layer - 1); - } - - return; -} - - -/* - * Convert the table which controls the deterministic prediction - * process from the internal format into the representation required - * for the 1728 byte long DPTABLE element of a BIH. - * - * The bit order of the DPTABLE format (see also ITU-T T.82 figure 13) is - * - * high res: 4 5 6 low res: 0 1 - * 7 8 9 2 3 - * 10 11 12 - * - * were 4 table entries are packed into one byte, while we here use - * internally an unpacked 6912 byte long table indexed by the following - * bit order: - * - * high res: 7 6 5 high res: 8 7 6 low res: 1 0 - * (phase 0) 4 . . (phase 1) 5 4 . 3 2 - * . . . . . . - * - * high res: 10 9 8 high res: 11 10 9 - * (phase 2) 7 6 5 (phase 3) 8 7 6 - * 4 . . 5 4 . - */ -void jbg_int2dppriv(unsigned char *dptable, const char *internal) -{ - int i, j, k; - int trans0[ 8] = { 1, 0, 3, 2, 7, 6, 5, 4 }; - int trans1[ 9] = { 1, 0, 3, 2, 8, 7, 6, 5, 4 }; - int trans2[11] = { 1, 0, 3, 2, 10, 9, 8, 7, 6, 5, 4 }; - int trans3[12] = { 1, 0, 3, 2, 11, 10, 9, 8, 7, 6, 5, 4 }; - - for (i = 0; i < 1728; dptable[i++] = 0); - -#define FILL_TABLE1(offset, len, trans) \ - for (i = 0; i < len; i++) { \ - k = 0; \ - for (j = 0; j < 8; j++) \ - k |= ((i >> j) & 1) << trans[j]; \ - dptable[(i + offset) >> 2] |= \ - (internal[k + offset] & 3) << ((3 - (i&3)) << 1); \ - } - - FILL_TABLE1( 0, 256, trans0); - FILL_TABLE1( 256, 512, trans1); - FILL_TABLE1( 768, 2048, trans2); - FILL_TABLE1(2816, 4096, trans3); - - return; -} - - -/* - * Convert the table which controls the deterministic prediction - * process from the 1728 byte long DPTABLE format into the 6912 byte long - * internal format. - */ -void jbg_dppriv2int(char *internal, const unsigned char *dptable) -{ - int i, j, k; - int trans0[ 8] = { 1, 0, 3, 2, 7, 6, 5, 4 }; - int trans1[ 9] = { 1, 0, 3, 2, 8, 7, 6, 5, 4 }; - int trans2[11] = { 1, 0, 3, 2, 10, 9, 8, 7, 6, 5, 4 }; - int trans3[12] = { 1, 0, 3, 2, 11, 10, 9, 8, 7, 6, 5, 4 }; - -#define FILL_TABLE2(offset, len, trans) \ - for (i = 0; i < len; i++) { \ - k = 0; \ - for (j = 0; j < 8; j++) \ - k |= ((i >> j) & 1) << trans[j]; \ - internal[k + offset] = \ - (dptable[(i + offset) >> 2] >> ((3 - (i & 3)) << 1)) & 3; \ - } - - FILL_TABLE2( 0, 256, trans0); - FILL_TABLE2( 256, 512, trans1); - FILL_TABLE2( 768, 2048, trans2); - FILL_TABLE2(2816, 4096, trans3); - - return; -} - - -/* - * Encode one full BIE and pass the generated data to the specified - * call-back function - */ -void jbg_enc_out(struct jbg_enc_state *s) -{ - long bpl; - unsigned char bih[20]; - unsigned long xd, yd, y; - long ii[3], is[3], ie[3]; /* generic variables for the 3 nested loops */ - unsigned long stripe; - int layer, plane; - int order; - unsigned char dpbuf[1728]; - extern char jbg_dptable[]; - - /* some sanity checks */ - s->order &= JBG_HITOLO | JBG_SEQ | JBG_ILEAVE | JBG_SMID; - order = s->order & (JBG_SEQ | JBG_ILEAVE | JBG_SMID); - if (index[order][0] < 0) - s->order = order = JBG_SMID | JBG_ILEAVE; - if (s->options & JBG_DPON && s->dppriv != jbg_dptable) - s->options |= JBG_DPPRIV; - if (s->mx > MX_MAX) - s->mx = MX_MAX; - s->my = 0; - if (s->mx && s->mx < ((s->options & JBG_LRLTWO) ? 5U : 3U)) - s->mx = 0; - if (s->d > 255 || s->d < 0 || s->dh > s->d || s->dh < 0 || - s->dl < 0 || s->dl > s->dh || s->planes < 0 || s->planes > 255) - return; - - /* ensure correct zero padding of bitmap at the final byte of each line */ - if (s->xd & 7) { - bpl = (s->xd + 7) / 8; /* bytes per line */ - for (plane = 0; plane < s->planes; plane++) - for (y = 0; y < s->yd; y++) - s->lhp[0][plane][y * bpl + bpl - 1] &= ~((1 << (8 - (s->xd & 7))) - 1); - } - - /* calculate number of stripes that will be required */ - s->stripes = ((s->yd >> s->d) + - ((((1UL << s->d) - 1) & s->xd) != 0) + s->l0 - 1) / s->l0; - - /* allocate buffers for SDE pointers */ - if (s->sde == NULL) { - s->sde = (struct jbg_buf ****) - checked_malloc(s->stripes * sizeof(struct jbg_buf ***)); - for (stripe = 0; stripe < s->stripes; stripe++) { - s->sde[stripe] = (struct jbg_buf ***) - checked_malloc((s->d + 1) * sizeof(struct jbg_buf **)); - for (layer = 0; layer < s->d + 1; layer++) { - s->sde[stripe][layer] = (struct jbg_buf **) - checked_malloc(s->planes * sizeof(struct jbg_buf *)); - for (plane = 0; plane < s->planes; plane++) - s->sde[stripe][layer][plane] = SDE_TODO; - } - } - } - - /* output BIH */ - bih[0] = s->dl; - bih[1] = s->dh; - bih[2] = s->planes; - bih[3] = 0; - xd = jbg_ceil_half(s->xd, s->d - s->dh); - yd = jbg_ceil_half(s->yd, s->d - s->dh); - bih[4] = xd >> 24; - bih[5] = (xd >> 16) & 0xff; - bih[6] = (xd >> 8) & 0xff; - bih[7] = xd & 0xff; - bih[8] = yd >> 24; - bih[9] = (yd >> 16) & 0xff; - bih[10] = (yd >> 8) & 0xff; - bih[11] = yd & 0xff; - bih[12] = s->l0 >> 24; - bih[13] = (s->l0 >> 16) & 0xff; - bih[14] = (s->l0 >> 8) & 0xff; - bih[15] = s->l0 & 0xff; - bih[16] = s->mx; - bih[17] = s->my; - bih[18] = s->order; - bih[19] = s->options & 0x7f; - s->data_out(bih, 20, s->file); - if ((s->options & (JBG_DPON | JBG_DPPRIV | JBG_DPLAST)) == - (JBG_DPON | JBG_DPPRIV)) { - /* write private table */ - jbg_int2dppriv(dpbuf, s->dppriv); - s->data_out(dpbuf, 1728, s->file); - } - -#if 0 - /* - * Encode everything first. This is a simple-minded alternative to - * all the tricky on-demand encoding logic in output_sde() for - * debugging purposes. - */ - for (layer = s->dh; layer >= s->dl; layer--) { - for (plane = 0; plane < s->planes; plane++) { - if (layer > 0) - resolution_reduction(s, plane, layer); - for (stripe = 0; stripe < s->stripes; stripe++) - encode_sde(s, stripe, layer, plane); - s->highres[plane] ^= 1; - } - } -#endif - - /* - * Generic loops over all SDEs. Which loop represents layer, plane and - * stripe depends on the option flags. - */ - - /* start and end value vor each loop */ - is[index[order][STRIPE]] = 0; - ie[index[order][STRIPE]] = s->stripes - 1; - is[index[order][LAYER]] = s->dl; - ie[index[order][LAYER]] = s->dh; - is[index[order][PLANE]] = 0; - ie[index[order][PLANE]] = s->planes - 1; - - for (ii[0] = is[0]; ii[0] <= ie[0]; ii[0]++) - for (ii[1] = is[1]; ii[1] <= ie[1]; ii[1]++) - for (ii[2] = is[2]; ii[2] <= ie[2]; ii[2]++) { - - stripe = ii[index[order][STRIPE]]; - if (s->order & JBG_HITOLO) - layer = s->dh - (ii[index[order][LAYER]] - s->dl); - else - layer = ii[index[order][LAYER]]; - plane = ii[index[order][PLANE]]; - - output_sde(s, stripe, layer, plane); - - } - - return; -} - - -void jbg_enc_free(struct jbg_enc_state *s) -{ - unsigned long stripe; - int layer, plane; - -#ifdef DEBUG - fprintf(stderr, "jbg_enc_free(%p)\n", s); -#endif - - /* clear buffers for SDEs */ - if (s->sde) { - for (stripe = 0; stripe < s->stripes; stripe++) { - for (layer = 0; layer < s->d + 1; layer++) { - for (plane = 0; plane < s->planes; plane++) - if (s->sde[stripe][layer][plane] != SDE_DONE && - s->sde[stripe][layer][plane] != SDE_TODO) - jbg_buf_free(&s->sde[stripe][layer][plane]); - checked_free(s->sde[stripe][layer]); - } - checked_free(s->sde[stripe]); - } - checked_free(s->sde); - } - - /* clear free_list */ - jbg_buf_free(&s->free_list); - - /* clear memory for arithmetic encoder states */ - checked_free(s->s); - - /* clear memory for differential-layer typical prediction buffer */ - checked_free(s->tp); - - /* clear memory for adaptive template pixel offsets */ - checked_free(s->tx); - - /* clear lowres image buffers */ - if (s->lhp[1]) { - for (plane = 0; plane < s->planes; plane++) - checked_free(s->lhp[1][plane]); - checked_free(s->lhp[1]); - } - - return; -} - - -/* - * Convert the error codes used by jbg_dec_in() into a string - * written in the selected language and character set. - */ -const char *jbg_strerror(int errnum, int language) -{ - if (errnum < 0 || errnum >= NEMSG) - return "Unknown error code passed to jbg_strerror()"; - if (language < 0 || language >= NEMSG_LANG) - return "Unknown language code passed to jbg_strerror()"; - - return errmsg[language][errnum]; -} - - -/* - * The constructor for a decoder - */ -void jbg_dec_init(struct jbg_dec_state *s) -{ - s->order = 0; - s->d = -1; - s->bie_len = 0; - s->buf_len = 0; - s->dppriv = NULL; - s->xmax = 4294967295UL; - s->ymax = 4294967295UL; - s->dmax = 256; - s->s = NULL; - - return; -} - - -/* - * Specify a maximum image size for the decoder. If the JBIG file has - * the order bit ILEAVE, but not the bit SEQ set, then the decoder - * will abort to decode after the image has reached the maximal - * resolution layer which is still not wider than xmax or higher than - * ymax. - */ -void jbg_dec_maxsize(struct jbg_dec_state *s, unsigned long xmax, - unsigned long ymax) -{ - if (xmax > 0) s->xmax = xmax; - if (ymax > 0) s->ymax = ymax; - - return; -} - - -/* - * Decode the new len PSDC bytes to which data points and add them to - * the current stripe. Return the number of bytes which have actually - * been read (this will be less than len if a marker segment was - * part of the data or if the final byte was 0xff were this code - * can not determine, whether we have a marker segment. - */ -static size_t decode_pscd(struct jbg_dec_state *s, unsigned char *data, - size_t len) -{ - unsigned long stripe; - unsigned int layer, plane; - unsigned long hl, ll, y, hx, hy, lx, ly, hbpl, lbpl; - unsigned char *hp, *lp1, *lp2, *p1, *q1; - register unsigned long line_h1, line_h2, line_h3; - register unsigned long line_l1, line_l2, line_l3; - struct jbg_ardec_state *se; - unsigned long x; - int n; - int pix, cx = 0, slntp, shift, tx; - - /* SDE loop variables */ - stripe = s->ii[index[s->order & 7][STRIPE]]; - layer = s->ii[index[s->order & 7][LAYER]]; - plane = s->ii[index[s->order & 7][PLANE]]; - - /* forward data to arithmetic decoder */ - se = s->s[plane] + layer - s->dl; - se->pscd_ptr = data; - se->pscd_end = data + len; - - /* number of lines per stripe in highres image */ - hl = s->l0 << layer; - /* number of lines per stripe in lowres image */ - ll = hl >> 1; - /* current line number in highres image */ - y = stripe * hl + s->i; - /* number of pixels in highres image */ - hx = jbg_ceil_half(s->xd, s->d - layer); - hy = jbg_ceil_half(s->yd, s->d - layer); - /* number of pixels in lowres image */ - lx = jbg_ceil_half(hx, 1); - ly = jbg_ceil_half(hy, 1); - /* bytes per line in highres and lowres image */ - hbpl = (hx + 7) / 8; - lbpl = (lx + 7) / 8; - /* pointer to highres and lowres image bytes */ - hp = s->lhp[ layer & 1][plane] + (stripe * hl + s->i) * hbpl + - (s->x >> 3); - lp2 = s->lhp[(layer-1) & 1][plane] + (stripe * ll + (s->i >> 1)) * lbpl + - (s->x >> 4); - lp1 = lp2 + lbpl; - - /* restore a few local variables */ - line_h1 = s->line_h1; - line_h2 = s->line_h2; - line_h3 = s->line_h3; - line_l1 = s->line_l1; - line_l2 = s->line_l2; - line_l3 = s->line_l3; - x = s->x; - - if (s->x == 0 && s->i == 0 && - (stripe == 0 || s->reset[plane][layer - s->dl])) { - s->tx[plane][layer - s->dl] = s->ty[plane][layer - s->dl] = 0; - if (s->pseudo) - s->lntp[plane][layer - s->dl] = 1; - } - -#ifdef DEBUG - if (s->x == 0 && s->i == 0 && s->pseudo) - fprintf(stderr, "decode_pscd(%p, %p, %ld): s/d/p = %2lu/%2u/%2u\n", - s, data, (long) len, stripe, layer, plane); -#endif - - if (layer == 0) { - - /* - * Decode lowest resolution layer - */ - - for (; s->i < hl && y < hy; s->i++, y++) { - - /* adaptive template changes */ - if (x == 0) - for (n = 0; n < s->at_moves; n++) - if (s->at_line[n] == s->i) { - s->tx[plane][layer - s->dl] = s->at_tx[n]; - s->ty[plane][layer - s->dl] = s->at_ty[n]; -#ifdef DEBUG - fprintf(stderr, "ATMOVE: line=%lu, tx=%d, ty=%d.\n", s->i, - s->tx[plane][layer - s->dl], s->ty[plane][layer - s->dl]); -#endif - } - tx = s->tx[plane][layer - s->dl]; - shift = tx - ((s->options & JBG_LRLTWO) ? 5 : 3); - - /* typical prediction */ - if (s->options & JBG_TPBON && s->pseudo) { - slntp = arith_decode(se, (s->options & JBG_LRLTWO) ? TPB2CX : TPB3CX); - if (se->result == JBG_MORE || se->result == JBG_MARKER) - goto leave; - s->lntp[plane][layer - s->dl] = - !(slntp ^ s->lntp[plane][layer - s->dl]); - if (s->lntp[plane][layer - s->dl]) { - /* this line is 'not typical' and has to be coded completely */ - s->pseudo = 0; - } else { - /* this line is 'typical' (i.e. identical to the previous one) */ - p1 = hp; - if (s->i == 0 && (stripe == 0 || s->reset[plane][layer - s->dl])) - while (p1 < hp + hbpl) *p1++ = 0; - else { - q1 = hp - hbpl; - while (q1 < hp) *p1++ = *q1++; - } - hp += hbpl; - continue; - } - } - - /* - * Layout of the variables line_h1, line_h2, line_h3, which contain - * as bits the neighbour pixels of the currently decoded pixel X: - * - * 76543210 76543210 76543210 76543210 line_h3 - * 76543210 76543210 76543210 76543210 line_h2 - * 76543210 76543210 76543210 76543210 X line_h1 - */ - - if (x == 0) { - line_h1 = line_h2 = line_h3 = 0; - if (s->i > 0 || (y > 0 && !s->reset[plane][layer - s->dl])) - line_h2 = (long)*(hp - hbpl) << 8; - if (s->i > 1 || (y > 1 && !s->reset[plane][layer - s->dl])) - line_h3 = (long)*(hp - hbpl - hbpl) << 8; - } - - /* - * Another tiny JBIG standard bug: - * - * While implementing the line_h3 handling here, I discovered - * another problem with the ITU-T T.82(1993 E) specification. - * This might be a somewhat pathological case, however. The - * standard is unclear about how a decoder should behave in the - * following situation: - * - * Assume we are in layer 0 and all stripes are single lines - * (L0=1 allowed by table 9). We are now decoding the first (and - * only) line of the third stripe. Assume, the first stripe was - * terminated by SDRST and the second stripe was terminated by - * SDNORM. While decoding the only line of the third stripe with - * the three-line template, we need access to pixels from the - * previous two stripes. We know that the previous stripe - * terminated with SDNROM, so we access the pixel from the - * second stripe. But do we have to replace the pixels from the - * first stripe by background pixels, because this stripe ended - * with SDRST? The standard, especially clause 6.2.5 does never - * mention this case, so the behaviour is undefined here. My - * current implementation remembers only the marker used to - * terminate the previous stripe. In the above example, the - * pixels of the first stripe are accessed despite the fact that - * this stripe ended with SDRST. An alternative (only slightly - * more complicated) implementation would be to remember the end - * marker (SDNORM or SDRST) of the previous two stripes in a - * plane/layer and to act accordingly when accessing the two - * previous lines. What am I supposed to do here? - * - * As the standard is unclear about the correct behaviour in the - * situation of the above example, I strongly suggest to avoid - * the following situation while encoding data with JBIG: - * - * LRLTWO = 0, L0=1 and both SDNORM and SDRST appear in layer 0. - * - * I guess that only a very few if any encoders will switch - * between SDNORM and SDRST, so let us hope that this ambiguity - * in the standard will never cause any interoperability - * problems. - * - * Markus Kuhn -- 1995-04-30 - */ - - /* decode line */ - while (x < hx) { - if ((x & 7) == 0) { - if (x < hbpl * 8 - 8 && - (s->i > 0 || (y > 0 && !s->reset[plane][layer - s->dl]))) { - line_h2 |= *(hp - hbpl + 1); - if (s->i > 1 || (y > 1 && !s->reset[plane][layer - s->dl])) - line_h3 |= *(hp - hbpl - hbpl + 1); - } - } - if (s->options & JBG_LRLTWO) { - /* two line template */ - do { - if (tx) - pix = arith_decode(se, (((line_h2 >> 9) & 0x3e0) | - ((line_h1 >> shift) & 0x010) | - (line_h1 & 0x00f))); - else - pix = arith_decode(se, (((line_h2 >> 9) & 0x3f0) | - (line_h1 & 0x00f))); - if (se->result == JBG_MORE || se->result == JBG_MARKER) - goto leave; - line_h1 = (line_h1 << 1) | pix; - line_h2 <<= 1; - } while ((++x & 7) && x < hx); - } else { - /* three line template */ - do { - if (tx) - pix = arith_decode(se, (((line_h3 >> 7) & 0x380) | - ((line_h2 >> 11) & 0x078) | - ((line_h1 >> shift) & 0x004) | - (line_h1 & 0x003))); - else - pix = arith_decode(se, (((line_h3 >> 7) & 0x380) | - ((line_h2 >> 11) & 0x07c) | - (line_h1 & 0x003))); - if (se->result == JBG_MORE || se->result == JBG_MARKER) - goto leave; - - line_h1 = (line_h1 << 1) | pix; - line_h2 <<= 1; - line_h3 <<= 1; - } while ((++x & 7) && x < hx); - } /* if (s->options & JBG_LRLTWO) */ - *hp++ = line_h1; - } /* while */ - *(hp - 1) <<= hbpl * 8 - hx; - x = 0; - s->pseudo = 1; - } /* for (i = ...) */ - - } else { - - /* - * Decode differential layer - */ - - for (; s->i < hl && y < hy; s->i++, y++) { - - /* adaptive template changes */ - if (x == 0) - for (n = 0; n < s->at_moves; n++) - if (s->at_line[n] == s->i) { - s->tx[plane][layer - s->dl] = s->at_tx[n]; - s->ty[plane][layer - s->dl] = s->at_ty[n]; -#ifdef DEBUG - fprintf(stderr, "ATMOVE: line=%lu, tx=%d, ty=%d.\n", s->i, - s->tx[plane][layer - s->dl], s->ty[plane][layer - s->dl]); -#endif - } - tx = s->tx[plane][layer - s->dl]; - shift = tx - 3; - - /* handle lower border of low-resolution image */ - if ((s->i >> 1) >= ll - 1 || (y >> 1) >= ly - 1) - lp1 = lp2; - - /* typical prediction */ - if (s->options & JBG_TPDON && s->pseudo) { - s->lntp[plane][layer - s->dl] = arith_decode(se, TPDCX); - if (se->result == JBG_MORE || se->result == JBG_MARKER) - goto leave; - s->pseudo = 0; - } - - - /* - * Layout of the variables line_h1, line_h2, line_h3, which contain - * as bits the high resolution neighbour pixels of the currently - * decoded highres pixel X: - * - * 76543210 76543210 76543210 76543210 line_h3 - * 76543210 76543210 76543210 76543210 line_h2 - * 76543210 76543210 76543210 76543210 X line_h1 - * - * Layout of the variables line_l1, line_l2, line_l3, which contain - * the low resolution pixels near the currently decoded pixel as bits. - * The lowres pixel in which the currently coded highres pixel is - * located is marked as Y: - * - * 76543210 76543210 76543210 76543210 line_l3 - * 76543210 76543210 Y6543210 76543210 line_l2 - * 76543210 76543210 76543210 76543210 line_l1 - */ - - - if (x == 0) { - line_h1 = line_h2 = line_h3 = line_l1 = line_l2 = line_l3 = 0; - if (s->i > 0 || (y > 0 && !s->reset[plane][layer - s->dl])) { - line_h2 = (long)*(hp - hbpl) << 8; - if (s->i > 1 || (y > 1 && !s->reset[plane][layer - s->dl])) - line_h3 = (long)*(hp - hbpl - hbpl) << 8; - } - if (s->i > 1 || (y > 1 && !s->reset[plane][layer-s->dl])) - line_l3 = (long)*(lp2 - lbpl) << 8; - line_l2 = (long)*lp2 << 8; - line_l1 = (long)*lp1 << 8; - } - - /* decode line */ - while (x < hx) { - if ((x & 15) == 0) - if ((x >> 1) < lbpl * 8 - 8) { - line_l1 |= *(lp1 + 1); - line_l2 |= *(lp2 + 1); - if (s->i > 1 || - (y > 1 && !s->reset[plane][layer - s->dl])) - line_l3 |= *(lp2 - lbpl + 1); - } - do { - - assert(hp - (s->lhp[ layer &1][plane] + (stripe * hl + s->i) - * hbpl) == (ptrdiff_t) x >> 3); - assert(lp2 - (s->lhp[(layer-1) &1][plane] + (stripe * ll + (s->i>>1)) - * lbpl) == (ptrdiff_t) x >> 4); - - if ((x & 7) == 0) - if (x < hbpl * 8 - 8) { - if (s->i > 0 || (y > 0 && !s->reset[plane][layer - s->dl])) { - line_h2 |= *(hp + 1 - hbpl); - if (s->i > 1 || (y > 1 && !s->reset[plane][layer - s->dl])) - line_h3 |= *(hp + 1 - hbpl - hbpl); - } - } - do { - if (!s->lntp[plane][layer - s->dl]) - cx = (((line_l3 >> 14) & 0x007) | - ((line_l2 >> 11) & 0x038) | - ((line_l1 >> 8) & 0x1c0)); - if (!s->lntp[plane][layer - s->dl] && - (cx == 0x000 || cx == 0x1ff)) { - /* pixels are typical and have not to be decoded */ - do { - line_h1 = (line_h1 << 1) | (cx & 1); - } while ((++x & 1) && x < hx); - line_h2 <<= 2; line_h3 <<= 2; - } else - do { - - /* deterministic prediction */ - if (s->options & JBG_DPON) - if ((y & 1) == 0) - if ((x & 1) == 0) - /* phase 0 */ - pix = s->dppriv[((line_l3 >> 15) & 0x003) | - ((line_l2 >> 13) & 0x00c) | - ((line_h1 << 4) & 0x010) | - ((line_h2 >> 9) & 0x0e0)]; - else - /* phase 1 */ - pix = s->dppriv[(((line_l3 >> 15) & 0x003) | - ((line_l2 >> 13) & 0x00c) | - ((line_h1 << 4) & 0x030) | - ((line_h2 >> 9) & 0x1c0)) + 256]; - else - if ((x & 1) == 0) - /* phase 2 */ - pix = s->dppriv[(((line_l3 >> 15) & 0x003) | - ((line_l2 >> 13) & 0x00c) | - ((line_h1 << 4) & 0x010) | - ((line_h2 >> 9) & 0x0e0) | - ((line_h3 >> 6) & 0x700)) + 768]; - else - /* phase 3 */ - pix = s->dppriv[(((line_l3 >> 15) & 0x003) | - ((line_l2 >> 13) & 0x00c) | - ((line_h1 << 4) & 0x030) | - ((line_h2 >> 9) & 0x1c0) | - ((line_h3 >> 6) & 0xe00)) + 2816]; - else - pix = 2; - - if (pix & 2) { - if (tx) - cx = ((line_h1 & 0x003) | - (((line_h1 << 2) >> shift) & 0x010) | - ((line_h2 >> 12) & 0x00c) | - ((line_h3 >> 10) & 0x020)); - else - cx = ((line_h1 & 0x003) | - ((line_h2 >> 12) & 0x01c) | - ((line_h3 >> 10) & 0x020)); - if (x & 1) - cx |= (((line_l2 >> 8) & 0x0c0) | - ((line_l1 >> 6) & 0x300)) | (1UL << 10); - else - cx |= (((line_l2 >> 9) & 0x0c0) | - ((line_l1 >> 7) & 0x300)); - cx |= (y & 1) << 11; - - pix = arith_decode(se, cx); - if (se->result == JBG_MORE || se->result == JBG_MARKER) - goto leave; - } - - line_h1 = (line_h1 << 1) | pix; - line_h2 <<= 1; - line_h3 <<= 1; - - } while ((++x & 1) && x < hx); - line_l1 <<= 1; line_l2 <<= 1; line_l3 <<= 1; - } while ((x & 7) && x < hx); - *hp++ = line_h1; - } while ((x & 15) && x < hx); - ++lp1; - ++lp2; - } /* while */ - x = 0; - - *(hp - 1) <<= hbpl * 8 - hx; - if ((s->i & 1) == 0) { - /* low resolution pixels are used twice */ - lp1 -= lbpl; - lp2 -= lbpl; - } else - s->pseudo = 1; - - } /* for (i = ...) */ - - } - - leave: - - /* save a few local variables */ - s->line_h1 = line_h1; - s->line_h2 = line_h2; - s->line_h3 = line_h3; - s->line_l1 = line_l1; - s->line_l2 = line_l2; - s->line_l3 = line_l3; - s->x = x; - - return se->pscd_ptr - data; -} - - -/* - * Provide a new BIE fragment to the decoder. - * - * If cnt is not NULL, then *cnt will contain after the call the - * number of actually read bytes. If the data was not complete, then - * the return value will be JBG_EAGAIN and *cnt == len. In case this - * function has returned with JBG_EOK, then it has reached the end of - * a BIE but it can be called again with data from the next BIE if - * there exists one in order to get to a higher resolution layer. In - * case the return value was JBG_EOK_INTR then this function can be - * called again with the rest of the BIE, because parsing the BIE has - * been interrupted by a jbg_dec_maxsize() specification. In both - * cases the remaining len - *cnt bytes of the previous block will - * have to passed to this function again (if len > *cnt). In case of - * any other return value than JBG_EOK, JBG_EOK_INTR or JBG_EAGAIN, a - * serious problem has occured and the only function you should call - * is jbg_dec_free() in order to remove the mess (and probably - * jbg_strerror() in order to find out what to tell the user). - */ -int jbg_dec_in(struct jbg_dec_state *s, unsigned char *data, size_t len, - size_t *cnt) -{ - int i, j, required_length; - unsigned long x, y; - unsigned long is[3], ie[3]; - long hsize, lsize; - extern char jbg_dptable[]; - size_t dummy_cnt; - - if (!cnt) cnt = &dummy_cnt; - *cnt = 0; - if (len < 1) return JBG_EAGAIN; - - /* read in 20-byte BIH */ - if (s->bie_len < 20) { - while (s->bie_len < 20 && *cnt < len) - s->buffer[s->bie_len++] = data[(*cnt)++]; - if (s->bie_len < 20) - return JBG_EAGAIN; - if (s->buffer[1] < s->buffer[0]) - return JBG_EINVAL; - /* test whether this looks like a valid JBIG header at all */ - if (s->buffer[3] != 0 || (s->buffer[18] & 0xf0) != 0 || - (s->buffer[19] & 0x80) != 0) - return JBG_EINVAL; - if (s->buffer[0] != s->d + 1) - return JBG_ENOCONT; - s->dl = s->buffer[0]; - s->d = s->buffer[1]; - if (s->dl == 0) - s->planes = s->buffer[2]; - else - if (s->planes != s->buffer[2]) - return JBG_ENOCONT; - x = (((long) s->buffer[ 4] << 24) | ((long) s->buffer[ 5] << 16) | - ((long) s->buffer[ 6] << 8) | (long) s->buffer[ 7]); - y = (((long) s->buffer[ 8] << 24) | ((long) s->buffer[ 9] << 16) | - ((long) s->buffer[10] << 8) | (long) s->buffer[11]); - if (s->dl != 0 && ((s->xd << (s->d - s->dl + 1)) != x && - (s->yd << (s->d - s->dl + 1)) != y)) - return JBG_ENOCONT; - s->xd = x; - s->yd = y; - s->l0 = (((long) s->buffer[12] << 24) | ((long) s->buffer[13] << 16) | - ((long) s->buffer[14] << 8) | (long) s->buffer[15]); - if (!s->planes || !s->xd || !s->yd || !s->l0) - return JBG_EINVAL; - s->mx = s->buffer[16]; - if (s->mx > 127) - return JBG_EINVAL; - s->my = s->buffer[17]; - if (s->mx > 32 || s->my > 0) - return JBG_EIMPL; - s->order = s->buffer[18]; - if (index[s->order & 7][0] < 0) - return JBG_EINVAL; - /* HITOLO and SEQ currently not yet implemented */ - if (s->dl != s->d && (s->order & JBG_HITOLO || s->order & JBG_SEQ)) - return JBG_EIMPL; - s->options = s->buffer[19]; - - /* calculate number of stripes that will be required */ - s->stripes = ((s->yd >> s->d) + - ((((1UL << s->d) - 1) & s->xd) != 0) + s->l0 - 1) / s->l0; - - /* some initialization */ - s->ii[index[s->order & 7][STRIPE]] = 0; - s->ii[index[s->order & 7][LAYER]] = s->dl; - s->ii[index[s->order & 7][PLANE]] = 0; - /* bytes required for resolution layer D and D-1 */ - hsize = ((s->xd + 7) / 8) * s->yd; - lsize = ((jbg_ceil_half(s->xd, 1) + 7) / 8) * - jbg_ceil_half(s->yd, 1); - if (s->dl == 0) { - s->s = checked_malloc(s->planes * sizeof(struct jbg_ardec_state *)); - s->tx = checked_malloc(s->planes * sizeof(int *)); - s->ty = checked_malloc(s->planes * sizeof(int *)); - s->reset = checked_malloc(s->planes * sizeof(int *)); - s->lntp = checked_malloc(s->planes * sizeof(int *)); - s->lhp[0] = checked_malloc(s->planes * sizeof(unsigned char *)); - s->lhp[1] = checked_malloc(s->planes * sizeof(unsigned char *)); - for (i = 0; i < s->planes; i++) { - s->s[i] = checked_malloc((s->d - s->dl + 1) * - sizeof(struct jbg_ardec_state)); - s->tx[i] = checked_malloc((s->d - s->dl + 1) * sizeof(int)); - s->ty[i] = checked_malloc((s->d - s->dl + 1) * sizeof(int)); - s->reset[i] = checked_malloc((s->d - s->dl + 1) * sizeof(int)); - s->lntp[i] = checked_malloc((s->d - s->dl + 1) * sizeof(int)); - s->lhp[s->d &1][i] = checked_malloc(sizeof(unsigned char) * hsize); - s->lhp[(s->d-1)&1][i] = checked_malloc(sizeof(unsigned char) * lsize); - } - } else { - for (i = 0; i < s->planes; i++) { - s->s[i] = checked_realloc(s->s[i], (s->d - s->dl + 1) * - sizeof(struct jbg_ardec_state)); - s->tx[i] = checked_realloc(s->tx[i], (s->d - s->dl + 1) * sizeof(int)); - s->ty[i] = checked_realloc(s->ty[i], (s->d - s->dl + 1) * sizeof(int)); - s->reset[i] = checked_realloc(s->reset[i], - (s->d - s->dl +1) * sizeof(int)); - s->lntp[i] = checked_realloc(s->lntp[i], - (s->d - s->dl +1) * sizeof(int)); - s->lhp[s->d &1][i] = checked_realloc(s->lhp[s->d & 1][i], - sizeof(unsigned char) * hsize); - s->lhp[(s->d-1)&1][i] = checked_realloc(s->lhp[(s->d-1)&1][i], - sizeof(unsigned char) * lsize); - } - } - for (i = 0; i < s->planes; i++) - for (j = 0; j <= s->d - s->dl; j++) - arith_decode_init(s->s[i] + j, 0); - if (s->dl == 0 || (s->options & JBG_DPON && !(s->options & JBG_DPPRIV))) - s->dppriv = jbg_dptable; - s->comment_skip = 0; - s->buf_len = 0; - s->x = 0; - s->i = 0; - s->pseudo = 1; - s->at_moves = 0; - } - - /* read in DPTABLE */ - if (s->bie_len < 20 + 1728 && - (s->options & (JBG_DPON | JBG_DPPRIV | JBG_DPLAST)) == - (JBG_DPON | JBG_DPPRIV)) { - assert(s->bie_len >= 20); - while (s->bie_len < 20 + 1728 && *cnt < len) - s->buffer[s->bie_len++ - 20] = data[(*cnt)++]; - if (s->bie_len < 20 + 1728) - return JBG_EAGAIN; - if (!s->dppriv || s->dppriv == jbg_dptable) - s->dppriv = checked_malloc(sizeof(char) * 1728); - jbg_dppriv2int(s->dppriv, s->buffer); - } - - /* - * BID processing loop - */ - - while (*cnt < len) { - - /* process floating marker segments */ - - /* skip COMMENT contents */ - if (s->comment_skip) { - if (s->comment_skip <= len - *cnt) { - *cnt += s->comment_skip; - s->comment_skip = 0; - } else { - s->comment_skip -= len - *cnt; - *cnt = len; - } - continue; - } - - /* load complete marker segments into s->buffer for processing */ - if (s->buf_len > 0) { - assert(s->buffer[0] == MARKER_ESC); - while (s->buf_len < 2 && *cnt < len) - s->buffer[s->buf_len++] = data[(*cnt)++]; - if (s->buf_len < 2) continue; - switch (s->buffer[1]) { - case MARKER_COMMENT: required_length = 6; break; - case MARKER_ATMOVE: required_length = 8; break; - case MARKER_NEWLEN: required_length = 6; break; - case MARKER_ABORT: - case MARKER_SDNORM: - case MARKER_SDRST: required_length = 2; break; - case MARKER_STUFF: - /* forward stuffed 0xff to arithmetic decoder */ - s->buf_len = 0; - decode_pscd(s, s->buffer, 2); - continue; - default: - return JBG_EMARKER; - } - while (s->buf_len < required_length && *cnt < len) - s->buffer[s->buf_len++] = data[(*cnt)++]; - if (s->buf_len < required_length) continue; - /* now the buffer is filled with exactly one marker segment */ - switch (s->buffer[1]) { - case MARKER_COMMENT: - s->comment_skip = - (((long) s->buffer[2] << 24) | ((long) s->buffer[3] << 16) | - ((long) s->buffer[4] << 8) | (long) s->buffer[5]); - break; - case MARKER_ATMOVE: - if (s->at_moves < JBG_ATMOVES_MAX) { - s->at_line[s->at_moves] = - (((long) s->buffer[2] << 24) | ((long) s->buffer[3] << 16) | - ((long) s->buffer[4] << 8) | (long) s->buffer[5]); - s->at_tx[s->at_moves] = (signed char) s->buffer[6]; - s->at_ty[s->at_moves] = s->buffer[7]; - if (s->at_tx[s->at_moves] < - (int) s->mx || - s->at_tx[s->at_moves] > (int) s->mx || - s->at_ty[s->at_moves] > (int) s->my || - (s->at_ty[s->at_moves] == 0 && s->at_tx[s->at_moves] < 0)) - return JBG_EINVAL; - s->at_moves++; - } else - return JBG_EINVAL; - break; - case MARKER_NEWLEN: - y = (((long) s->buffer[2] << 24) | ((long) s->buffer[3] << 16) | - ((long) s->buffer[4] << 8) | (long) s->buffer[5]); - if (y > s->yd || !(s->options & JBG_VLENGTH)) - return JBG_EINVAL; - s->yd = y; - /* calculate again number of stripes that will be required */ - s->stripes = - ((s->yd >> s->d) + - ((((1UL << s->d) - 1) & s->xd) != 0) + s->l0 - 1) / s->l0; - break; - case MARKER_ABORT: - return JBG_EABORT; - - case MARKER_SDNORM: - case MARKER_SDRST: - /* decode final pixels based on trailing zero bytes */ - decode_pscd(s, s->buffer, 2); - - arith_decode_init(s->s[s->ii[index[s->order & 7][PLANE]]] + - s->ii[index[s->order & 7][LAYER]] - s->dl, - s->ii[index[s->order & 7][STRIPE]] != s->stripes - 1 - && s->buffer[1] != MARKER_SDRST); - - s->reset[s->ii[index[s->order & 7][PLANE]]] - [s->ii[index[s->order & 7][LAYER]] - s->dl] = - (s->buffer[1] == MARKER_SDRST); - - /* prepare for next SDE */ - s->x = 0; - s->i = 0; - s->pseudo = 1; - s->at_moves = 0; - - /* increment layer/stripe/plane loop variables */ - /* start and end value for each loop: */ - is[index[s->order & 7][STRIPE]] = 0; - ie[index[s->order & 7][STRIPE]] = s->stripes - 1; - is[index[s->order & 7][LAYER]] = s->dl; - ie[index[s->order & 7][LAYER]] = s->d; - is[index[s->order & 7][PLANE]] = 0; - ie[index[s->order & 7][PLANE]] = s->planes - 1; - i = 2; /* index to innermost loop */ - do { - j = 0; /* carry flag */ - if (++s->ii[i] > ie[i]) { - /* handling overflow of loop variable */ - j = 1; - if (i > 0) - s->ii[i] = is[i]; - } - } while (--i >= 0 && j); - - s->buf_len = 0; - - /* check whether this have been all SDEs */ - if (j) { - s->bie_len = 0; - return JBG_EOK; - } - - /* check whether we have to abort because of xmax/ymax */ - if (index[s->order & 7][LAYER] == 0 && i < 0) { - /* LAYER is the outermost loop and we have just gone to next layer */ - if (jbg_ceil_half(s->xd, s->d - s->ii[0]) > s->xmax || - jbg_ceil_half(s->yd, s->d - s->ii[0]) > s->ymax) { - s->xmax = 4294967295UL; - s->ymax = 4294967295UL; - return JBG_EOK_INTR; - } - if (s->ii[0] > (unsigned long) s->dmax) { - s->dmax = 256; - return JBG_EOK_INTR; - } - } - - break; - } - s->buf_len = 0; - - } else if (data[*cnt] == MARKER_ESC) - s->buffer[s->buf_len++] = data[(*cnt)++]; - - else { - - /* we have found PSCD bytes */ - *cnt += decode_pscd(s, data + *cnt, len - *cnt); - if (*cnt < len && data[*cnt] != 0xff) { -#ifdef DEBUG - fprintf(stderr, "PSCD was longer than expected, unread bytes " - "%02x %02x %02x %02x ...\n", data[*cnt], data[*cnt+1], - data[*cnt+2], data[*cnt+3]); -#endif - return JBG_EINVAL; - } - - } - } /* of BID processing loop 'while (*cnt < len) ...' */ - - return JBG_EAGAIN; -} - - -/* - * After jbg_dec_in() returned JBG_EOK or JBG_EOK_INTR, you can call this - * function in order to find out the width of the image. - */ -long jbg_dec_getwidth(const struct jbg_dec_state *s) -{ - if (s->d < 0) - return -1; - if (index[s->order & 7][LAYER] == 0) { - if (s->ii[0] < 1) - return -1; - else - return jbg_ceil_half(s->xd, s->d - (s->ii[0] - 1)); - } - - return s->xd; -} - - -/* - * After jbg_dec_in() returned JBG_EOK or JBG_EOK_INTR, you can call this - * function in order to find out the height of the image. - */ -long jbg_dec_getheight(const struct jbg_dec_state *s) -{ - if (s->d < 0) - return -1; - if (index[s->order & 7][LAYER] == 0) { - if (s->ii[0] < 1) - return -1; - else - return jbg_ceil_half(s->yd, s->d - (s->ii[0] - 1)); - } - - return s->yd; -} - - -/* - * After jbg_dec_in() returned JBG_EOK or JBG_EOK_INTR, you can call this - * function in order to get a pointer to the image. - */ -unsigned char *jbg_dec_getimage(const struct jbg_dec_state *s, int plane) -{ - if (s->d < 0) - return NULL; - if (index[s->order & 7][LAYER] == 0) { - if (s->ii[0] < 1) - return NULL; - else - return s->lhp[(s->ii[0] - 1) & 1][plane]; - } - - return s->lhp[s->d & 1][plane]; -} - - -/* - * After jbg_dec_in() returned JBG_EOK or JBG_EOK_INTR, you can call - * this function in order to find out the size in bytes of one - * bitplane of the image. - */ -long jbg_dec_getsize(const struct jbg_dec_state *s) -{ - if (s->d < 0) - return -1; - if (index[s->order & 7][LAYER] == 0) { - if (s->ii[0] < 1) - return -1; - else - return - ((jbg_ceil_half(s->xd, s->d - (s->ii[0] - 1)) + 7) / 8) * - jbg_ceil_half(s->yd, s->d - (s->ii[0] - 1)); - } - - return ((s->xd + 7) / 8) * s->yd; -} - - -/* - * After jbg_dec_in() returned JBG_EOK or JBG_EOK_INTR, you can call - * this function in order to find out the size of the image that you - * can retrieve with jbg_merge_planes(). - */ -long jbg_dec_getsize_merged(const struct jbg_dec_state *s) -{ - if (s->d < 0) - return -1; - if (index[s->order & 7][LAYER] == 0) { - if (s->ii[0] < 1) - return -1; - else - return - jbg_ceil_half(s->xd, s->d - (s->ii[0] - 1)) * - jbg_ceil_half(s->yd, s->d - (s->ii[0] - 1)) * - ((s->planes + 7) / 8); - } - - return s->xd * s->yd * ((s->planes + 7) / 8); -} - - -/* - * The destructor function which releases any resources obtained by the - * other decoder functions. - */ -void jbg_dec_free(struct jbg_dec_state *s) -{ - int i; - - if (s->d < 0 || s->s == NULL) - return; - s->d = -2; - - for (i = 0; i < s->planes; i++) { - checked_free(s->s[i]); - checked_free(s->tx[i]); - checked_free(s->ty[i]); - checked_free(s->reset[i]); - checked_free(s->lntp[i]); - checked_free(s->lhp[0][i]); - checked_free(s->lhp[1][i]); - } - - checked_free(s->s); - checked_free(s->tx); - checked_free(s->ty); - checked_free(s->reset); - checked_free(s->lntp); - checked_free(s->lhp[0]); - checked_free(s->lhp[1]); - - s->s = NULL; - - return; -} - - -/* - * Split bigendian integer pixel field into separate bit planes. In the - * src array, every pixel is represented by a ((has_planes + 7) / 8) byte - * long word, most significant byte first. While has_planes describes - * the number of used bits per pixel in the source image, encode_plane - * is the number of most significant bits among those that we - * actually transfer to dest. - */ -void jbg_split_planes(unsigned long x, unsigned long y, int has_planes, - int encode_planes, - const unsigned char *src, unsigned char **dest, - int use_graycode) -{ - unsigned bpl = (x + 7) / 8; /* bytes per line in dest plane */ - unsigned i, k = 8; - int p; - unsigned long line; - extern void *memset(void *s, int c, size_t n); - unsigned prev; /* previous *src byte shifted by 8 bit to the left */ - register int bits, msb = has_planes - 1; - int bitno; - - /* sanity checks */ - if (encode_planes > has_planes) - encode_planes = has_planes; - use_graycode = use_graycode != 0 && encode_planes > 1; - - for (p = 0; p < encode_planes; p++) - memset(dest[p], 0, bpl * y); - - for (line = 0; line < y; line++) { /* lines loop */ - for (i = 0; i * 8 < x; i++) { /* dest bytes loop */ - for (k = 0; k < 8 && i * 8 + k < x; k++) { /* pixel loop */ - prev = 0; - for (p = 0; p < encode_planes; p++) { /* bit planes loop */ - /* calculate which bit in *src do we want */ - bitno = (msb - p) & 7; - /* put this bit with its left neighbor right adjusted into bits */ - bits = (prev | *src) >> bitno; - /* go to next *src byte, but keep old */ - if (bitno == 0) - prev = *src++; - /* make space for inserting new bit */ - dest[p][bpl * line + i] <<= 1; - /* insert bit, if requested apply Gray encoding */ - dest[p][bpl * line + i] |= (bits ^ (use_graycode & (bits>>1))) & 1; - /* - * Theorem: Let b(n),...,b(1),b(0) be the digits of a - * binary word and let g(n),...,g(1),g(0) be the digits of the - * corresponding Gray code word, then g(i) = b(i) xor b(i+1). - */ - } - /* skip unused *src bytes */ - for (;p < has_planes; p++) - if (((has_planes - 1 - p) & 7) == 0) - src++; - } - } - for (p = 0; p < encode_planes; p++) /* right padding loop */ - dest[p][bpl * (line + 1) - 1] <<= 8 - k; - } - - return; -} - -/* - * Merge the separate bit planes decoded by the JBIG decoder into an - * integer pixel field. This is essentially the counterpart to - * jbg_split_planes(). */ -void jbg_dec_merge_planes(const struct jbg_dec_state *s, int use_graycode, - void (*data_out)(unsigned char *start, size_t len, - void *file), void *file) -{ -#define BUFLEN 4096 - int bpp, bpl; - unsigned long line; - unsigned i, k = 8; - int p, q; - unsigned char buf[BUFLEN]; - unsigned char *bp = buf; - unsigned char **src; - unsigned long x, y; - unsigned v; - - /* sanity check */ - use_graycode = use_graycode != 0; - - x = jbg_dec_getwidth(s); - y = jbg_dec_getheight(s); - if (x <= 0 || y <= 0) - return; - bpp = (s->planes + 7) / 8; /* bytes per pixel in dest image */ - bpl = (x + 7) / 8; /* bytes per line in src plane */ - - if (index[s->order & 7][LAYER] == 0) - if (s->ii[0] < 1) - return; - else - src = s->lhp[(s->ii[0] - 1) & 1]; - else - src = s->lhp[s->d & 1]; - - for (line = 0; line < y; line++) { /* lines loop */ - for (i = 0; i * 8 < x; i++) { /* src bytes loop */ - for (k = 0; k < 8 && i * 8 + k < x; k++) { /* pixel loop */ - for (p = (s->planes-1) & ~7; p >= 0; p -= 8) { /* dest bytes loop */ - v = 0; - for (q = 0; q < 8 && p+q < s->planes; q++) /* pixel bit loop */ - v = (v << 1) | - (((src[p+q][bpl * line + i] >> (7 - k)) & 1) ^ - (use_graycode & v)); - *bp++ = v; - if (bp - buf == BUFLEN) { - data_out(buf, BUFLEN, file); - bp = buf; - } - } - } - } - } - - if (bp - buf > 0) - data_out(buf, bp - buf, file); - - return; -} diff --git a/converter/other/jbig/jbig.doc b/converter/other/jbig/jbig.doc deleted file mode 100644 index 10eeda80..00000000 --- a/converter/other/jbig/jbig.doc +++ /dev/null @@ -1,721 +0,0 @@ - -Using the JBIG-KIT library --------------------------- - -Markus Kuhn -- 1998-04-10 - - -This text explains how to include the functions provided by the -JBIG-KIT portable image compression library into your application -software. - - -1 Introduction to JBIG - -Below follows a short introduction into some technical aspects of the -JBIG standard. More detailed information is provided in the -"Introduction and overview" section of the JBIG standard. Information -about how to obtain a copy of the standard is available on the -Internet from or . - -Image data encoded with the JBIG algorithm is separated into planes, -layers, and stripes. Each plane contains one bit per pixel. The number -of planes stored in a JBIG data stream is the number of bits per -pixel. Resolution layers are numbered from 0 to D with 0 being the -layer with the lowest resolution and D the layer with the highest one. -Each next higher resolution layer has exactly twice the number of rows -and columns than the previous one. Layer 0 is encoded independently of -any other data, all other resolution layers are encoded as only the -difference between the next lower and the current layer. For -applications that require very quick access to parts of an image it is -possible to divide an image into several horizontal stripes. All -stripes of one resolution layer have equal size except perhaps the -final one. The number of stripes of an image is equal in all -resolution layers and in all bit planes. - -The compressed data stream specified by the JBIG standard is called a -bi-level image entity (BIE). A BIE consists of a 20-byte header, -followed by an optional 1728-byte table (usually not present, except -in special applications) followed by a sequence of stripe data -entities (SDE). SDEs are the data blocks of which each encodes the -content of one single stripe in one plane and resolution layer. -Between the SDEs, other information blocks (called floating marker -segments) can also be present, which change certain parameters of the -algorithm in the middle of an image or contain additional application -specific information. A BIE looks like this: - - - +------------------------------------------------+ - | | - | 20-byte header (with image size, #planes, | - | #layers, stripe size, first layer, options, | - | SDE ordering, ...) | - | | - +------------------------------------------------+ - | | - | optional 1728-byte table | - | | - +------------------------------------------------+ - | | - | stripe data entity | - | | - +------------------------------------------------+ - | | - | optional floating marker segments | - | | - +------------------------------------------------+ - | | - | stripe data entity | - | | - +------------------------------------------------+ - ... - +------------------------------------------------+ - | | - | stripe data entity | - | | - +------------------------------------------------+ - - -One BIE can contain all resolution layers of an image, but it is also -possible to store various resolution layers in several BIEs. The BIE -header contains the number of the first and the last resolution layer -stored in this BIE, as well as the size of the highest resolution -layer stored in this BIE. Progressive coding is deactivated by simply -storing the image in one single resolution layer. - -Different applications might have different requirements for the order -in which the SDEs for stripes of various planes and layers are stored -in the BIE, so all possible sensible orderings are allowed and -indicated by four bits in the header. - -It is possible to use the raw BIE data stream as specified by the JBIG -standard directly as the format of a file used for storing images. -This is what the JBIG<->PBM conversion tools that are provided in this -package as demonstration applications do. However as the BIE format -has been designed for a large number of very different applications -and also in order to allow efficient direct processing by special JBIG -hardware chip implementations, the BIE header contains only the -minimum amount of information absolutely required by the decompression -algorithm. A large number of features expected from a good file format -are missing in the BIE data stream: - - - no "magic code" in the first few bytes to allow identification - of the file on a typeless file system as JBIG encoded and to allow - automatic distinction from other compression algorithms - - - no standardized way to encode additional information like a textual - description, information about the meaning of various bit planes, - the physical size and resolution of the document, etc. - - - a checksum that ensures image integrity - - - encryption and signature mechanisms - - - many things more - -Raw BIE data streams alone are consequently no suitable format for -document archiving and exchange. A standard format for this purpose -would typically combine a BIE representing the image data together -with an additional header providing auxiliary information into one -file. Existing established multi-purpose file formats with a rich set -of auxiliary information attributes like TIFF could be extended easily -so that they can also contain JBIG compressed data. - -On the other hand, in database applications for instance, a BIE might -be directly stored in a variable length field. Auxiliary information -on which efficient search operations are required would then be stored -in other fields of the same record. - - -2 Compressing an image - -2.1 Format of the source image - -For processing by the library, the image has to be present in memory -as separate bitmap planes. Each byte of a bitmap contains eight -pixels, the most significant bit represents the leftmost of these -pixels. Each line of a bitmap has to be stored in an integral number -of bytes. If the image width is not an integral multiple of eight, -then the final byte has to be padded with zero bits. - -For example the 23x5 pixels large single plane image: - - .XXXXX..XXX...X...XXX.. - .....X..X..X..X..X..... - .....X..XXX...X..X.XXX. - .X...X..X..X..X..X...X. - ..XXX...XXX...X...XXX.. - -is represented by the 15 bytes - - 01111100 11100010 00111000 - 00000100 10010010 01000000 - 00000100 11100010 01011100 - 01000100 10010010 01000100 - 00111000 11100010 00111000 - -or in hexadecimal notation - - 7c e2 38 04 92 40 04 e2 5c 44 92 44 38 e2 38 - -This is the format used in binary PBM files and it can also be be -handled directly by the Xlib library of the X Window System. - -As JBIG can also handle images with several bit planes, the JBIG-KIT -library functions accept and return always arrays of pointers to -bitmaps with one pointer per plane. - -For single plane images, the standard recommends that a 0 pixel -represents the background and a 1 pixel represents the foreground -color of an image, i.e. 0 is white and 1 is black for scanned paper -documents. For images with several bits per pixel, the JBIG standard -makes no recommendations about how various colors should be encoded. - -For greyscale images, by using a Gray code instead of a simple binary -weighted representation of the pixel intensity, some increase in -coding efficiency can be reached. - -A Gray code is also a binary representation of integer numbers, but -has the property that the representations of the integer numbers i and -(i+1) differ always in exactly one single bit. For example, the -numbers 0 to 7 can be represented in normal binary code and Gray code -as in the following table: - - normal - number binary code Gray code - --------------------------------------- - 0 000 000 - 1 001 001 - 2 010 011 - 3 011 010 - 4 100 110 - 5 101 111 - 6 110 101 - 7 111 100 - -The form of Gray code shown above has the property that the second -half of the code (numbers 4 - 7) is simply the mirrored first half -(numbers 3 - 0) with the first bit set to one. This way, arbitrarily -large Gray codes can be generated quickly by mirroring the above -example and prefixing the first half with zeros and the second half -with ones as often as required. In greyscale images, it is common -practise to use the all-0 code for black and the all-1 code for white. - -No matter whether a Gray code or a binary code is used for encoding a -pixel intensity in several bit planes, it always makes sense to store -the most significant (leftmost) bit in plane 0, which is transmitted -first. This way, a decoder could increase the precision of the -displayed pixel intensities while data is still being received and the -basic structure of the image will become visible as early as possible -during the transmission. - - -2.2 A simple compression application - -In order to use JBIG-KIT in your application, just link libjbig.a to -your executable (on Unix systems just add -ljbig and -L. to the -command line options of your compiler, on other systems you will have -to write a new Makefile anyway), copy the file jbig.h into your source -directory and put the line - - #include "jbig.h" - -into your source code. - -The library interface follows the concepts of object-oriented -programming. You have to declare a variable (object) - - struct jbg_enc_state se; - -which contains the current status of an encoder. Then you initialize -the encoder by calling the constructor function - - void jbg_enc_init(struct jbg_enc_state *s, unsigned long x, unsigned long y, - int pl, unsigned char **p, - void (*data_out)(unsigned char *start, size_t len, - void *file), - void *file); - -The parameters have the following meaning: - - s A pointer to the jbg_enc_state structure which you want - to initialize. - - x The width of your image. - - y The height of your image. - - pl the number of bitmap planes you want to encode. - - p A pointer to an array of pl pointers, where each is again - pointing to the first byte of a bitmap as described in - section 2.1. - - data_out This is a call-back function which will be called during - the compression process by libjbig in order to deliver - the BIE data to the application. The parameters of the - function data_out are a pointer start to the new block of - data to be delivered as well as the number len of delivered - bytes. The pointer file is transparently delivered to - data_out as specified in jbg_enc_init(). Usually, data_out - will write the BIE portion to a file, send it to a - network connection or append it to some memory buffer. - - file A pointer parameter which is transparently passed to - data_out() and allows data_out() to distinguish by which - compression task it has been called in multi-threaded - applications. - -In the simplest case, the compression is then started by calling the -function - - void jbg_enc_out(struct jbg_enc_state *s); - -which will deliver the complete BIE to data_out(). After this, a call -to the destructor function - - void jbg_enc_free(struct jbg_enc_state *s); - -will release any memory allocated by the previous functions. - - -A minimal example application which sends the BIE of the above example -bitmap to stdout looks like this: - ---------------------------------------------------------------------------- -/* A sample JBIG encoding application */ - -#include -#include "jbig.h" - -void output_bie(unsigned char *start, size_t len, void *file) -{ - fwrite(start, 1, len, (FILE *) file); - - return; -} - -int main() -{ - unsigned char bitmap[15] = { - /* 23 x 5 pixels, "JBIG" */ - 0x7c, 0xe2, 0x38, 0x04, 0x92, 0x40, 0x04, 0xe2, - 0x5c, 0x44, 0x92, 0x44, 0x38, 0xe2, 0x38 - }; - unsigned char *bitmaps[1] = { bitmap }; - struct jbg_enc_state se; - - jbg_enc_init(&se, 23, 5, 1, bitmaps, - output_bie, stdout); /* initialize encoder */ - jbg_enc_out(&se); /* encode image */ - jbg_enc_free(&se); /* release allocated resources */ - - return 0; -} ---------------------------------------------------------------------------- - -This software produces a 42 byte long BIE. (JBIG is not very good at -compressing extremely small images like in this example, because the -arithmetic encoder requires some startup data in order to generate -reasonable statistics which influence the compression process and -because there is some header overhead.) - - -2.3 More about compression - -If jbg_enc_out() is called directly after jbg_enc_init(), the -following default values are used for various compression parameters: - - - Only one single resolution layer is used, i.e. no progressive - mode. - - - The number of lines per stripe is selected so that approximately - 35 stripes per image are used (as recommended in annex C of the - standard together with the suggested adaptive template change - algorithm). However not less than 2 and not more than 128 lines - are used in order to stay within the suggested minimum parameter - support range specified in annex A of the standard). - - - All optional parts of the JBIG algorithm are activated (TPBON, - TPDON and DPON). - - - The default resolution reduction table and the default deterministic - prediction tables are used - - - The maximal vertical offset of the adaptive template pixel is 0 - and the maximal horizontal offset is 8 (mx = 8, my = 0). - -In order to change any of these default parameters, additional -functions have to be called between jbg_enc_init() and jbg_enc_out(). - -In order to activate progressive encoding, it is possible to specify -with - - void jbg_enc_layers(struct jbg_enc_state *s, int d); - -the number d of differential resolution layers which shall be encoded -in addition to the lowest resolution layer 0. For example, if a 300 -dpi document has to be stored and the lowest resolution layer shall -have 75 dpi so that a screen previewer can directly decompress only -the required resolution, then a call - - jbg_enc_layers(&se, 2); - -will cause three resolution layers with 75, 150 and 300 dots per inch. - -If the application does not know what typical resolutions are used and -simply wants to ensure that the lowest resolution layer will fit into -a given maximal window size, then as an alternative, a call to - - int jbg_enc_lrlmax(struct jbg_enc_state *s, unsigned long mwidth, - unsigned long mheight); - -will cause the library to automatically determine the suitable number -of resolutions so that the lowest resolution layer 0 will not be -larger than mwidth x mheight pixels. E.g. if one wants to ensure that -systems with a 640 x 480 pixel large screen can decode the required -resolution directly, then call - - jbg_enc_lrlmax(&se, 640, 480); - -The return value is the number of differential layers selected. - -After the number of resolution layers has been specified by calls to -jbg_enc_layers() or jbg_enc_lrlmax(), by default all these layers will -be written into the BIE. This can be changed with a call to - - int jbg_enc_lrange(struct jbg_enc_state *s, int dl, int dh); - -Parameter dl specifies the lowest resolution layer and dh the highest -resolution layer that will appear in the BIE. If e.g. only layer 0 -shall be written to the first BIE and layer 1 and 2 shall be written -to a second one, then before writing the first BIE, one calls - - jbg_enc_lrange(&se, 0, 0); - -and before writing the second BIE with jbg_enc_out(), one calls - - jbg_enc_lrange(&se, 1, 2); - -If any of the parameters is negative, it will be ignored. The return -value is the total number of differential layers which will represent -the input image. This way, jbg_enc_lrange(&se, -1, -1) can be used to -query the layer of the full image. - -A number of other more exotic options of the JBIG algorithm can be -modified by calling - - void jbg_enc_options(struct jbg_enc_state *s, int order, int options, - long l0, int mx, int my); - -before calling jbg_enc_out(). - -The order parameter can be a combination of the bits JBG_HITOLO, -JBG_SEQ, JBG_ILEAVE and JBG_SMID and it determines in which order -the SDEs are stored in the BIE. The bits have the following meaning: - - JBG_HITOLO Usually, the lower resolution layers are stored before - the higher resolution layers, so that a decoder can - already start to display a low resolution version of - the full image once a prefix of the BIE has been - received. When this bit is set however, the BIE will - contain the higher layers before the lower layers. This - avoids additional buffer memory in the encoder and is - intended for applications where the encoder is connected - to a database which can easily reorder the SDEs before - sending them to a decoder. Warning: JBIG decoders are - not expected to support the HITOLO option (e.g. the - JBIG-KIT decoder does currently not) so you should - normally not use it. - - JBG_SEQ Usually, at first all stripes of one resolution layer - are written to the BIE and then all stripes of the next - layer, and so on. When the SEQ bit is set however, then - all layers of the first stripe will be written, - followed by all layers of the second stripe, etc. This - option also should normally never be required and is - not supported by the current JBIG-KIT decoder. - - JBG_SMID In case there exist several bit planes, then the order of - the stripes is determined by 3 loops over all stripes, - all planes and all layers. When SMID is set, the loop - over all stripes is the middle loop. - - JBG_ILEAVE If this bit is set, then at first all layers of one - plane are written before the encoder starts with the next - plane. - -The above description might be somewhat confusing, but the following -table (see also Table 11 in ITU-T T.82) makes clear how the three bits -JBG_SEQ, JBIG_ILEAVE and JBG_SMID influence the ordering of the loops -over all stripes, planes and layers: - - - Loops: - JBG_SEQ JBG_ILEAVE JBG_SMID | Outer Middle Inner - ------------------------------------+--------------------------- - 0 0 0 | p d s - 0 1 0 | d p s - 0 1 1 | d s p - 1 0 0 | s p d - 1 0 1 | p s d - 1 1 0 | s d p - - p: plane, s: stripe, d: layer - - -By default, the order combination JBG_ILEAVE | JBG_SMID is used. - -The options value can contain the following bits, which activate -some of the optional algorithms defined by JBIG: - - JBG_LRLTWO Normally, in the lowest resolution layer, pixels - from three lines around the next pixel are used - in order to determine the context in which the next - pixel is encoded. Some people in the JBIG committee - seem to have argued that using only 2 lines will - make software implementations a little bit faster, - however others have argued that using only two lines - will decrease compression efficiency by around 5%. - As you might expect from a committee, now both - alternatives are allowed and if JBG_LRLTWO is set, - the slightly faster but 5% less well compressing two - line alternative is selected. God bless the committees. - Although probably nobody will ever need this option, - it has been implemented in JBIG-KIT and is off by - default. - - JBG_TPDON This activates the "typical prediction" algorithm - for differential layers which avoids that large - areas of equal color have to be encoded at all. - This is on by default and there is no good reason to - switch it off except for debugging or preparing data - for cheap JBIG hardware which does not support this - option. - - JBG_TPBON Like JBG_TPDON this activates the "typical prediction" - algorithm in the lowest resolution layer. Also activated - by default. - - JBG_DPON This bit activates for the differential resolution - layers the "deterministic prediction" algorithm, - which avoids that higher resolution layer pixels are - encoded when their value can already be determined - with the knowledge of the neighbor pixels, the - corresponding lower resolution pixels and the - resolution reduction algorithm. This is also - activated by default and one only might perhaps want - to deactivate it if the default resolution reduction - algorithm is replaced by a new one. - - JBG_DELAY_AT Use a slightly less efficient algorithm to determine - when an adaptive template change is necessary. With - this bit set, the encoder output is compatible to the - conformance test examples in cause 7.2 of ITU-T T.82. - Then all adaptive template changes are delayed until - the first line of the next stripe. This option is by - default deactivated and only required for passing a - special compatibility test suite. - -In addition, parameter l0 in jbg_enc_options() allows you to specify -the number of lines per stripe in resolution layer 0. The parameters -mx and my change the maximal offset allowed for the adaptive template -pixel. The JBIG-KIT implementation allows currently a maximal mx value -of 23 in the encoder and 32 in the decoder. Parameter my is at the -moment ignored and always set to 0. As the standard requires of all -decoder implementations only a maximum supported mx = 16 and my = 0, -higher values should normally be avoided in order to guarantee -interoperability. Default is mx = 8 and my = 0. If any of the -parameters order, options, l0, mx or my is negative, then this value -is ignored and the current value stays unmodified. - -The resolution reduction and deterministic prediction tables can also -be replaced. However as these options are anyway only for experts, -please have a look at the source code of jbg_enc_out() and the struct -members dppriv and res_tab of struct jbg_enc_state for the details of -how to do this in case you really need it. The functions -jbg_int2dppriv and jbg_dppriv2int are provided in order to convert the -DPTABLE data from the format used in the standard into the more -efficient format used internally by JBIG-KIT. - -If you want to encode a greyscale image, you can use the library -function - - void jbg_split_planes(unsigned long x, unsigned long y, int has_planes, - int encode_planes, - const unsigned char *src, unsigned char **dest, - int use_graycode); - -It separates an image in which each pixel is represented by one or -more bytes into separate bitplanes. The dest array of pointers to -these bitplanes can then be handed over to jbg_enc_init(). The -variables x and y specify the width and height of the image in pixels, -and has_planes specifies how many bits per pixel are used. As each -pixel is represented by an integral number of consecutive bytes, of -which each contains up to eight bits, the total length of the input -image array src[] will therefore be x * y * ((has_planes + 7) / 8) -bytes. The pixels are stored as usually in English reading order, and -for each pixel the integer value is stored with the most significant -byte coming first (Bigendian). This is exactly the format used in raw -PGM files. In encode_planes, the number of bitplanes that shall be -extracted can be specified. This allows for instance to extract only -the most significant 8 bits of a 12-bit image, where each pixel is -represented by two bytes, by specifying has_planes = 12 and -encode_planes = 8. If use_graycode is zero, then the binary code of -the pixel integer values will be used instead of the Gray code. Plane -0 contains always the most significant bit. - - -3 Decompressing an image - -Like with the compression functions, if you want to use the JBIG-KIT -library, you have to put the line - - #include "jbig.h" - -into your source code and link your executable with libjbig.a. - -The state of a JBIG decoder is stored completely in a struct and you -will have to define a variable like - - struct jbg_dec_state sd; - -which is initialized by a call to - - void jbg_dec_init(struct jbg_dec_state *s); - -After this, you can directly start to pass data from the BIE to the decoder -by calling the function - - int jbg_dec_in(struct jbg_dec_state *s, unsigned char *data, size_t len, - size_t *cnt); - -The pointer data points to the first byte of a data block with length -len, which contains bytes from a BIE. It is not necessary to pass a -whole BIE at once to jbg_dec_in(), it can arrive fragmented in any way -by calling jbg_dec_in() several times. It is also possible to send -several BIEs concatenated to jbg_dec_in(), however these then have to -fit together. If you send several BIEs to the decoder, the lowest -resolution layer in each following BIE has to be the highest -resolution layer in the previous BIE plus one and the image sizes and -number of planes also have to fit together, otherwise jbg_dec_in() -will return the error JBG_ENOCONT after the header of the new BIE has -been received completely. - -If pointer cnt is not NULL, then the number of bytes actually read -from the data block is stored there. In case the data block did not -contain the end of the BIE, then the value JBG_EAGAIN will be returned -and *cnt equals len. - -Once the end of a BIE has been reached, the return value of -jbg_dec_in() will be JBG_EOK. After this has happened, the functions -and macros - - long jbg_dec_getwidth(struct jbg_dec_state *s); - long jbg_dec_getheight(struct jbg_dec_state *s); - int jbg_dec_getplanes(struct jbg_dec_state *s); - unsigned char *jbg_dec_getimage(struct jbg_dec_state *s, int plane); - long jbg_dec_getsize(struct jbg_dec_state *s); - -can be used to query the dimensions of the now completely decoded -image and to get a pointer to all bitmap planes. The bitmaps are -stored as described in section 2.1. The function jbg_dec_getsize() -calculates the number of bytes which one bitmap requires. - -The function - - void jbg_dec_merge_planes(const struct jbg_dec_state *s, int use_graycode, - void (*data_out)(unsigned char *start, size_t len, - void *file), void *file); - -allows you to merge the bitplanes that can be accessed individually -with jbg_dec_getimage() into an array with one or more bytes per pixel -(i.e., the format provided to jbg_split_planes()). If use_graycode is -zero, then a binary encoding will be used. The output array will be -delivered via the callback function data_out, exactly in the same way -in which the encoder provides the BIE. The function - - long jbg_dec_getsize_merged(const struct jbg_dec_state *s); - -determines how long the data array delivered by jbg_dec_merge_planes() -is going to be. - -Before calling jbg_dec_in() the first time, it is possible to specify with -a call to - - void jbg_dec_maxsize(struct jbg_dec_state *s, unsigned long xmax, - unsigned long ymax); - -an abort criterion for progressively encoded images. For instance if an -application will display a whole document on a screen which is 1024 x -768 pixels large, then this application should call - - jbg_dec_maxsize(&sd, 1024, 768); - -before the decoding process starts. If the image has been encoded in -progressive mode (i.e. with several resolution layers), then the -decoder will stop with a return value JBG_EOK_INTR after the largest -resolution layer that is still smaller than 1024 x 768. However this -is no guarantee that the image which can then be read out using -jbg_dec_getimage(), etc. is really not larger than the specified -maximal size. The application will have to check the size of the -image, because the decoder does not automatically apply a resolution -reduction if no suitable resolution layer is available in the BIE. - -If jbg_dec_in() returned JBG_EOK_INTR or JBG_EOK, then it is possible -to continue calling jbg_dec_in() with the remaining data in order to -either decode the remaining resolution layers of the current BIE or in -order to add another BIE with additional resolution layers. In both -cases, after jbg_dec_in() returned JBG_EOK_INTR or JBG_EOK, *cnt is -probably not equal to len and the remainder of the data block which -has not yet been processed by the decoder has to be delivered to -jbg_dec_in() again. - -If any other return value than JBG_EOK, JBG_EOK_INTR or JBG_EAGAIN -has been returned by jbg_dec_in(), then an error has occurred and - - void jbg_dec_free(struct jbg_dec_state *s); - -should be called in order to release any allocated memory. The -destructor jbg_dec_free() should of course also be called, once the -decoded bitmap returned by jbg_dec_getimage() is no longer required -and the memory can be released. - -The function - - const char *jbg_strerror(int errnum, int language); - -returns a pointer to a short single line test message which explains -the return value of jbg_dec_in(). This message can be used in order to -provide the user a brief informative message about what when wrong -while decompressing the JBIG image. The error messages are available -in several languages and in several character sets. Currently -supported are the following values for the language parameter: - - JBG_EN English messages in ASCII - JBG_DE_8859_1 German messages in ISO 8859-1 Latin 1 character set - JBG_DE_UTF_8 German messages in ISO 10646/Unicode UTF-8 encoding - - -The current implementation of the JBIG-KIT decoder has the following -limitations: - - - The maximal horizontal offset mx of the adaptive template pixel - must not be larger than 32 and the maximal vertical offset must - be zero. - - - HITOLO and SEQ bits must not be set in the order value. - -A more detailed description of the JBIG-KIT implementation is - - Markus Kuhn: Effiziente Kompression von bi-level Bilddaten durch - kontextsensitive arithmetische Codierung. Studienarbeit, Lehrstuhl - für Betriebssysteme, IMMD IV, Universität Erlangen-Nürnberg, - Erlangen, July 1995. (German, 62 pages) - - -Please quote the above if you use JBIG-KIT in your research project. - -*** Happy compressing *** - -[end] diff --git a/converter/other/jbig/jbig.h b/converter/other/jbig/jbig.h deleted file mode 100644 index dd9a76f3..00000000 --- a/converter/other/jbig/jbig.h +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Header file for the portable free JBIG compression library - * - * Markus Kuhn -- mkuhn@acm.org - * - * $Id: jbig.h,v 1.9 1999-11-16 15:58:45+00 mgk25 Rel $ - */ - -#ifndef JBG_H -#define JBG_H - -#include - -/* - * JBIG-KIT version number - */ - -#define JBG_VERSION "1.1" - -/* - * Buffer block for SDEs which are temporarily stored by encoder - */ - -#define JBG_BUFSIZE 4000 - -struct jbg_buf { - unsigned char d[JBG_BUFSIZE]; /* one block of a buffer list */ - int len; /* length of the data in this block */ - struct jbg_buf *next; /* pointer to next block */ - struct jbg_buf *previous; /* pointer to previous block * - * (unused in freelist) */ - struct jbg_buf *last; /* only used in list head: final block of list */ - struct jbg_buf **free_list; /* pointer to pointer to head of free list */ -}; - -/* - * Maximum number of allowed ATMOVEs per stripe - */ - -#define JBG_ATMOVES_MAX 64 - -/* - * Option and order flags - */ - -#define JBG_HITOLO 0x08 -#define JBG_SEQ 0x04 -#define JBG_ILEAVE 0x02 -#define JBG_SMID 0x01 - -#define JBG_LRLTWO 0x40 -#define JBG_VLENGTH 0x20 -#define JBG_TPDON 0x10 -#define JBG_TPBON 0x08 -#define JBG_DPON 0x04 -#define JBG_DPPRIV 0x02 -#define JBG_DPLAST 0x01 - -#define JBG_DELAY_AT 0x100 /* delay ATMOVE until the first line of the next - * stripe. Option available for compatibility - * with conformance test example in clause 7.2.*/ - - -/* - * Possible error code return values - */ - -#define JBG_EOK 0 -#define JBG_EOK_INTR 1 -#define JBG_EAGAIN 2 -#define JBG_ENOMEM 3 -#define JBG_EABORT 4 -#define JBG_EMARKER 5 -#define JBG_ENOCONT 6 -#define JBG_EINVAL 7 -#define JBG_EIMPL 8 - -/* - * Language code for error message strings (based on ISO 639 2-letter - * standard language name abbreviations). - */ - -#define JBG_EN 0 /* English */ -#define JBG_DE_8859_1 1 /* German in ISO Latin 1 character set */ -#define JBG_DE_UTF_8 2 /* German in Unicode UTF-8 encoding */ - -/* - * Status description of an arithmetic encoder - */ - -struct jbg_arenc_state { - unsigned char st[4096]; /* probability status for contexts, MSB = MPS */ - unsigned long c; /* C register, base of coding intervall, * - * layout as in Table 23 */ - unsigned long a; /* A register, normalized size of coding intervall */ - long sc; /* counter for buffered 0xff values which might overflow */ - int ct; /* bit shift counter, determines when next byte will be written */ - int buffer; /* buffer for most recent output byte != 0xff */ - void (*byte_out)(int, void *); /* function which receives all PSCD bytes */ - void *file; /* parameter passed to byte_out */ -}; - - -/* - * Status description of an arithmetic decoder - */ - -struct jbg_ardec_state { - unsigned char st[4096]; /* probability status for contexts, MSB = MPS */ - unsigned long c; /* C register, base of coding intervall, * - * layout as in Table 25 */ - unsigned long a; /* A register, normalized size of coding intervall */ - int ct; /* bit shift counter, determines when next byte will be read */ - unsigned char *pscd_ptr; /* pointer to next PSCD data byte */ - unsigned char *pscd_end; /* pointer to byte after PSCD */ - enum { - JBG_OK, /* symbol has been successfully decoded */ - JBG_READY, /* no more bytes of this PSCD required, marker * - * encountered, probably more symbols available */ - JBG_MORE, /* more PSCD data bytes required to decode a symbol */ - JBG_MARKER /* more PSCD data bytes required, ignored final 0xff byte */ - } result; /* result of previous decode call */ - int startup; /* controls initial fill of s->c */ -}; - -#ifdef TEST_CODEC -void arith_encode_init(struct jbg_arenc_state *s, int reuse_st); -void arith_encode_flush(struct jbg_arenc_state *s); -void arith_encode(struct jbg_arenc_state *s, int cx, int pix); -void arith_decode_init(struct jbg_ardec_state *s, int reuse_st); -int arith_decode(struct jbg_ardec_state *s, int cx); -#endif - - -/* - * Status of a JBIG encoder - */ - -struct jbg_enc_state { - int d; /* resolution layer of the input image */ - unsigned long xd, yd; /* size of the input image (resolution layer d) */ - int planes; /* number of different bitmap planes */ - int dl; /* lowest resolution layer in the next BIE */ - int dh; /* highest resolution layer in the next BIE */ - unsigned long l0; /* number of lines per stripe at lowest * - * resolution layer 0 */ - unsigned long stripes; /* number of stripes required (determ. by l0) */ - unsigned char **lhp[2]; /* pointers to lower/higher resolution images */ - int *highres; /* index [plane] of highres image in lhp[] */ - int order; /* SDE ordering parameters */ - int options; /* encoding parameters */ - unsigned mx, my; /* maximum ATMOVE window size */ - int *tx; /* array [plane] with x-offset of adaptive template pixel */ - char *dppriv; /* optional private deterministic prediction table */ - char *res_tab; /* table for the resolution reduction algorithm */ - struct jbg_buf ****sde; /* array [stripe][layer][plane] pointers to * - * buffers for stored SDEs */ - struct jbg_arenc_state *s; /* array [planes] for arithm. encoder status */ - struct jbg_buf *free_list; /* list of currently unused SDE block buffers */ - void (*data_out)(unsigned char *start, size_t len, void *file); - /* data write callback */ - void *file; /* parameter passed to data_out() */ - char *tp; /* buffer for temp. values used by diff. typical prediction */ -}; - - -/* - * Status of a JBIG decoder - */ - -struct jbg_dec_state { - /* data from BIH */ - int d; /* resolution layer of the full image */ - int dl; /* first resolution layer in this BIE */ - unsigned long xd, yd; /* size of the full image (resolution layer d) */ - int planes; /* number of different bitmap planes */ - unsigned long l0; /* number of lines per stripe at lowest * - * resolution layer 0 */ - unsigned long stripes; /* number of stripes required (determ. by l0) */ - int order; /* SDE ordering parameters */ - int options; /* encoding parameters */ - int mx, my; /* maximum ATMOVE window size */ - char *dppriv; /* optional private deterministic prediction table */ - - /* loop variables */ - unsigned long ii[3]; /* current stripe, layer, plane (outer loop first) */ - - /* - * Pointers to array [planes] of lower/higher resolution images. - * lhp[d & 1] contains image of layer d. - */ - unsigned char **lhp[2]; - - /* status information */ - int **tx, **ty; /* array [plane][layer-dl] with x,y-offset of AT pixel */ - struct jbg_ardec_state **s; /* array [plane][layer-dl] for arithmetic * - * decoder status */ - int **reset; /* array [plane][layer-dl] remembers if previous stripe * - * in that plane/resolution ended with SDRST. */ - unsigned long bie_len; /* number of bytes read so far */ - unsigned char buffer[20]; /* used to store BIH or marker segments fragm. */ - int buf_len; /* number of bytes in buffer */ - unsigned long comment_skip; /* remaining bytes of a COMMENT segment */ - unsigned long x; /* x position of next pixel in current SDE */ - unsigned long i; /* line in current SDE (first line of each stripe is 0) */ - int at_moves; /* number of AT moves in the current stripe */ - unsigned long at_line[JBG_ATMOVES_MAX]; /* lines at which an * - * AT move will happen */ - int at_tx[JBG_ATMOVES_MAX], at_ty[JBG_ATMOVES_MAX]; /* ATMOVE offsets in * - * current stripe */ - unsigned long line_h1, line_h2, line_h3; /* variables of decode_pscd */ - unsigned long line_l1, line_l2, line_l3; - int pseudo; /* flag for TPBON/TPDON: next pixel is pseudo pixel */ - int **lntp; /* flag [plane][layer-dl] for TP: line is not typical */ - - unsigned long xmax, ymax; /* if possible abort before image gets * - * larger than this size */ - int dmax; /* abort after this layer */ -}; - - -/* some macros (too trivial for a function) */ - -#define jbg_dec_getplanes(s) ((s)->planes) - - -/* function prototypes */ - -void jbg_enc_init(struct jbg_enc_state *s, unsigned long x, unsigned long y, - int planes, unsigned char **p, - void (*data_out)(unsigned char *start, size_t len, - void *file), - void *file); -int jbg_enc_lrlmax(struct jbg_enc_state *s, unsigned long mwidth, - unsigned long mheight); -void jbg_enc_layers(struct jbg_enc_state *s, int d); -int jbg_enc_lrange(struct jbg_enc_state *s, int dl, int dh); -void jbg_enc_options(struct jbg_enc_state *s, int order, int options, - long l0, int mx, int my); -void jbg_enc_out(struct jbg_enc_state *s); -void jbg_enc_free(struct jbg_enc_state *s); - -void jbg_dec_init(struct jbg_dec_state *s); -void jbg_dec_maxsize(struct jbg_dec_state *s, unsigned long xmax, - unsigned long ymax); -int jbg_dec_in(struct jbg_dec_state *s, unsigned char *data, size_t len, - size_t *cnt); -long jbg_dec_getwidth(const struct jbg_dec_state *s); -long jbg_dec_getheight(const struct jbg_dec_state *s); -unsigned char *jbg_dec_getimage(const struct jbg_dec_state *s, int plane); -long jbg_dec_getsize(const struct jbg_dec_state *s); -void jbg_dec_merge_planes(const struct jbg_dec_state *s, int use_graycode, - void (*data_out)(unsigned char *start, size_t len, - void *file), void *file); -long jbg_dec_getsize_merged(const struct jbg_dec_state *s); -void jbg_dec_free(struct jbg_dec_state *s); - -const char *jbg_strerror(int errnum, int language); -void jbg_int2dppriv(unsigned char *dptable, const char *internal); -void jbg_dppriv2int(char *internal, const unsigned char *dptable); -unsigned long jbg_ceil_half(unsigned long x, int n); -void jbg_split_planes(unsigned long x, unsigned long y, int has_planes, - int encode_planes, - const unsigned char *src, unsigned char **dest, - int use_graycode); - -#endif /* JBG_H */ diff --git a/converter/other/jbig/jbig_tab.c b/converter/other/jbig/jbig_tab.c deleted file mode 100644 index 55183503..00000000 --- a/converter/other/jbig/jbig_tab.c +++ /dev/null @@ -1,428 +0,0 @@ -/* - * Probability estimation tables for the arithmetic encoder/decoder - * given by ITU T.82 Table 24. - * - * $Id: jbig_tab.c,v 1.6 1998-04-05 18:36:19+01 mgk25 Rel $ - */ - -short jbg_lsz[113] = { - 0x5a1d, 0x2586, 0x1114, 0x080b, 0x03d8, 0x01da, 0x00e5, 0x006f, - 0x0036, 0x001a, 0x000d, 0x0006, 0x0003, 0x0001, 0x5a7f, 0x3f25, - 0x2cf2, 0x207c, 0x17b9, 0x1182, 0x0cef, 0x09a1, 0x072f, 0x055c, - 0x0406, 0x0303, 0x0240, 0x01b1, 0x0144, 0x00f5, 0x00b7, 0x008a, - 0x0068, 0x004e, 0x003b, 0x002c, 0x5ae1, 0x484c, 0x3a0d, 0x2ef1, - 0x261f, 0x1f33, 0x19a8, 0x1518, 0x1177, 0x0e74, 0x0bfb, 0x09f8, - 0x0861, 0x0706, 0x05cd, 0x04de, 0x040f, 0x0363, 0x02d4, 0x025c, - 0x01f8, 0x01a4, 0x0160, 0x0125, 0x00f6, 0x00cb, 0x00ab, 0x008f, - 0x5b12, 0x4d04, 0x412c, 0x37d8, 0x2fe8, 0x293c, 0x2379, 0x1edf, - 0x1aa9, 0x174e, 0x1424, 0x119c, 0x0f6b, 0x0d51, 0x0bb6, 0x0a40, - 0x5832, 0x4d1c, 0x438e, 0x3bdd, 0x34ee, 0x2eae, 0x299a, 0x2516, - 0x5570, 0x4ca9, 0x44d9, 0x3e22, 0x3824, 0x32b4, 0x2e17, 0x56a8, - 0x4f46, 0x47e5, 0x41cf, 0x3c3d, 0x375e, 0x5231, 0x4c0f, 0x4639, - 0x415e, 0x5627, 0x50e7, 0x4b85, 0x5597, 0x504f, 0x5a10, 0x5522, - 0x59eb -}; - -unsigned char jbg_nmps[113] = { - 1, 2, 3, 4, 5, 6, 7, 8, - 9, 10, 11, 12, 13, 13, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, - 33, 34, 35, 9, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 52, 53, 54, 55, 56, - 57, 58, 59, 60, 61, 62, 63, 32, - 65, 66, 67, 68, 69, 70, 71, 72, - 73, 74, 75, 76, 77, 78, 79, 48, - 81, 82, 83, 84, 85, 86, 87, 71, - 89, 90, 91, 92, 93, 94, 86, 96, - 97, 98, 99, 100, 93, 102, 103, 104, - 99, 106, 107, 103, 109, 107, 111, 109, - 111 -}; - -/* - * least significant 7 bits (mask 0x7f) of jbg_nlps[] contain NLPS value, - * most significant bit (mask 0x80) contains SWTCH bit - */ -unsigned char jbg_nlps[113] = { - 129, 14, 16, 18, 20, 23, 25, 28, - 30, 33, 35, 9, 10, 12, 143, 36, - 38, 39, 40, 42, 43, 45, 46, 48, - 49, 51, 52, 54, 56, 57, 59, 60, - 62, 63, 32, 33, 165, 64, 65, 67, - 68, 69, 70, 72, 73, 74, 75, 77, - 78, 79, 48, 50, 50, 51, 52, 53, - 54, 55, 56, 57, 58, 59, 61, 61, - 193, 80, 81, 82, 83, 84, 86, 87, - 87, 72, 72, 74, 74, 75, 77, 77, - 208, 88, 89, 90, 91, 92, 93, 86, - 216, 95, 96, 97, 99, 99, 93, 223, - 101, 102, 103, 104, 99, 105, 106, 107, - 103, 233, 108, 109, 110, 111, 238, 112, - 240 -}; - -/* - * Resolution reduction table given by ITU-T T.82 Table 17 - */ - -char jbg_resred[4096] = { - 0,0,0,1,0,0,0,1,0,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1, - 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1, - 0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1, - 1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,1,0,1,0,0,1,1,1,0,1,1, - 0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,0,0,1,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1, - 1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1, - 0,0,1,1,0,0,0,1,0,0,0,1,0,0,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0,1,1,0,1,1,1,1,1,1,0,1,1,1,0, - 0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1, - 0,0,0,1,0,0,0,1,0,1,1,0,1,0,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1, - 1,1,1,0,1,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1, - 1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,1,1,1,1,1,1, - 0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,1,1,0,1,0,1,1,0,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,1,0,1,1,0,0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,1,0,1,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,0,0,1,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,1,1,1,1,0,1,1, - 1,0,0,1,0,0,1,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0, - 0,0,1,0,1,1,1,1,0,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0, - 0,0,0,0,1,0,0,1,0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,0,1,1,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,0,1,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,0,0,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1, - 0,0,1,0,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,1, - 0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,1,0,0,1,0,0,1,1, - 0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,0,1,0,0,0,0,1,0,1,0,1,0,1,0,1, - 0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,1,0,0,0,0,0,0,0,1,1,1,1,0,1,1,1, - 0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,1,0,1,0,1,1,0,0,0,1,0,0,1,1, - 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,1,1,0,0,1,1, - 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1, - 0,0,1,0,0,1,1,1,0,0,0,0,1,0,0,1,0,0,0,1,1,1,1,0,1,0,1,1,1,1,1,1, - 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,1,1,0, - 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,1,1,1,0,1,1,1, - 0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,1,1,0,1,0,0,0,1,1,0,1,0,0,0,0,1,1,1,1,0,0,1,1,1,0,1,1,0,0,1,1, - 0,0,0,0,0,0,0,0,1,1,0,1,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1, - 0,0,1,1,0,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,0,1,0,0,0,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1, - 0,0,0,1,0,0,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1, - 0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1, - 0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1, - 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,1,1,0,1,1, - 0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,0,1,0,1,0,1,1,0,1,1,1,0,1,1,1, - 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,1,0,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1, - 0,0,0,0,1,0,0,1,0,0,1,1,0,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1, - 1,0,1,0,1,0,0,1,1,0,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,1,0,1,1,0,1,1,1, - 0,0,1,0,0,0,0,1,0,0,0,0,0,0,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,1,1,0,1,1,0,1,1,1,1, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,1,1,0,1,0,1,0,1,1,0,1,0,1,0,0,0,1,1,1,1,1,1,1,1,1, - 1,1,1,0,1,0,0,0,1,1,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1, - 1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,1,1,0,1,1, - 0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,0,1,1,0,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,0,1,0,1,0,0,1,0,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1, - 0,0,0,0,1,0,1,0,0,0,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1, - 1,0,0,0,1,0,0,0,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,1,1,1,0,1,1,0, - 0,0,1,1,1,1,1,1,0,0,0,0,1,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,1,1,0,1,1,1,1,1,1,1, - 0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1, - 0,0,1,0,1,0,1,1,0,0,1,0,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1, - 0,0,1,0,1,0,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,0,1,1,0,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,1, - 0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1, - 0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,0,1,0,0,0,0,1,0,1,0,1,0,1,0,1, - 0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,1,0,0,1,1, - 0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,1, - 0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,1, - 0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,1, - 1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0, - 0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,1, - 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1, - 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1, - 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0,1,0,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,1,1, - 0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,1,1,0,0,0,1,0,1,1,1,0,1,1,1 -}; - -/* - * Deterministic prediction tables given by ITU-T T.82 tables - * 19 to 22. The table below is organized differently, the - * index bits are permutated for higher efficiency. - */ - -char jbg_dptable[256 + 512 + 2048 + 4096] = { - /* phase 0: offset=0 */ - 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2, - 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,0,2,2,2,2,2,2,2, - 0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,0,2,0,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - /* phase 1: offset=256 */ - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2, - 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,0,2,0,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2, - 0,2,2,2,2,1,2,1,2,2,2,2,1,1,1,1,2,0,2,0,2,2,2,2,0,2,0,2,2,2,2,2, - 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,2,2,2,2,0,2,2,2,2,2,2,2, - 0,2,0,2,2,2,2,2,2,2,2,2,2,0,2,0,2,2,0,0,2,2,2,2,2,0,0,2,2,2,2,2, - 0,2,2,2,2,1,2,1,2,2,2,2,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1, - 1,2,1,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,1,1,2,2,2,2,2,0,2,2,2,2,2,2, - 2,2,2,2,2,0,2,0,2,2,2,2,0,0,0,0,0,2,0,2,2,2,2,2,0,2,2,2,2,2,2,2, - 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,2,2,2,0,2,0,2,2,2,2,2, - 2,2,2,2,2,1,1,1,2,2,2,2,1,1,1,1,1,2,1,2,2,2,2,2,2,2,2,2,2,2,2,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,0,1,2,0,2,0,2,2,2,2,2,0,2,0,2,2,2,2,1, - 0,2,0,2,2,1,2,1,2,2,2,2,1,1,1,1,0,0,0,0,2,2,2,2,0,2,0,2,2,2,2,1, - 2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,0,0,0,2,2,2,2,2, - 2,2,2,2,2,1,2,1,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,1,2,1,2,2,2,2,1, - 2,2,2,2,2,2,2,2,0,2,0,2,2,1,2,2,2,2,2,2,2,2,2,2,0,0,0,2,2,2,2,2, - /* phase 2: offset=768 */ - 2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,2,2,2,2,1,1,1,1, - 0,2,2,2,2,1,2,1,2,2,2,2,1,2,1,2,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1, - 2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,1,2,1,2,2,2,2,2,1,1,1, - 2,0,2,2,2,1,2,1,0,2,2,2,1,2,1,2,2,2,2,0,2,2,2,2,0,2,0,2,2,2,2,2, - 0,2,0,0,1,1,1,1,2,2,2,2,1,1,1,1,0,2,0,2,1,1,1,1,2,2,2,2,1,1,1,1, - 2,2,0,2,2,2,1,2,2,2,2,2,1,2,1,2,2,2,0,2,2,1,2,1,0,2,0,2,1,1,1,1, - 2,0,0,2,2,2,2,2,0,2,0,2,2,0,2,0,2,0,2,0,2,2,2,1,2,2,0,2,1,1,2,1, - 2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,2,2,2,2,1,1,1,1, - 0,0,0,0,2,2,2,2,0,0,0,0,2,2,2,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,0,2,2,2,2,1,0,2,2,2,1,1,1,1,2,0,2,2,2,2,2,2,0,2,0,2,2,1,2,1, - 2,0,2,0,2,2,2,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2, - 0,2,2,2,1,2,1,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2, - 2,2,0,2,2,2,2,2,2,2,2,2,2,2,0,2,2,0,0,2,2,1,2,1,0,2,2,2,1,1,1,1, - 2,2,2,0,2,2,2,2,2,2,0,2,2,0,2,0,2,1,2,2,2,2,2,2,1,2,1,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,2,2,1, - 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,1,1,1,2,2,2,2,1,1,1,1, - 2,2,2,1,2,2,2,2,2,2,1,2,0,0,0,0,2,2,0,2,2,1,2,2,2,2,2,2,1,1,1,1, - 2,0,0,0,2,2,2,2,0,2,2,2,2,2,2,0,2,2,2,0,2,2,2,2,2,0,0,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,0,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,1, - 0,2,0,2,2,1,1,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2, - 2,0,2,0,2,1,2,1,0,2,0,2,2,2,1,2,2,0,2,0,2,2,2,2,0,2,0,2,2,2,1,2, - 2,2,2,0,2,2,2,2,2,2,0,2,2,2,2,2,2,2,1,2,2,2,2,2,2,0,1,2,2,2,2,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, - 0,2,2,2,1,2,1,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2, - 2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,1,2,1,0,2,2,2,1,1,1,1, - 2,0,2,0,2,1,2,2,0,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,1,2,2, - 2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,0,2,2,2,2,0,0,0,0,2,1,2,1, - 2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,0,0,2,2,2,1,2,2,2, - 0,0,2,0,2,2,2,2,0,2,0,2,2,0,2,0,1,1,1,2,2,2,2,2,2,2,2,2,2,1,1,1, - 2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,0,2,0,2,2,2,1, - 2,2,0,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,2,2,2,2,1,1,1,1, - 0,2,2,2,1,2,1,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2, - 2,0,0,2,2,2,2,2,0,2,0,2,2,2,2,2,1,0,1,2,2,2,2,1,0,2,2,2,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,0,2,2,0,2,0,2,1,2,2,2,2,2,2,2,2,0,2,2,1,2,2, - 0,2,0,0,1,1,1,1,0,2,2,2,1,1,1,1,2,2,2,2,2,2,2,2,2,0,2,2,1,2,1,1, - 2,2,0,2,2,1,2,2,2,2,2,2,1,2,2,2,2,0,2,2,2,2,2,2,0,2,0,2,1,2,1,1, - 2,0,2,0,2,2,2,2,0,2,0,2,2,1,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,1, - 2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, - 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 0,2,2,2,2,0,2,0,2,2,2,2,0,0,0,0,2,2,2,2,2,1,1,2,2,2,2,2,1,2,2,2, - 2,0,2,2,2,1,2,1,0,2,2,2,2,2,1,2,2,0,2,0,2,2,2,2,0,2,0,2,2,1,2,2, - 0,2,0,0,2,2,2,2,1,2,2,2,2,2,2,0,2,1,2,2,2,2,2,2,1,2,2,2,2,2,2,2, - 0,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,1,0,2,2, - 0,0,0,2,2,1,1,1,2,2,2,2,1,2,2,2,2,0,2,0,2,2,2,1,2,2,2,2,1,2,1,2, - 0,0,0,0,2,2,2,2,2,2,0,2,2,1,2,2,2,1,2,1,2,2,2,2,1,2,1,2,0,2,2,2, - 2,0,2,0,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, - 0,2,2,2,1,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,1,2,2,2,2,2,0,2,2,1,2,2,0,0,0,2,2,2,2,2,1,2,2,0,2,2,2,1,2,1,2, - 2,0,2,0,2,2,2,2,0,2,0,2,2,1,2,2,0,2,0,0,2,2,2,2,2,2,2,2,2,1,2,2, - 2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,0,2,0,2,2,2,1, - 1,2,0,2,2,1,2,1,2,2,2,2,1,2,2,2,2,0,2,0,2,2,2,2,2,0,2,2,1,1,1,1, - 0,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,2,1,2,1, - 2,2,0,0,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1, - 2,2,2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,1,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2, - 2,0,2,0,2,2,2,2,2,1,1,2,2,2,2,2,2,2,2,2,2,2,2,1,0,2,0,2,2,2,1,2, - 2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2, - 2,0,2,0,2,2,2,2,2,0,2,0,2,2,2,2,2,0,2,0,2,2,2,2,0,0,0,0,2,1,2,1, - 2,2,2,2,2,1,2,1,0,2,0,2,2,2,2,2,2,0,2,0,2,2,2,2,0,2,0,2,2,2,2,1, - 2,0,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,0, - 2,0,2,0,2,2,2,1,2,2,2,0,2,2,2,1,2,0,2,0,2,2,2,2,0,0,0,2,2,2,2,1, - 2,0,2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2, - /* phase 3: offset=2816 */ - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1, - 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,1,2,1,2,0,2,0,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,0,2,2,2,1,2,0,2,2,2,1,2,2,2,2,0,2,0,2,1,2,1,0,0,0,0,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,0,2,2,2,1,2, - 2,2,2,1,2,2,2,0,1,1,1,1,0,0,0,0,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,0,0,0,0,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1,0,0,0,0,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,2, - 2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1,2,0,2,0,2,1,2,1, - 2,0,0,0,2,1,1,1,0,0,0,0,1,1,1,1,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2, - 2,0,2,2,2,1,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,0,0,2,0,1,1,2,1, - 2,2,2,0,2,2,2,1,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1, - 0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,2,0,2,0,2,1,2,1,0,0,0,0,1,1,1,1, - 2,0,0,2,2,1,1,2,2,2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,2,1,1,1,2,0,0,0, - 2,1,2,1,2,0,2,0,1,2,1,2,0,2,0,2,2,2,2,0,2,2,2,1,2,0,2,0,2,1,2,1, - 2,0,2,0,2,1,2,1,0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1, - 2,2,2,2,2,2,2,2,2,0,0,0,2,1,1,1,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2, - 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2, - 2,0,0,0,2,1,1,1,0,0,0,0,1,1,1,1,2,0,2,0,2,1,2,1,0,0,2,0,1,1,2,1, - 2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,0,0,0,2,1,1,1, - 2,2,2,1,2,2,2,0,2,1,1,1,2,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,1,2,1,2,0,2,0,2, - 2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, - 2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,2,1,1,1,0,0,0,0,1,1,1,1, - 2,0,2,2,2,1,2,2,0,0,2,0,1,1,2,1,2,1,2,1,2,0,2,0,2,2,2,2,2,2,2,2, - 2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,0,0,0,0,1,1,1,1, - 2,0,0,0,2,1,1,1,0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,2,1,0,2,2,0,1,2, - 2,2,2,1,2,2,2,0,2,1,1,1,2,0,0,0,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, - 2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, - 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2, - 2,1,2,1,2,0,2,0,1,2,1,1,0,2,0,0,0,0,2,1,1,1,2,0,0,0,0,0,1,1,1,1, - 2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,0,2,1,2,1,2,0,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,0,2,2,2,1,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,0,2,2,2,1,2,2,2,0,0,2,2,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2, - 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2, - 2,0,2,0,2,1,2,1,0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,0,0,0,0,1,1,1,1, - 2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,0,0,0,2,1,1,1, - 2,2,2,0,2,2,2,1,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2, - 2,0,2,2,2,1,2,2,2,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, - 2,1,2,1,2,0,2,0,1,2,1,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,1,2,1,2,0,2,0,1,2,1,1,0,2,0,0,2,0,2,2,2,1,2,2,0,2,1,2,1,2,0,2, - 2,2,2,1,2,2,2,0,2,2,1,2,2,2,0,2,2,1,2,2,2,0,2,2,2,2,0,2,2,2,1,2, - 0,0,2,0,1,1,2,1,0,0,1,0,1,1,0,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,0,2,2,2,1,1,2,2,2,0,2,2,2,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1, - 2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, - 2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,0,0,2,2,1,1,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2, - 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2, - 2,0,0,0,2,1,1,1,0,0,0,0,1,1,1,1,2,2,2,1,2,2,2,0,2,1,2,1,2,0,2,0, - 2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2,0,2,0,0,1,2,1,1,2,0,0,0,2,1,1,1, - 2,2,2,2,2,2,2,2,2,1,1,1,2,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,0,2,2,2,1,2,2,0,2,2,2,1,2,2,1,2,1,2,0,2,0,2,0,2,2,2,1,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,1,1,1,2,0,0,0, - 2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,0,0,1,2,1,1, - 2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,0,2,2,2,1,2,2,2, - 2,1,2,1,2,0,2,0,2,1,2,2,2,0,2,2,2,2,2,0,2,2,2,1,2,0,2,0,2,1,2,1, - 2,0,2,0,2,1,2,1,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2, - 2,2,2,2,2,2,2,2,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,0,1,0,0,1,0,1,1, - 2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,1,2,2,1,0,2,0,2,2,2,1,2,2,2, - 2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,0,2,2,2,1,2,2,0,2,2,2,1,2, - 2,0,2,0,2,1,2,1,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2, - 0,2,0,0,1,2,1,1,2,0,0,0,2,1,1,1,2,2,2,2,2,2,2,2,1,0,1,2,0,1,0,2, - 2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,1,2,2,2,0,2,2,1,1,2,2,0,0,2,2, - 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,1,2,1,2,0,2,0,2,1,2,2,2,0,2,2,2,0,2,2,2,1,2,2,0,2,2,2,1,2,2,2, - 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,1,2,2,2,0,2,2,2, - 2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1,2, - 0,0,0,0,1,1,1,1,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,2,2,0,2,2,2,1,2, - 2,0,2,0,2,1,2,1,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2, - 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,1,2,2,2,0,1,1,2,1,0,0,2,0,2,0,2,2,2,1,2,2,0,2,2,2,1,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,0,2,2,2,1,2, - 2,0,2,0,2,1,2,1,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2, - 0,2,0,0,1,2,1,1,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,0,0,0,2,1,1,1,2, - 2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, - 2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,0,0,2,1,1,1,2,0,0,2,2,2,1,2,2,2, - 2,1,2,1,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,0,1,2,1,1, - 0,0,2,2,1,1,2,2,0,2,1,2,1,2,0,2,2,1,2,1,2,0,2,0,1,2,1,2,0,2,0,2, - 2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,2,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1, - 2,2,0,0,2,2,1,1,2,2,0,0,2,2,1,1,2,2,2,2,2,2,2,2,2,2,0,0,2,2,1,1, - 2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,0,0,1,2,1,1, - 2,2,2,0,2,2,2,1,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,1,1,1,2,0,0,0,2, - 2,2,2,2,2,2,2,2,1,1,1,2,0,0,0,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2, - 2,0,2,0,2,1,2,1,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,0,0,0,2,1,1,1, - 2,0,2,2,2,1,2,2,0,2,2,2,1,2,2,2,2,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2, - 2,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,0,2,0,2,1,2,1,2,1,2,0,2,0,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,0,2,0,2,1,2,1,1,2,1,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,2,2,1,2,1,2,0,2,0,2,2,2,2,2,2,2,2, - 2,0,2,1,2,1,2,0,0,2,1,2,1,2,0,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, - 2,0,2,0,2,1,2,1,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1, - 2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,1,2,1,2,0,2,0,1,1,1,2,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, - 2,0,2,0,2,1,2,1,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, -}; diff --git a/converter/other/jbig/jbigtopnm.c b/converter/other/jbig/jbigtopnm.c index 7a6e95c1..733ba227 100644 --- a/converter/other/jbig/jbigtopnm.c +++ b/converter/other/jbig/jbigtopnm.c @@ -231,7 +231,7 @@ int main (int argc, char **argv) pm_error("Problem while reading input file '%s", fnin); if (result != JBG_EOK && result != JBG_EOK_INTR) pm_error("Problem with input file '%s': %s\n", - fnin, jbg_strerror(result, JBG_EN)); + fnin, jbg_strerror(result)); if (plane >= 0 && jbg_dec_getplanes(&s) <= plane) pm_error("Image has only %d planes!\n", jbg_dec_getplanes(&s)); diff --git a/converter/other/jbig/libjbig/ANNOUNCE b/converter/other/jbig/libjbig/ANNOUNCE new file mode 100644 index 00000000..15ce550d --- /dev/null +++ b/converter/other/jbig/libjbig/ANNOUNCE @@ -0,0 +1,172 @@ + +JBIG-KIT lossless image compression library +------------------------------------------- + +by Markus Kuhn + + +The latest release of JBIG-KIT can be downloaded from + + http://www.cl.cam.ac.uk/~mgk25/jbigkit/ + +JBIG-KIT implements a highly effective data compression algorithm for +bi-level high-resolution images such as fax pages or scanned +documents. + +JBIG-KIT provides two variants of a portable library of compression +and decompression functions with a documented interface. You can very +easily include into your image or document processing software. In +addition, JBIG-KIT provides ready-to-use compression and decompression +programs with a simple command line interface (similar to the +converters found in Jef Poskanzer's PBM graphics file conversion +package). + +JBIG-KIT implements the specification + + International Standard ISO/IEC 11544:1993 and ITU-T Recommendation + T.82(1993), "Information technology - Coded representation of picture + and audio information - progressive bi-level image compression", + , + +which is commonly referred to as the "JBIG1 standard". JBIG (Joint +Bi-level Image experts Group) is the committee which developed this +international standard for the lossless compression of images using +arithmetic coding. Like the well-known compression algorithms JPEG and +MPEG, JBIG has also been developed and published by the International +Organization for Standardization (ISO) and the International +Telecommunication Union (ITU). See also + + http://www.jpeg.org/jbig/ + http://www.iso.ch/ + http://www.itu.int/ + +The JBIG compression algorithm offers the following features: + + - Close to state-of-the-art lossless compression ratio for high + resolution bi-level images. + + - About 1.1 to 1.5 times better compression ratio on typical + scanned documents compared to G4 fax compression (ITU-T T.6), + which has been the best compression algorithm for scanned + documents available prior to JBIG. + + - Up to 30 times better compression of scanned images with dithered + images compared to G4 fax compression. + + - About 2 times better compression on typical 300 dpi documents + compared to 'gzip -9' on raw bitmaps. + + - About 3-4 times better compression than GIF on typical 300 dpi + documents. + + - Even much better competitive compression results on computer + generated images which are free of scanning distortions. + + - JBIG supports hierarchical "progressive" encoding, that means it is + possible to encode a low resolution image first, followed by + resolution enhancement data. This allows, for instance, a document + browser to display already a good 75 dpi low resolution version of + an image, while the data necessary to reconstruct the full 300 dpi + version for laser printer reproduction is still arriving (say + over a slow network link or mass storage medium). + + - The various resolution layers of a JBIG image in progressive + encoding mode together require not much more space than a + normal non-progressive mode encoded image (which JBIG also + supports). + + - The progressive encoding mode utilizes a quite sophisticated + resolution reduction algorithm which offers high quality low + resolution versions that preserve the shape of characters as well + as the integrity of thin lines and dithered images. + + - JBIG supports multiple bit planes and can this way also be used + for grayscale and color images, although the main field of + application is compression of bi-level images, i.e. images with + only two different pixel values. For grayscale images with up to + 6 bit per pixel, JBIG performs superior to JPEG's lossless + mode. + +JBIG-KIT can be used as free software under the GNU General Public +License. Other license arrangements more suitable for commercial +applications are available as well, please contact the author for +details. JBIG-KIT provides two portable libraries implemented in +ANSI/ISO C for encoding and decoding JBIG data streams, along with +documentation. The first library, jbig.c, implements nearly all of the +options that the JBIG standard provides, but keeps the entire +uncompressed image in memory. The second library, jbig85.c, implements +only the ITU-R T.85 subset of the standard that black/white fax +machines use (single bit per pixel, no "progressive" encoding), and +keeps only three lines of the uncompressed image in memory, making it +particularly attractive for low-memory embedded applications. + +The libraries are not intended for 8-bit or 16-bit machine +architectures (e.g., old MS-DOS C compilers). For maximum performance, +a 32-bit processor is required (64-bit systems work too, of course). +On architectures with 16-bit pointer arithmetic, the full-featured +jbig.c library can process only very small images. + +Special features of the full-featured jbig.c variant: + + - Fully reentrant multithread-capable design (no global or static + variables, isolated malloc()/free() calls, etc.) + + - Capable of handling incomplete and growing JBIG data streams in + order to allow earliest display of low resolution versions + + - Capable of handling several incoming data streams simultaneously + in one single process and thread + + - Especially designed with applications in mind that want to display + incoming data as early as possible (e.g., similar to the way in + which Netscape Navigator handles incoming GIF images) + + - Implements all JBIG features and options including progressive and + sequential encoding, multiple bit planes, user specified + resolution reduction and deterministic prediction tables, adaptive + template changes for optimal performance on half-tone images, + deterministic prediction, typical prediction in lowest and + differential layers, various stripe orderings, etc; only the SEQ + and HITOLO options are currently not supported by the decoder + (they are normally never required, but could be added later in + case of user requirements) + + - Suitable for fax applications, satisfies ITU-T T.85 profile + + - Efficient code, optimized utilization of 32-bit processor + registers + + - Very easy to use documented C library interface + + - Included Gray code conversion routines for efficient encoding + of grayscale images + + - Ready-to-use pbmtojbg and jbgtopbm converters. + +Special features of the light-weight jbig85.c variant: + + - Suitable for low-memory embedded applications + + - Implements only the JBIG1 subset defined in the ITU-T T.85 + profile (single bit plane, no differential layers) + + - Requires only three pixel rows of the uncompressed image to be + kept in memory + + - Handles all NEWLEN modes of operation required by ITU-T T.85 with + just a single pass over the data, automatically performing the + necessary lookahead after the last stripe + + - Codec buffers only a few bytes of arithmetic-codec data and outputs + resulting bytes or lines as soon as they are available. + +I will try to provide free support and maintenance for this software +for the foreseeable future, depending on my available time. + +Happy compressing ... + +Markus Kuhn + +-- +Markus Kuhn, Computer Laboratory, University of Cambridge +http://www.cl.cam.ac.uk/~mgk25/ || CB3 0FD, Great Britain diff --git a/converter/other/jbig/libjbig/COPYING b/converter/other/jbig/libjbig/COPYING new file mode 100644 index 00000000..a43ea212 --- /dev/null +++ b/converter/other/jbig/libjbig/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/converter/other/jbig/libjbig/Makefile b/converter/other/jbig/libjbig/Makefile new file mode 100644 index 00000000..2e574903 --- /dev/null +++ b/converter/other/jbig/libjbig/Makefile @@ -0,0 +1,24 @@ +ifeq ($(SRCDIR)x,x) + SRCDIR = $(CURDIR)/../../../.. + BUILDDIR = $(SRCDIR) +endif +SUBDIR = converter/other/jbig/libjbig +VPATH=.:$(SRCDIR)/$(SUBDIR) + +include $(BUILDDIR)/config.mk + +LIBJBIG_OBJECTS = jbig.o jbig_ar.o + +OBJECTS = $(LIBJBIG_OBJECTS) +MERGE_OBJECTS = $(LIBJBIG_OBJECTS) + +COMP_INCLUDES = -I$(SRCDIR)/$(SUBDIR)/include + +all: libjbig.a + +include $(SRCDIR)/common.mk + +libjbig.a: $(LIBJBIG_OBJECTS) + $(AR) -rc $@ $^ + $(RANLIB) $@ + diff --git a/converter/other/jbig/libjbig/include/jbig.h b/converter/other/jbig/libjbig/include/jbig.h new file mode 100644 index 00000000..67994107 --- /dev/null +++ b/converter/other/jbig/libjbig/include/jbig.h @@ -0,0 +1,233 @@ +/* + * Header file for the portable JBIG compression library + * + * Copyright 1995-2014 -- Markus Kuhn -- http://www.cl.cam.ac.uk/~mgk25/ + */ + +#ifndef JBG_H +#define JBG_H + +#include +#include "jbig_ar.h" + +/* + * JBIG-KIT version number + */ + +#define JBG_VERSION "2.1" +#define JBG_VERSION_MAJOR 2 +#define JBG_VERSION_MINOR 1 + +/* + * JBIG-KIT licence agreement reference code: + * If you use JBIG-KIT under a commercial licence, please replace + * below the letters GPL with the reference code that you received + * with your licence agreement. (This code is typically a letter "A" + * followed by four decimal digits, e.g. "A1234".) + */ + +#define JBG_LICENCE "GPL" + +/* + * Buffer block for SDEs which are temporarily stored by encoder + */ + +#define JBG_BUFSIZE 4000 + +struct jbg_buf { + unsigned char d[JBG_BUFSIZE]; /* one block of a buffer list */ + int len; /* length of the data in this block */ + struct jbg_buf *next; /* pointer to next block */ + struct jbg_buf *previous; /* pointer to previous block * + * (unused in freelist) */ + struct jbg_buf *last; /* only used in list head: final block of list */ + struct jbg_buf **free_list; /* pointer to pointer to head of free list */ +}; + +/* + * Maximum number of ATMOVEs per stripe that decoder can handle + */ + +#define JBG_ATMOVES_MAX 64 + +/* + * Option and order flags + */ + +#define JBG_HITOLO 0x08 +#define JBG_SEQ 0x04 +#define JBG_ILEAVE 0x02 +#define JBG_SMID 0x01 + +#define JBG_LRLTWO 0x40 +#define JBG_VLENGTH 0x20 +#define JBG_TPDON 0x10 +#define JBG_TPBON 0x08 +#define JBG_DPON 0x04 +#define JBG_DPPRIV 0x02 +#define JBG_DPLAST 0x01 + +/* encoding options that will not be indicated in the header */ + +#define JBG_DELAY_AT 0x100 /* Delay ATMOVE until the first line of the next + * stripe. Option available for compatibility + * with conformance test example in clause 7.2. */ + +#define JBG_SDRST 0x200 /* Use SDRST instead of SDNORM. This option is + * there for anyone who needs to generate + * test data that covers the SDRST cases. */ + +/* + * Possible error code return values + */ + +#define JBG_EOK (0 << 4) +#define JBG_EOK_INTR (1 << 4) +#define JBG_EAGAIN (2 << 4) +#define JBG_ENOMEM (3 << 4) +#define JBG_EABORT (4 << 4) +#define JBG_EMARKER (5 << 4) +#define JBG_EINVAL (6 << 4) +#define JBG_EIMPL (7 << 4) +#define JBG_ENOCONT (8 << 4) + +/* + * Status of a JBIG encoder + */ + +struct jbg_enc_state { + int d; /* resolution layer of the input image */ + unsigned long xd, yd; /* size of the input image (resolution layer d) */ + unsigned long yd1; /* BIH announced height of image, use yd1 != yd to + emulate T.85-style NEWLEN height updates for tests */ + int planes; /* number of different bitmap planes */ + int dl; /* lowest resolution layer in the next BIE */ + int dh; /* highest resolution layer in the next BIE */ + unsigned long l0; /* number of lines per stripe at lowest * + * resolution layer 0 */ + unsigned long stripes; /* number of stripes required (determ. by l0) */ + unsigned char **lhp[2]; /* pointers to lower/higher resolution images */ + int *highres; /* index [plane] of highres image in lhp[] */ + int order; /* SDE ordering parameters */ + int options; /* encoding parameters */ + unsigned mx, my; /* maximum ATMOVE window size */ + int *tx; /* array [plane] with x-offset of adaptive template pixel */ + char *dppriv; /* optional private deterministic prediction table */ + char *res_tab; /* table for the resolution reduction algorithm */ + struct jbg_buf ****sde; /* array [stripe][layer][plane] pointers to * + * buffers for stored SDEs */ + struct jbg_arenc_state *s; /* array [planes] for arithm. encoder status */ + struct jbg_buf *free_list; /* list of currently unused SDE block buffers */ + void (*data_out)(unsigned char *start, size_t len, void *file); + /* data write callback */ + void *file; /* parameter passed to data_out() */ + char *tp; /* buffer for temp. values used by diff. typical prediction */ + unsigned char *comment; /* content of comment marker segment to be added + at next opportunity (will be reset to NULL + as soon as comment has been written) */ + unsigned long comment_len; /* length of data pointed to by comment */ +}; + + +/* + * Status of a JBIG decoder + */ + +struct jbg_dec_state { + /* data from BIH */ + int d; /* resolution layer of the full image */ + int dl; /* first resolution layer in this BIE */ + unsigned long xd, yd; /* size of the full image (resolution layer d) */ + int planes; /* number of different bitmap planes */ + unsigned long l0; /* number of lines per stripe at lowest * + * resolution layer 0 */ + unsigned long stripes; /* number of stripes required (determ. by l0) */ + int order; /* SDE ordering parameters */ + int options; /* encoding parameters */ + int mx, my; /* maximum ATMOVE window size */ + char *dppriv; /* optional private deterministic prediction table */ + + /* loop variables */ + unsigned long ii[3]; /* current stripe, layer, plane (outer loop first) */ + + /* + * Pointers to array [planes] of lower/higher resolution images. + * lhp[d & 1] contains image of layer d. + */ + unsigned char **lhp[2]; + + /* status information */ + int **tx, **ty; /* array [plane][layer-dl] with x,y-offset of AT pixel */ + struct jbg_ardec_state **s; /* array [plane][layer-dl] for arithmetic * + * decoder status */ + int **reset; /* array [plane][layer-dl] remembers if previous stripe * + * in that plane/resolution ended with SDRST. */ + unsigned long bie_len; /* number of bytes read so far */ + unsigned char buffer[20]; /* used to store BIH or marker segments fragm. */ + int buf_len; /* number of bytes in buffer */ + unsigned long comment_skip; /* remaining bytes of a COMMENT segment */ + unsigned long x; /* x position of next pixel in current SDE */ + unsigned long i; /* line in current SDE (first line of each stripe is 0) */ + int at_moves; /* number of AT moves in the current stripe */ + unsigned long at_line[JBG_ATMOVES_MAX]; /* lines at which an * + * AT move will happen */ + int at_tx[JBG_ATMOVES_MAX], at_ty[JBG_ATMOVES_MAX]; /* ATMOVE offsets in * + * current stripe */ + unsigned long line_h1, line_h2, line_h3; /* variables of decode_pscd */ + unsigned long line_l1, line_l2, line_l3; + int pseudo; /* flag for TPBON/TPDON: next pixel is pseudo pixel */ + int **lntp; /* flag [plane][layer-dl] for TP: line is not typical */ + + unsigned long xmax, ymax; /* if possible abort before image gets * + * larger than this size */ + int dmax; /* abort after this layer */ +}; + + +/* some macros (too trivial for a function) */ + +#define jbg_dec_getplanes(s) ((s)->planes) + + +/* function prototypes */ + +void jbg_enc_init(struct jbg_enc_state *s, unsigned long x, unsigned long y, + int planes, unsigned char **p, + void (*data_out)(unsigned char *start, size_t len, + void *file), + void *file); +int jbg_enc_lrlmax(struct jbg_enc_state *s, unsigned long mwidth, + unsigned long mheight); +void jbg_enc_layers(struct jbg_enc_state *s, int d); +int jbg_enc_lrange(struct jbg_enc_state *s, int dl, int dh); +void jbg_enc_options(struct jbg_enc_state *s, int order, int options, + unsigned long l0, int mx, int my); +void jbg_enc_out(struct jbg_enc_state *s); +void jbg_enc_free(struct jbg_enc_state *s); + +void jbg_dec_init(struct jbg_dec_state *s); +void jbg_dec_maxsize(struct jbg_dec_state *s, unsigned long xmax, + unsigned long ymax); +int jbg_dec_in(struct jbg_dec_state *s, unsigned char *data, size_t len, + size_t *cnt); +unsigned long jbg_dec_getwidth(const struct jbg_dec_state *s); +unsigned long jbg_dec_getheight(const struct jbg_dec_state *s); +unsigned char *jbg_dec_getimage(const struct jbg_dec_state *s, int plane); +unsigned long jbg_dec_getsize(const struct jbg_dec_state *s); +void jbg_dec_merge_planes(const struct jbg_dec_state *s, int use_graycode, + void (*data_out)(unsigned char *start, size_t len, + void *file), void *file); +unsigned long jbg_dec_getsize_merged(const struct jbg_dec_state *s); +void jbg_dec_free(struct jbg_dec_state *s); + +const char *jbg_strerror(int errnum); +void jbg_int2dppriv(unsigned char *dptable, const char *internal); +void jbg_dppriv2int(char *internal, const unsigned char *dptable); +unsigned long jbg_ceil_half(unsigned long x, int n); +void jbg_split_planes(unsigned long x, unsigned long y, int has_planes, + int encode_planes, + const unsigned char *src, unsigned char **dest, + int use_graycode); +int jbg_newlen(unsigned char *bie, size_t len); + +#endif /* JBG_H */ diff --git a/converter/other/jbig/libjbig/include/jbig_ar.h b/converter/other/jbig/libjbig/include/jbig_ar.h new file mode 100644 index 00000000..d58b1ae0 --- /dev/null +++ b/converter/other/jbig/libjbig/include/jbig_ar.h @@ -0,0 +1,53 @@ +/* + * Header file for the arithmetic encoder and decoder of + * the portable JBIG compression library + * + * Markus Kuhn -- http://www.cl.cam.ac.uk/~mgk25/jbigkit/ + */ + +#ifndef JBG_AR_H +#define JBG_AR_H + +/* + * Status of arithmetic encoder + */ + +struct jbg_arenc_state { + unsigned char st[4096]; /* probability status for contexts, MSB = MPS */ + unsigned long c; /* register C: base of coding intervall, * + * layout as in Table 23 */ + unsigned long a; /* register A: normalized size of coding interval */ + long sc; /* number of buffered 0xff values that might still overflow */ + int ct; /* bit shift counter, determines when next byte will be written */ + int buffer; /* buffer for most recent output byte != 0xff */ + void (*byte_out)(int, void *); /* function that receives all PSCD bytes */ + void *file; /* parameter passed to byte_out */ +}; + +/* + * Status of arithmetic decoder + */ + +struct jbg_ardec_state { + unsigned char st[4096]; /* probability status for contexts, MSB = MPS */ + unsigned long c; /* register C: base of coding intervall, * + * layout as in Table 25 */ + unsigned long a; /* register A: normalized size of coding interval */ + unsigned char *pscd_ptr; /* pointer to next PSCD data byte */ + unsigned char *pscd_end; /* pointer to byte after PSCD */ + int ct; /* bit-shift counter, determines when next byte will be read; + * special value -1 signals that zero-padding has started */ + int startup; /* boolean flag that controls initial fill of s->c */ + int nopadding; /* boolean flag that triggers return -2 between + * reaching PSCD end and decoding the first symbol + * that might never have been encoded in the first + * place */ +}; + +void arith_encode_init(struct jbg_arenc_state *s, int reuse_st); +void arith_encode_flush(struct jbg_arenc_state *s); +void arith_encode(struct jbg_arenc_state *s, int cx, int pix); +void arith_decode_init(struct jbg_ardec_state *s, int reuse_st); +int arith_decode(struct jbg_ardec_state *s, int cx); + +#endif /* JBG_AR_H */ diff --git a/converter/other/jbig/libjbig/jbig.c b/converter/other/jbig/libjbig/jbig.c new file mode 100644 index 00000000..1ff867e8 --- /dev/null +++ b/converter/other/jbig/libjbig/jbig.c @@ -0,0 +1,3285 @@ +/* + * Portable JBIG image compression library + * + * Copyright 1995-2014 -- Markus Kuhn -- http://www.cl.cam.ac.uk/~mgk25/ + * + * This module implements a portable standard C encoder and decoder + * using the JBIG1 lossless bi-level image compression algorithm + * specified in International Standard ISO 11544:1993 and + * ITU-T Recommendation T.82. See the file jbig.txt for usage + * instructions and application examples. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * If you want to use this program under different license conditions, + * then contact the author for an arrangement. + */ + +#ifdef DEBUG +#include +#else +#define NDEBUG +#endif + +#include +#include +#include + +#include "jbig.h" + +#define MX_MAX 127 + /* maximal mx offset for adaptive template in the encoder */ + +#define TPB2CX 0x195 /* contexts for TP special pixels */ +#define TPB3CX 0x0e5 +#define TPDCX 0xc3f + +/* marker codes */ +#define MARKER_STUFF 0x00 +#define MARKER_RESERVE 0x01 +#define MARKER_SDNORM 0x02 +#define MARKER_SDRST 0x03 +#define MARKER_ABORT 0x04 +#define MARKER_NEWLEN 0x05 +#define MARKER_ATMOVE 0x06 +#define MARKER_COMMENT 0x07 +#define MARKER_ESC 0xff + +/* loop array indices */ +#define STRIPE 0 +#define LAYER 1 +#define PLANE 2 + +/* special jbg_buf pointers (instead of NULL) */ +#define SDE_DONE ((struct jbg_buf *) -1) +#define SDE_TODO ((struct jbg_buf *) 0) + +/* object code version id */ + +const char jbg_version[] = + "JBIG-KIT " JBG_VERSION " -- (c) 1995-2014 Markus Kuhn -- " + "Licence: " JBG_LICENCE "\n"; + +/* + * The following array specifies for each combination of the 3 + * ordering bits, which ii[] variable represents which dimension + * of s->sde. + */ +static const int iindex[8][3] = { + { 2, 1, 0 }, /* no ordering bit set */ + { -1, -1, -1}, /* SMID -> illegal combination */ + { 2, 0, 1 }, /* ILEAVE */ + { 1, 0, 2 }, /* SMID + ILEAVE */ + { 0, 2, 1 }, /* SEQ */ + { 1, 2, 0 }, /* SEQ + SMID */ + { 0, 1, 2 }, /* SEQ + ILEAVE */ + { -1, -1, -1 } /* SEQ + SMID + ILEAVE -> illegal combination */ +}; + +#define _(String) String /* to mark translatable string for GNU gettext */ + +/* + * Array with English ASCII error messages that correspond + * to return values from public functions in this library. + */ +static const char *errmsg[] = { + _("All OK"), /* JBG_EOK */ + _("Reached specified image size"), /* JBG_EOK_INTR */ + _("Unexpected end of input data stream"), /* JBG_EAGAIN */ + _("Not enough memory available"), /* JBG_ENOMEM */ + _("ABORT marker segment encountered"), /* JBG_EABORT */ + _("Unknown marker segment encountered"), /* JBG_EMARKER */ + _("Input data stream contains invalid data"), /* JBG_EINVAL */ + _("Input data stream uses unimplemented JBIG features"), /* JBG_EIMPL */ + _("Incremental BIE does not continue previous one") /* JBG_ENOCONT */ +}; + + +/* + * The following three functions are the only places in this code, were + * C library memory management functions are called. The whole JBIG + * library has been designed in order to allow multi-threaded + * execution. No static or global variables are used, so all fuctions + * are fully reentrant. However if you want to use this multi-thread + * capability and your malloc, realloc and free are not reentrant, + * then simply add the necessary semaphores or mutex primitives below. + * In contrast to C's malloc() and realloc(), but like C's calloc(), + * these functions take two parameters nmemb and size that are multiplied + * before being passed on to the corresponding C function. + * This we can catch all overflows during a size_t multiplication a + * a single place. + */ + +#ifndef SIZE_MAX +#define SIZE_MAX ((size_t) -1) /* largest value of size_t */ +#endif + +static void *checked_malloc(size_t nmemb, size_t size) +{ + void *p; + + /* Full manual exception handling is ugly here for performance + * reasons. If an adequate handling of lack of memory is required, + * then use C++ and throw a C++ exception instead of abort(). */ + + /* assert that nmemb * size <= SIZE_MAX */ + if (size > SIZE_MAX / nmemb) + abort(); + + p = malloc(nmemb * size); + + if (!p) + abort(); + +#if 0 + fprintf(stderr, "%p = malloc(%lu * %lu)\n", p, + (unsigned long) nmemb, (unsigned long) size); +#endif + + return p; +} + + +static void *checked_realloc(void *ptr, size_t nmemb, size_t size) +{ + void *p; + + /* Full manual exception handling is ugly here for performance + * reasons. If an adequate handling of lack of memory is required, + * then use C++ and throw a C++ exception here instead of abort(). */ + + /* assert that nmemb * size <= SIZE_MAX */ + if (size > SIZE_MAX / nmemb) + abort(); + + p = realloc(ptr, nmemb * size); + + if (!p) + abort(); + +#if 0 + fprintf(stderr, "%p = realloc(%p, %lu * %lu)\n", p, ptr, + (unsigned long) nmemb, (unsigned long) size); +#endif + + return p; +} + + +static void checked_free(void *ptr) +{ + free(ptr); + +#if 0 + fprintf(stderr, "free(%p)\n", ptr); +#endif + +} + + + + +/* + * Memory management for buffers which are used for temporarily + * storing SDEs by the encoder. + * + * The following functions manage a set of struct jbg_buf storage + * containers were each can keep JBG_BUFSIZE bytes. The jbg_buf + * containers can be linked to form linear double-chained lists for + * which a number of operations are provided. Blocks which are + * tempoarily not used any more are returned to a freelist which each + * encoder keeps. Only the destructor of the encoder actually returns + * the block via checked_free() to the stdlib memory management. + */ + + +/* + * Allocate a new buffer block and initialize it. Try to get it from + * the free_list, and if it is empty, call checked_malloc(). + */ +static struct jbg_buf *jbg_buf_init(struct jbg_buf **free_list) +{ + struct jbg_buf *new_block; + + /* Test whether a block from the free list is available */ + if (*free_list) { + new_block = *free_list; + *free_list = new_block->next; + } else { + /* request a new memory block */ + new_block = (struct jbg_buf *) checked_malloc(1, sizeof(struct jbg_buf)); + } + new_block->len = 0; + new_block->next = NULL; + new_block->previous = NULL; + new_block->last = new_block; + new_block->free_list = free_list; + + return new_block; +} + + +/* + * Return an entire free_list to the memory management of stdlib. + * This is only done by jbg_enc_free(). + */ +static void jbg_buf_free(struct jbg_buf **free_list) +{ + struct jbg_buf *tmp; + + while (*free_list) { + tmp = (*free_list)->next; + checked_free(*free_list); + *free_list = tmp; + } + + return; +} + + +/* + * Append a single byte to a single list that starts with the block + * *(struct jbg_buf *) head. The type of *head is void here in order to + * keep the interface of the arithmetic encoder gereric, which uses this + * function as a call-back function in order to deliver single bytes + * for a PSCD. + */ +static void jbg_buf_write(int b, void *head) +{ + struct jbg_buf *now; + + now = ((struct jbg_buf *) head)->last; + if (now->len < JBG_BUFSIZE - 1) { + now->d[now->len++] = b; + return; + } + now->next = jbg_buf_init(((struct jbg_buf *) head)->free_list); + now->next->previous = now; + now->next->d[now->next->len++] = b; + ((struct jbg_buf *) head)->last = now->next; + + return; +} + + +/* + * Remove any trailing zero bytes from the end of a linked jbg_buf list, + * however make sure that no zero byte is removed which directly + * follows a 0xff byte (i.e., keep MARKER_ESC MARKER_STUFF sequences + * intact). This function is used to remove any redundant final zero + * bytes from a PSCD. + */ +static void jbg_buf_remove_zeros(struct jbg_buf *head) +{ + struct jbg_buf *last; + + while (1) { + /* remove trailing 0x00 in last block of list until this block is empty */ + last = head->last; + while (last->len && last->d[last->len - 1] == 0) + last->len--; + /* if block became really empty, remove it in case it is not the + * only remaining block and then loop to next block */ + if (last->previous && !last->len) { + head->last->next = *head->free_list; + *head->free_list = head->last; + head->last = last->previous; + head->last->next = NULL; + } else + break; + } + + /* + * If the final non-zero byte is 0xff (MARKER_ESC), then we just have + * removed a MARKER_STUFF and we will append it again now in order + * to preserve PSCD status of byte stream. + */ + if (head->last->len && head->last->d[head->last->len - 1] == MARKER_ESC) + jbg_buf_write(MARKER_STUFF, head); + + return; +} + + +/* + * The jbg_buf list which starts with block *new_prefix is concatenated + * with the list which starts with block **start and *start will then point + * to the first block of the new list. + */ +static void jbg_buf_prefix(struct jbg_buf *new_prefix, struct jbg_buf **start) +{ + new_prefix->last->next = *start; + new_prefix->last->next->previous = new_prefix->last; + new_prefix->last = new_prefix->last->next->last; + *start = new_prefix; + + return; +} + + +/* + * Send the contents of a jbg_buf list that starts with block **head to + * the call back function data_out and return the blocks of the jbg_buf + * list to the freelist from which these jbg_buf blocks have been taken. + * After the call, *head == NULL. + */ +static void jbg_buf_output(struct jbg_buf **head, + void (*data_out)(unsigned char *start, + size_t len, void *file), + void *file) +{ + struct jbg_buf *tmp; + + while (*head) { + data_out((*head)->d, (*head)->len, file); + tmp = (*head)->next; + (*head)->next = *(*head)->free_list; + *(*head)->free_list = *head; + *head = tmp; + } + + return; +} + + +/* + * Calculate y = ceil(x/2) applied n times, which is equivalent to + * y = ceil(x/(2^n)). This function is used to + * determine the number of pixels per row or column after n resolution + * reductions. E.g. X[d-1] = jbg_ceil_half(X[d], 1) and X[0] = + * jbg_ceil_half(X[d], d) as defined in clause 6.2.3 of T.82. + */ +unsigned long jbg_ceil_half(unsigned long x, int n) +{ + unsigned long mask; + + assert(n >= 0 && n < 32); + mask = (1UL << n) - 1; /* the lowest n bits are 1 here */ + return (x >> n) + ((mask & x) != 0); +} + + +/* + * Set L0 (the number of lines in a stripe at lowest resolution) + * to a default value, such that there are about 35 stripes, as + * suggested in Annex C of ITU-T T.82, without exceeding the + * limit 128/2^D suggested in Annex A. + */ +static void jbg_set_default_l0(struct jbg_enc_state *s) +{ + s->l0 = jbg_ceil_half(s->yd, s->d) / 35; /* 35 stripes/image */ + while ((s->l0 << s->d) > 128) /* but <= 128 lines/stripe */ + --s->l0; + if (s->l0 < 2) s->l0 = 2; +} + + +/* + * Calculate the number of stripes, as defined in clause 6.2.3 of T.82. + */ +static unsigned long jbg_stripes(unsigned long l0, unsigned long yd, + unsigned long d) +{ + unsigned long y0 = jbg_ceil_half(yd, d); + + return y0 / l0 + (y0 % l0 != 0); +} + + +/* + * Resolution reduction table given by ITU-T T.82 Table 17 + */ + +static char jbg_resred[4096] = { + 0,0,0,1,0,0,0,1,0,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1, + 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1, + 0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1, + 1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,1,0,1,0,0,1,1,1,0,1,1, + 0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,1,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1, + 1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1, + 0,0,1,1,0,0,0,1,0,0,0,1,0,0,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0,1,1,0,1,1,1,1,1,1,0,1,1,1,0, + 0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1, + 0,0,0,1,0,0,0,1,0,1,1,0,1,0,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1, + 1,1,1,0,1,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1, + 1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,1,1,1,1,1,1, + 0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,1,1,0,1,0,1,1,0,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,1,1,0,0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,1,0,1,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,1,1,1,1,0,1,1, + 1,0,0,1,0,0,1,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0, + 0,0,1,0,1,1,1,1,0,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0, + 0,0,0,0,1,0,0,1,0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,1,1,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,1,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1, + 0,0,1,0,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,1, + 0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,1,0,0,1,0,0,1,1, + 0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,0,1,0,0,0,0,1,0,1,0,1,0,1,0,1, + 0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,1,0,0,0,0,0,0,0,1,1,1,1,0,1,1,1, + 0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,1,0,1,0,1,1,0,0,0,1,0,0,1,1, + 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,1,1,0,0,1,1, + 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1, + 0,0,1,0,0,1,1,1,0,0,0,0,1,0,0,1,0,0,0,1,1,1,1,0,1,0,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,1,1,0, + 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,1,1,1,0,1,1,1, + 0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,1,1,0,1,0,0,0,1,1,0,1,0,0,0,0,1,1,1,1,0,0,1,1,1,0,1,1,0,0,1,1, + 0,0,0,0,0,0,0,0,1,1,0,1,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1, + 0,0,1,1,0,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,1,0,0,0,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1, + 0,0,0,1,0,0,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1, + 0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1, + 0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1, + 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,1,1,0,1,1, + 0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,0,1,0,1,0,1,1,0,1,1,1,0,1,1,1, + 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,1,0,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1, + 0,0,0,0,1,0,0,1,0,0,1,1,0,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1, + 1,0,1,0,1,0,0,1,1,0,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,1,0,1,1,0,1,1,1, + 0,0,1,0,0,0,0,1,0,0,0,0,0,0,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,1,1,0,1,1,0,1,1,1,1, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,1,0,1,0,1,0,1,1,0,1,0,1,0,0,0,1,1,1,1,1,1,1,1,1, + 1,1,1,0,1,0,0,0,1,1,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1, + 1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,1,1,0,1,1, + 0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,0,1,1,0,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,0,1,0,1,0,0,1,0,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,1,0,1,0,0,0,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1, + 1,0,0,0,1,0,0,0,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,1,1,1,0,1,1,0, + 0,0,1,1,1,1,1,1,0,0,0,0,1,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,1,1,0,1,1,1,1,1,1,1, + 0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1, + 0,0,1,0,1,0,1,1,0,0,1,0,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1, + 0,0,1,0,1,0,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,0,1,1,0,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,1, + 0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1, + 0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,0,1,0,0,0,0,1,0,1,0,1,0,1,0,1, + 0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,1,0,0,1,1, + 0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,1, + 0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,1, + 0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,1, + 1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0, + 0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,1, + 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1, + 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1, + 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0,1,0,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,1,1, + 0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,1,1,0,0,0,1,0,1,1,1,0,1,1,1 +}; + +/* + * Deterministic prediction tables given by ITU-T T.82 tables + * 19 to 22. The table below is organized differently, the + * index bits are permutated for higher efficiency. + */ + +static char jbg_dptable[256 + 512 + 2048 + 4096] = { + /* phase 0: offset=0 */ + 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2, + 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,0,2,2,2,2,2,2,2, + 0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,0,2,0,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + /* phase 1: offset=256 */ + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2, + 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,0,2,0,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2, + 0,2,2,2,2,1,2,1,2,2,2,2,1,1,1,1,2,0,2,0,2,2,2,2,0,2,0,2,2,2,2,2, + 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,2,2,2,2,0,2,2,2,2,2,2,2, + 0,2,0,2,2,2,2,2,2,2,2,2,2,0,2,0,2,2,0,0,2,2,2,2,2,0,0,2,2,2,2,2, + 0,2,2,2,2,1,2,1,2,2,2,2,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1, + 1,2,1,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,1,1,2,2,2,2,2,0,2,2,2,2,2,2, + 2,2,2,2,2,0,2,0,2,2,2,2,0,0,0,0,0,2,0,2,2,2,2,2,0,2,2,2,2,2,2,2, + 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,2,2,2,0,2,0,2,2,2,2,2, + 2,2,2,2,2,1,1,1,2,2,2,2,1,1,1,1,1,2,1,2,2,2,2,2,2,2,2,2,2,2,2,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,0,1,2,0,2,0,2,2,2,2,2,0,2,0,2,2,2,2,1, + 0,2,0,2,2,1,2,1,2,2,2,2,1,1,1,1,0,0,0,0,2,2,2,2,0,2,0,2,2,2,2,1, + 2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,0,0,0,2,2,2,2,2, + 2,2,2,2,2,1,2,1,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,1,2,1,2,2,2,2,1, + 2,2,2,2,2,2,2,2,0,2,0,2,2,1,2,2,2,2,2,2,2,2,2,2,0,0,0,2,2,2,2,2, + /* phase 2: offset=768 */ + 2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,2,2,2,2,1,1,1,1, + 0,2,2,2,2,1,2,1,2,2,2,2,1,2,1,2,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1, + 2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,1,2,1,2,2,2,2,2,1,1,1, + 2,0,2,2,2,1,2,1,0,2,2,2,1,2,1,2,2,2,2,0,2,2,2,2,0,2,0,2,2,2,2,2, + 0,2,0,0,1,1,1,1,2,2,2,2,1,1,1,1,0,2,0,2,1,1,1,1,2,2,2,2,1,1,1,1, + 2,2,0,2,2,2,1,2,2,2,2,2,1,2,1,2,2,2,0,2,2,1,2,1,0,2,0,2,1,1,1,1, + 2,0,0,2,2,2,2,2,0,2,0,2,2,0,2,0,2,0,2,0,2,2,2,1,2,2,0,2,1,1,2,1, + 2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,2,2,2,2,1,1,1,1, + 0,0,0,0,2,2,2,2,0,0,0,0,2,2,2,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,0,2,2,2,2,1,0,2,2,2,1,1,1,1,2,0,2,2,2,2,2,2,0,2,0,2,2,1,2,1, + 2,0,2,0,2,2,2,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2, + 0,2,2,2,1,2,1,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2, + 2,2,0,2,2,2,2,2,2,2,2,2,2,2,0,2,2,0,0,2,2,1,2,1,0,2,2,2,1,1,1,1, + 2,2,2,0,2,2,2,2,2,2,0,2,2,0,2,0,2,1,2,2,2,2,2,2,1,2,1,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,2,2,1, + 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,1,1,1,2,2,2,2,1,1,1,1, + 2,2,2,1,2,2,2,2,2,2,1,2,0,0,0,0,2,2,0,2,2,1,2,2,2,2,2,2,1,1,1,1, + 2,0,0,0,2,2,2,2,0,2,2,2,2,2,2,0,2,2,2,0,2,2,2,2,2,0,0,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,0,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,1, + 0,2,0,2,2,1,1,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2, + 2,0,2,0,2,1,2,1,0,2,0,2,2,2,1,2,2,0,2,0,2,2,2,2,0,2,0,2,2,2,1,2, + 2,2,2,0,2,2,2,2,2,2,0,2,2,2,2,2,2,2,1,2,2,2,2,2,2,0,1,2,2,2,2,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, + 0,2,2,2,1,2,1,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2, + 2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,1,2,1,0,2,2,2,1,1,1,1, + 2,0,2,0,2,1,2,2,0,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,1,2,2, + 2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,0,2,2,2,2,0,0,0,0,2,1,2,1, + 2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,0,0,2,2,2,1,2,2,2, + 0,0,2,0,2,2,2,2,0,2,0,2,2,0,2,0,1,1,1,2,2,2,2,2,2,2,2,2,2,1,1,1, + 2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,0,2,0,2,2,2,1, + 2,2,0,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,2,2,2,2,1,1,1,1, + 0,2,2,2,1,2,1,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2, + 2,0,0,2,2,2,2,2,0,2,0,2,2,2,2,2,1,0,1,2,2,2,2,1,0,2,2,2,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,0,2,2,0,2,0,2,1,2,2,2,2,2,2,2,2,0,2,2,1,2,2, + 0,2,0,0,1,1,1,1,0,2,2,2,1,1,1,1,2,2,2,2,2,2,2,2,2,0,2,2,1,2,1,1, + 2,2,0,2,2,1,2,2,2,2,2,2,1,2,2,2,2,0,2,2,2,2,2,2,0,2,0,2,1,2,1,1, + 2,0,2,0,2,2,2,2,0,2,0,2,2,1,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,1, + 2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, + 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 0,2,2,2,2,0,2,0,2,2,2,2,0,0,0,0,2,2,2,2,2,1,1,2,2,2,2,2,1,2,2,2, + 2,0,2,2,2,1,2,1,0,2,2,2,2,2,1,2,2,0,2,0,2,2,2,2,0,2,0,2,2,1,2,2, + 0,2,0,0,2,2,2,2,1,2,2,2,2,2,2,0,2,1,2,2,2,2,2,2,1,2,2,2,2,2,2,2, + 0,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,1,0,2,2, + 0,0,0,2,2,1,1,1,2,2,2,2,1,2,2,2,2,0,2,0,2,2,2,1,2,2,2,2,1,2,1,2, + 0,0,0,0,2,2,2,2,2,2,0,2,2,1,2,2,2,1,2,1,2,2,2,2,1,2,1,2,0,2,2,2, + 2,0,2,0,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, + 0,2,2,2,1,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,1,2,2,2,2,2,0,2,2,1,2,2,0,0,0,2,2,2,2,2,1,2,2,0,2,2,2,1,2,1,2, + 2,0,2,0,2,2,2,2,0,2,0,2,2,1,2,2,0,2,0,0,2,2,2,2,2,2,2,2,2,1,2,2, + 2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,0,2,0,2,2,2,1, + 1,2,0,2,2,1,2,1,2,2,2,2,1,2,2,2,2,0,2,0,2,2,2,2,2,0,2,2,1,1,1,1, + 0,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,2,1,2,1, + 2,2,0,0,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1, + 2,2,2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,1,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2, + 2,0,2,0,2,2,2,2,2,1,1,2,2,2,2,2,2,2,2,2,2,2,2,1,0,2,0,2,2,2,1,2, + 2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2, + 2,0,2,0,2,2,2,2,2,0,2,0,2,2,2,2,2,0,2,0,2,2,2,2,0,0,0,0,2,1,2,1, + 2,2,2,2,2,1,2,1,0,2,0,2,2,2,2,2,2,0,2,0,2,2,2,2,0,2,0,2,2,2,2,1, + 2,0,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,0, + 2,0,2,0,2,2,2,1,2,2,2,0,2,2,2,1,2,0,2,0,2,2,2,2,0,0,0,2,2,2,2,1, + 2,0,2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2, + /* phase 3: offset=2816 */ + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1, + 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,1,2,1,2,0,2,0,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,0,2,2,2,1,2,0,2,2,2,1,2,2,2,2,0,2,0,2,1,2,1,0,0,0,0,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,0,2,2,2,1,2, + 2,2,2,1,2,2,2,0,1,1,1,1,0,0,0,0,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,0,0,0,0,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1,0,0,0,0,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,2, + 2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1,2,0,2,0,2,1,2,1, + 2,0,0,0,2,1,1,1,0,0,0,0,1,1,1,1,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2, + 2,0,2,2,2,1,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,0,0,2,0,1,1,2,1, + 2,2,2,0,2,2,2,1,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1, + 0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,2,0,2,0,2,1,2,1,0,0,0,0,1,1,1,1, + 2,0,0,2,2,1,1,2,2,2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,2,1,1,1,2,0,0,0, + 2,1,2,1,2,0,2,0,1,2,1,2,0,2,0,2,2,2,2,0,2,2,2,1,2,0,2,0,2,1,2,1, + 2,0,2,0,2,1,2,1,0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1, + 2,2,2,2,2,2,2,2,2,0,0,0,2,1,1,1,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2, + 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2, + 2,0,0,0,2,1,1,1,0,0,0,0,1,1,1,1,2,0,2,0,2,1,2,1,0,0,2,0,1,1,2,1, + 2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,0,0,0,2,1,1,1, + 2,2,2,1,2,2,2,0,2,1,1,1,2,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,1,2,1,2,0,2,0,2, + 2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, + 2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,2,1,1,1,0,0,0,0,1,1,1,1, + 2,0,2,2,2,1,2,2,0,0,2,0,1,1,2,1,2,1,2,1,2,0,2,0,2,2,2,2,2,2,2,2, + 2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,0,0,0,0,1,1,1,1, + 2,0,0,0,2,1,1,1,0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,2,1,0,2,2,0,1,2, + 2,2,2,1,2,2,2,0,2,1,1,1,2,0,0,0,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, + 2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, + 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2, + 2,1,2,1,2,0,2,0,1,2,1,1,0,2,0,0,0,0,2,1,1,1,2,0,0,0,0,0,1,1,1,1, + 2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,0,2,1,2,1,2,0,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,0,2,2,2,1,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,0,2,2,2,1,2,2,2,0,0,2,2,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2, + 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2, + 2,0,2,0,2,1,2,1,0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,0,0,0,0,1,1,1,1, + 2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,0,0,0,2,1,1,1, + 2,2,2,0,2,2,2,1,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2, + 2,0,2,2,2,1,2,2,2,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, + 2,1,2,1,2,0,2,0,1,2,1,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,1,2,1,2,0,2,0,1,2,1,1,0,2,0,0,2,0,2,2,2,1,2,2,0,2,1,2,1,2,0,2, + 2,2,2,1,2,2,2,0,2,2,1,2,2,2,0,2,2,1,2,2,2,0,2,2,2,2,0,2,2,2,1,2, + 0,0,2,0,1,1,2,1,0,0,1,0,1,1,0,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,0,2,2,2,1,1,2,2,2,0,2,2,2,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1, + 2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, + 2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,0,0,2,2,1,1,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2, + 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2, + 2,0,0,0,2,1,1,1,0,0,0,0,1,1,1,1,2,2,2,1,2,2,2,0,2,1,2,1,2,0,2,0, + 2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2,0,2,0,0,1,2,1,1,2,0,0,0,2,1,1,1, + 2,2,2,2,2,2,2,2,2,1,1,1,2,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,0,2,2,2,1,2,2,0,2,2,2,1,2,2,1,2,1,2,0,2,0,2,0,2,2,2,1,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,1,1,1,2,0,0,0, + 2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,0,0,1,2,1,1, + 2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,0,2,2,2,1,2,2,2, + 2,1,2,1,2,0,2,0,2,1,2,2,2,0,2,2,2,2,2,0,2,2,2,1,2,0,2,0,2,1,2,1, + 2,0,2,0,2,1,2,1,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2, + 2,2,2,2,2,2,2,2,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,0,1,0,0,1,0,1,1, + 2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,1,2,2,1,0,2,0,2,2,2,1,2,2,2, + 2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,0,2,2,2,1,2,2,0,2,2,2,1,2, + 2,0,2,0,2,1,2,1,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2, + 0,2,0,0,1,2,1,1,2,0,0,0,2,1,1,1,2,2,2,2,2,2,2,2,1,0,1,2,0,1,0,2, + 2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,1,2,2,2,0,2,2,1,1,2,2,0,0,2,2, + 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,1,2,1,2,0,2,0,2,1,2,2,2,0,2,2,2,0,2,2,2,1,2,2,0,2,2,2,1,2,2,2, + 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,1,2,2,2,0,2,2,2, + 2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1,2, + 0,0,0,0,1,1,1,1,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,2,2,0,2,2,2,1,2, + 2,0,2,0,2,1,2,1,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2, + 0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,1,2,2,2,0,1,1,2,1,0,0,2,0,2,0,2,2,2,1,2,2,0,2,2,2,1,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,0,2,2,2,1,2, + 2,0,2,0,2,1,2,1,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2, + 0,2,0,0,1,2,1,1,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,0,0,0,2,1,1,1,2, + 2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, + 2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,0,0,2,1,1,1,2,0,0,2,2,2,1,2,2,2, + 2,1,2,1,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,0,1,2,1,1, + 0,0,2,2,1,1,2,2,0,2,1,2,1,2,0,2,2,1,2,1,2,0,2,0,1,2,1,2,0,2,0,2, + 2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,2,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1, + 2,2,0,0,2,2,1,1,2,2,0,0,2,2,1,1,2,2,2,2,2,2,2,2,2,2,0,0,2,2,1,1, + 2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,0,0,1,2,1,1, + 2,2,2,0,2,2,2,1,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,1,1,1,2,0,0,0,2, + 2,2,2,2,2,2,2,2,1,1,1,2,0,0,0,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2, + 2,0,2,0,2,1,2,1,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,0,0,0,2,1,1,1, + 2,0,2,2,2,1,2,2,0,2,2,2,1,2,2,2,2,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2, + 2,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,0,2,0,2,1,2,1,2,1,2,0,2,0,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,0,2,0,2,1,2,1,1,2,1,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,2,2,1,2,1,2,0,2,0,2,2,2,2,2,2,2,2, + 2,0,2,1,2,1,2,0,0,2,1,2,1,2,0,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, + 2,0,2,0,2,1,2,1,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1, + 2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,1,2,1,2,0,2,0,1,1,1,2,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1, + 2,0,2,0,2,1,2,1,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +}; + + +/* + * Initialize the status struct for the encoder. + */ +void jbg_enc_init(struct jbg_enc_state *s, unsigned long x, unsigned long y, + int planes, unsigned char **p, + void (*data_out)(unsigned char *start, size_t len, + void *file), + void *file) +{ + unsigned long l, lx; + int i; + + assert(x > 0 && y > 0 && planes > 0 && planes < 256); + s->xd = x; + s->yd = y; + s->yd1 = y; /* This is the hight initially announced in BIH. To provoke + generation of NEWLEN for T.85 compatibility tests, + overwrite with new value s->yd1 > s->yd */ + s->planes = planes; + s->data_out = data_out; + s->file = file; + + s->d = 0; + s->dl = 0; + s->dh = s->d; + jbg_set_default_l0(s); + s->mx = 8; + s->my = 0; + s->order = JBG_ILEAVE | JBG_SMID; + s->options = JBG_TPBON | JBG_TPDON | JBG_DPON; + s->comment = NULL; + s->dppriv = jbg_dptable; + s->res_tab = jbg_resred; + + s->highres = (int *) checked_malloc(planes, sizeof(int)); + s->lhp[0] = p; + s->lhp[1] = (unsigned char **) + checked_malloc(planes, sizeof(unsigned char *)); + for (i = 0; i < planes; i++) { + s->highres[i] = 0; + s->lhp[1][i] = (unsigned char *) + checked_malloc(jbg_ceil_half(y, 1), jbg_ceil_half(x, 1+3)); + } + + s->free_list = NULL; + s->s = (struct jbg_arenc_state *) + checked_malloc(s->planes, sizeof(struct jbg_arenc_state)); + s->tx = (int *) checked_malloc(s->planes, sizeof(int)); + lx = jbg_ceil_half(x, 1); + s->tp = (char *) checked_malloc(lx, sizeof(char)); + for (l = 0; l < lx; s->tp[l++] = 2) ; + s->sde = NULL; + + return; +} + + +/* + * This function selects the number of differential layers based on + * the maximum size requested for the lowest resolution layer. If + * possible, a number of differential layers is selected, which will + * keep the size of the lowest resolution layer below or equal to the + * given width x and height y. However not more than 6 differential + * resolution layers will be used. In addition, a reasonable value for + * l0 (height of one stripe in the lowest resolution layer) is + * selected, which obeys the recommended limitations for l0 in annex A + * and C of the JBIG standard. The selected number of resolution layers + * is returned. + */ +int jbg_enc_lrlmax(struct jbg_enc_state *s, unsigned long x, + unsigned long y) +{ + for (s->d = 0; s->d < 6; s->d++) + if (jbg_ceil_half(s->xd, s->d) <= x && jbg_ceil_half(s->yd, s->d) <= y) + break; + s->dl = 0; + s->dh = s->d; + jbg_set_default_l0(s); + return s->d; +} + + +/* + * As an alternative to jbg_enc_lrlmax(), the following function allows + * to specify the number of layers directly. The stripe height and layer + * range is also adjusted automatically here. + */ +void jbg_enc_layers(struct jbg_enc_state *s, int d) +{ + if (d < 0 || d > 31) + return; + s->d = d; + s->dl = 0; + s->dh = s->d; + jbg_set_default_l0(s); + return; +} + + +/* + * Specify the highest and lowest resolution layers which will be + * written to the output file. Call this function not before + * jbg_enc_layers() or jbg_enc_lrlmax(), because these two functions + * reset the lowest and highest resolution layer to default values. + * Negative values are ignored. The total number of layers is returned. + */ +int jbg_enc_lrange(struct jbg_enc_state *s, int dl, int dh) +{ + if (dl >= 0 && dl <= s->d) s->dl = dl; + if (dh >= s->dl && dh <= s->d) s->dh = dh; + + return s->d; +} + + +/* + * The following function allows to specify the bits describing the + * options of the format as well as the maximum AT movement window and + * the number of layer 0 lines per stripes. + */ +void jbg_enc_options(struct jbg_enc_state *s, int order, int options, + unsigned long l0, int mx, int my) +{ + if (order >= 0 && order <= 0x0f) s->order = order; + if (options >= 0) s->options = options; + if (l0 > 0) s->l0 = l0; + if (mx >= 0 && my < 128) s->mx = mx; + if (my >= 0 && my < 256) s->my = my; + + return; +} + + +/* + * This function actually does all the tricky work involved in producing + * a SDE, which is stored in the appropriate s->sde[][][] element + * for later output in the correct order. + */ +static void encode_sde(struct jbg_enc_state *s, + long stripe, int layer, int plane) +{ + unsigned char *hp, *lp1, *lp2, *p0, *p1, *q1, *q2; + unsigned long hl, ll, hx, hy, lx, ly, hbpl, lbpl; + unsigned long line_h0 = 0, line_h1 = 0; + unsigned long line_h2, line_h3, line_l1, line_l2, line_l3; + struct jbg_arenc_state *se; + unsigned long y; /* current line number in highres image */ + unsigned long i; /* current line number within highres stripe */ + unsigned long j; /* current column number in highres image */ + long o; + unsigned a, p, t; + int ltp, ltp_old, cx; + unsigned long c_all, c[MX_MAX + 1], cmin, cmax, clmin, clmax; + int tmax, at_determined; + int new_tx; + long new_tx_line = -1; + int reset; + struct jbg_buf *new_jbg_buf; + +#ifdef DEBUG + static long tp_lines, tp_exceptions, tp_pixels, dp_pixels; + static long encoded_pixels; +#endif + + /* return immediately if this stripe has already been encoded */ + if (s->sde[stripe][layer][plane] != SDE_TODO) + return; + +#ifdef DEBUG + if (stripe == 0) + tp_lines = tp_exceptions = tp_pixels = dp_pixels = encoded_pixels = 0; + fprintf(stderr, "encode_sde: s/d/p = %2ld/%2d/%2d\n", + stripe, layer, plane); +#endif + + /* number of lines per stripe in highres image */ + hl = s->l0 << layer; + /* number of lines per stripe in lowres image */ + ll = hl >> 1; + /* current line number in highres image */ + y = stripe * hl; + /* number of pixels in highres image */ + hx = jbg_ceil_half(s->xd, s->d - layer); + hy = jbg_ceil_half(s->yd, s->d - layer); + /* number of pixels in lowres image */ + lx = jbg_ceil_half(hx, 1); + ly = jbg_ceil_half(hy, 1); + /* bytes per line in highres and lowres image */ + hbpl = jbg_ceil_half(hx, 3); + lbpl = jbg_ceil_half(lx, 3); + /* pointer to first image byte of highres stripe */ + hp = s->lhp[s->highres[plane]][plane] + stripe * hl * hbpl; + lp2 = s->lhp[1 - s->highres[plane]][plane] + stripe * ll * lbpl; + lp1 = lp2 + lbpl; + + /* check whether we can refer to any state of a previous stripe */ + reset = (stripe == 0) || (s->options & JBG_SDRST); + + /* initialize arithmetic encoder */ + se = s->s + plane; + arith_encode_init(se, !reset); + s->sde[stripe][layer][plane] = jbg_buf_init(&s->free_list); + se->byte_out = jbg_buf_write; + se->file = s->sde[stripe][layer][plane]; + + /* initialize adaptive template movement algorithm */ + c_all = 0; + for (t = 0; t <= s->mx; t++) + c[t] = 0; + if (stripe == 0) /* the SDRST case is handled at the end */ + s->tx[plane] = 0; + new_tx = -1; + at_determined = 0; /* we haven't yet decided the template move */ + if (s->mx == 0) + at_determined = 1; + + /* initialize typical prediction */ + ltp = 0; + if (reset) + ltp_old = 0; + else { + ltp_old = 1; + p1 = hp - hbpl; + if (y > 1) { + q1 = p1 - hbpl; + while (p1 < hp && (ltp_old = (*p1++ == *q1++)) != 0) ; + } else + while (p1 < hp && (ltp_old = (*p1++ == 0)) != 0) ; + } + + if (layer == 0) { + + /* + * Encode lowest resolution layer + */ + + for (i = 0; i < hl && y < hy; i++, y++) { + + /* check whether it is worth to perform an ATMOVE */ + if (!at_determined && c_all > 2048) { + cmin = clmin = 0xffffffffL; + cmax = clmax = 0; + tmax = 0; + for (t = (s->options & JBG_LRLTWO) ? 5 : 3; t <= s->mx; t++) { + if (c[t] > cmax) cmax = c[t]; + if (c[t] < cmin) cmin = c[t]; + if (c[t] > c[tmax]) tmax = t; + } + clmin = (c[0] < cmin) ? c[0] : cmin; + clmax = (c[0] > cmax) ? c[0] : cmax; + if (c_all - cmax < (c_all >> 3) && + cmax - c[s->tx[plane]] > c_all - cmax && + cmax - c[s->tx[plane]] > (c_all >> 4) && + /* ^ T.82 said < here, fixed in Cor.1/25 */ + cmax - (c_all - c[s->tx[plane]]) > c_all - cmax && + cmax - (c_all - c[s->tx[plane]]) > (c_all >> 4) && + cmax - cmin > (c_all >> 2) && + (s->tx[plane] || clmax - clmin > (c_all >> 3))) { + /* we have decided to perform an ATMOVE */ + new_tx = tmax; + if (!(s->options & JBG_DELAY_AT)) { + new_tx_line = i; + s->tx[plane] = new_tx; + } +#ifdef DEBUG + fprintf(stderr, "ATMOVE: line=%ld, tx=%d, c_all=%ld\n", + i, new_tx, c_all); +#endif + } + at_determined = 1; + } + assert(s->tx[plane] >= 0); /* i.e., tx can safely be cast to unsigned */ + + /* typical prediction */ + if (s->options & JBG_TPBON) { + ltp = 1; + p1 = hp; + if (i > 0 || !reset) { + q1 = hp - hbpl; + while (q1 < hp && (ltp = (*p1++ == *q1++)) != 0) ; + } else + while (p1 < hp + hbpl && (ltp = (*p1++ == 0)) != 0) ; + arith_encode(se, (s->options & JBG_LRLTWO) ? TPB2CX : TPB3CX, + ltp == ltp_old); +#ifdef DEBUG + tp_lines += ltp; +#endif + ltp_old = ltp; + if (ltp) { + /* skip next line */ + hp += hbpl; + continue; + } + } + + /* + * Layout of the variables line_h1, line_h2, line_h3, which contain + * as bits the neighbour pixels of the currently coded pixel X: + * + * 76543210765432107654321076543210 line_h3 + * 76543210765432107654321076543210 line_h2 + * 76543210765432107654321X76543210 line_h1 + */ + + line_h1 = line_h2 = line_h3 = 0; + if (i > 0 || !reset) line_h2 = (long)*(hp - hbpl) << 8; + if (i > 1 || !reset) line_h3 = (long)*(hp - hbpl - hbpl) << 8; + + /* encode line */ + for (j = 0; j < hx; hp++) { + line_h1 |= *hp; + if (j < hbpl * 8 - 8 && (i > 0 || !reset)) { + line_h2 |= *(hp - hbpl + 1); + if (i > 1 || !reset) + line_h3 |= *(hp - hbpl - hbpl + 1); + } + if (s->options & JBG_LRLTWO) { + /* two line template */ + do { + line_h1 <<= 1; line_h2 <<= 1; line_h3 <<= 1; + if (s->tx[plane]) { + if ((unsigned) s->tx[plane] > j) + a = 0; + else { + o = (j - s->tx[plane]) - (j & ~7L); + a = (hp[o >> 3] >> (7 - (o & 7))) & 1; + a <<= 4; + } + assert(s->tx[plane] > 23 || + a == ((line_h1 >> (4 + s->tx[plane])) & 0x010)); + arith_encode(se, (((line_h2 >> 10) & 0x3e0) | a | + ((line_h1 >> 9) & 0x00f)), + (line_h1 >> 8) & 1); + } + else + arith_encode(se, (((line_h2 >> 10) & 0x3f0) | + ((line_h1 >> 9) & 0x00f)), + (line_h1 >> 8) & 1); +#ifdef DEBUG + encoded_pixels++; +#endif + /* statistics for adaptive template changes */ + if (!at_determined && j >= s->mx && j < hx-2) { + p = (line_h1 & 0x100) != 0; /* current pixel value */ + c[0] += ((line_h2 & 0x4000) != 0) == p; /* default position */ + assert(!(((line_h2 >> 6) ^ line_h1) & 0x100) == + (((line_h2 & 0x4000) != 0) == p)); + for (t = 5; t <= s->mx && t <= j; t++) { + o = (j - t) - (j & ~7L); + a = (hp[o >> 3] >> (7 - (o & 7))) & 1; + assert(t > 23 || + (a == p) == !(((line_h1 >> t) ^ line_h1) & 0x100)); + c[t] += a == p; + } + for (; t <= s->mx; t++) { + c[t] += 0 == p; + } + ++c_all; + } + } while (++j & 7 && j < hx); + } else { + /* three line template */ + do { + line_h1 <<= 1; line_h2 <<= 1; line_h3 <<= 1; + if (s->tx[plane]) { + if ((unsigned) s->tx[plane] > j) + a = 0; + else { + o = (j - s->tx[plane]) - (j & ~7L); + a = (hp[o >> 3] >> (7 - (o & 7))) & 1; + a <<= 2; + } + assert(s->tx[plane] > 23 || + a == ((line_h1 >> (6 + s->tx[plane])) & 0x004)); + arith_encode(se, (((line_h3 >> 8) & 0x380) | + ((line_h2 >> 12) & 0x078) | a | + ((line_h1 >> 9) & 0x003)), + (line_h1 >> 8) & 1); + } else + arith_encode(se, (((line_h3 >> 8) & 0x380) | + ((line_h2 >> 12) & 0x07c) | + ((line_h1 >> 9) & 0x003)), + (line_h1 >> 8) & 1); +#ifdef DEBUG + encoded_pixels++; +#endif + /* statistics for adaptive template changes */ + if (!at_determined && j >= s->mx && j < hx-2) { + p = (line_h1 & 0x100) != 0; /* current pixel value */ + c[0] += ((line_h2 & 0x4000) != 0) == p; /* default position */ + assert(!(((line_h2 >> 6) ^ line_h1) & 0x100) == + (((line_h2 & 0x4000) != 0) == p)); + for (t = 3; t <= s->mx && t <= j; t++) { + o = (j - t) - (j & ~7L); + a = (hp[o >> 3] >> (7 - (o & 7))) & 1; + assert(t > 23 || + (a == p) == !(((line_h1 >> t) ^ line_h1) & 0x100)); + c[t] += a == p; + } + for (; t <= s->mx; t++) { + c[t] += 0 == p; + } + ++c_all; + } + } while (++j & 7 && j < hx); + } /* if (s->options & JBG_LRLTWO) */ + } /* for (j = ...) */ + } /* for (i = ...) */ + + } else { + + /* + * Encode differential layer + */ + + for (i = 0; i < hl && y < hy; i++, y++) { + + /* check whether it is worth to perform an ATMOVE */ + if (!at_determined && c_all > 2048) { + cmin = clmin = 0xffffffffL; + cmax = clmax = 0; + tmax = 0; + for (t = 3; t <= s->mx; t++) { + if (c[t] > cmax) cmax = c[t]; + if (c[t] < cmin) cmin = c[t]; + if (c[t] > c[tmax]) tmax = t; + } + clmin = (c[0] < cmin) ? c[0] : cmin; + clmax = (c[0] > cmax) ? c[0] : cmax; + if (c_all - cmax < (c_all >> 3) && + cmax - c[s->tx[plane]] > c_all - cmax && + cmax - c[s->tx[plane]] > (c_all >> 4) && + /* ^ T.82 said < here, fixed in Cor.1/25 */ + cmax - (c_all - c[s->tx[plane]]) > c_all - cmax && + cmax - (c_all - c[s->tx[plane]]) > (c_all >> 4) && + cmax - cmin > (c_all >> 2) && + (s->tx[plane] || clmax - clmin > (c_all >> 3))) { + /* we have decided to perform an ATMOVE */ + new_tx = tmax; + if (!(s->options & JBG_DELAY_AT)) { + new_tx_line = i; + s->tx[plane] = new_tx; + } +#ifdef DEBUG + fprintf(stderr, "ATMOVE: line=%ld, tx=%d, c_all=%ld\n", + i, new_tx, c_all); +#endif + } + at_determined = 1; + } + + if ((i >> 1) >= ll - 1 || (y >> 1) >= ly - 1) + lp1 = lp2; + + /* typical prediction */ + if (s->options & JBG_TPDON && (i & 1) == 0) { + q1 = lp1; q2 = lp2; + p0 = p1 = hp; + if (i < hl - 1 && y < hy - 1) + p0 = hp + hbpl; + if (i > 1 || !reset) + line_l3 = (long)*(q2 - lbpl) << 8; + else + line_l3 = 0; + line_l2 = (long)*q2 << 8; + line_l1 = (long)*q1 << 8; + ltp = 1; + for (j = 0; j < lx && ltp; q1++, q2++) { + if (j < lbpl * 8 - 8) { + if (i > 1 || !reset) + line_l3 |= *(q2 - lbpl + 1); + line_l2 |= *(q2 + 1); + line_l1 |= *(q1 + 1); + } + do { + if ((j >> 2) < hbpl) { + line_h1 = *(p1++); + line_h0 = *(p0++); + } + do { + line_l3 <<= 1; + line_l2 <<= 1; + line_l1 <<= 1; + line_h1 <<= 2; + line_h0 <<= 2; + cx = (((line_l3 >> 15) & 0x007) | + ((line_l2 >> 12) & 0x038) | + ((line_l1 >> 9) & 0x1c0)); + if (cx == 0x000) + if ((line_h1 & 0x300) == 0 && (line_h0 & 0x300) == 0) + s->tp[j] = 0; + else { + ltp = 0; +#ifdef DEBUG + tp_exceptions++; +#endif + } + else if (cx == 0x1ff) + if ((line_h1 & 0x300) == 0x300 && (line_h0 & 0x300) == 0x300) + s->tp[j] = 1; + else { + ltp = 0; +#ifdef DEBUG + tp_exceptions++; +#endif + } + else + s->tp[j] = 2; + } while (++j & 3 && j < lx); + } while (j & 7 && j < lx); + } /* for (j = ...) */ + arith_encode(se, TPDCX, !ltp); +#ifdef DEBUG + tp_lines += ltp; +#endif + } + + + /* + * Layout of the variables line_h1, line_h2, line_h3, which contain + * as bits the high resolution neighbour pixels of the currently coded + * highres pixel X: + * + * 76543210 76543210 76543210 76543210 line_h3 + * 76543210 76543210 76543210 76543210 line_h2 + * 76543210 76543210 7654321X 76543210 line_h1 + * + * Layout of the variables line_l1, line_l2, line_l3, which contain + * the low resolution pixels near the currently coded pixel as bits. + * The lowres pixel in which the currently coded highres pixel is + * located is marked as Y: + * + * 76543210 76543210 76543210 76543210 line_l3 + * 76543210 7654321Y 76543210 76543210 line_l2 + * 76543210 76543210 76543210 76543210 line_l1 + */ + + + line_h1 = line_h2 = line_h3 = line_l1 = line_l2 = line_l3 = 0; + if (i > 0 || !reset) line_h2 = (long)*(hp - hbpl) << 8; + if (i > 1 || !reset) { + line_h3 = (long)*(hp - hbpl - hbpl) << 8; + line_l3 = (long)*(lp2 - lbpl) << 8; + } + line_l2 = (long)*lp2 << 8; + line_l1 = (long)*lp1 << 8; + + /* encode line */ + for (j = 0; j < hx; lp1++, lp2++) { + if ((j >> 1) < lbpl * 8 - 8) { + if (i > 1 || !reset) + line_l3 |= *(lp2 - lbpl + 1); + line_l2 |= *(lp2 + 1); + line_l1 |= *(lp1 + 1); + } + do { /* ... while (j & 15 && j < hx) */ + + assert(hp - (s->lhp[s->highres[plane]][plane] + + (stripe * hl + i) * hbpl) + == (ptrdiff_t) j >> 3); + + assert(lp2 - (s->lhp[1-s->highres[plane]][plane] + + (stripe * ll + (i>>1)) * lbpl) + == (ptrdiff_t) j >> 4); + + line_h1 |= *hp; + if (j < hbpl * 8 - 8) { + if (i > 0 || !reset) { + line_h2 |= *(hp - hbpl + 1); + if (i > 1 || !reset) + line_h3 |= *(hp - hbpl - hbpl + 1); + } + } + do { /* ... while (j & 7 && j < hx) */ + line_l1 <<= 1; line_l2 <<= 1; line_l3 <<= 1; + if (ltp && s->tp[j >> 1] < 2) { + /* pixel are typical and have not to be encoded */ + line_h1 <<= 2; line_h2 <<= 2; line_h3 <<= 2; +#ifdef DEBUG + do { + ++tp_pixels; + } while (++j & 1 && j < hx); +#else + j += 2; +#endif + } else + do { /* ... while (++j & 1 && j < hx) */ + line_h1 <<= 1; line_h2 <<= 1; line_h3 <<= 1; + + /* deterministic prediction */ + if (s->options & JBG_DPON) { + if ((y & 1) == 0) { + if ((j & 1) == 0) { + /* phase 0 */ + if (s->dppriv[((line_l3 >> 16) & 0x003) | + ((line_l2 >> 14) & 0x00c) | + ((line_h1 >> 5) & 0x010) | + ((line_h2 >> 10) & 0x0e0)] < 2) { +#ifdef DEBUG + ++dp_pixels; +#endif + continue; + } + } else { + /* phase 1 */ + if (s->dppriv[(((line_l3 >> 16) & 0x003) | + ((line_l2 >> 14) & 0x00c) | + ((line_h1 >> 5) & 0x030) | + ((line_h2 >> 10) & 0x1c0)) + 256] < 2) { +#ifdef DEBUG + ++dp_pixels; +#endif + continue; + } + } + } else { + if ((j & 1) == 0) { + /* phase 2 */ + if (s->dppriv[(((line_l3 >> 16) & 0x003) | + ((line_l2 >> 14) & 0x00c) | + ((line_h1 >> 5) & 0x010) | + ((line_h2 >> 10) & 0x0e0) | + ((line_h3 >> 7) & 0x700)) + 768] < 2) { +#ifdef DEBUG + ++dp_pixels; +#endif + continue; + } + } else { + /* phase 3 */ + if (s->dppriv[(((line_l3 >> 16) & 0x003) | + ((line_l2 >> 14) & 0x00c) | + ((line_h1 >> 5) & 0x030) | + ((line_h2 >> 10) & 0x1c0) | + ((line_h3 >> 7) & 0xe00)) + 2816] < 2) { +#ifdef DEBUG + ++dp_pixels; +#endif + continue; + } + } + } + } + + /* determine context */ + if (s->tx[plane]) { + if ((unsigned) s->tx[plane] > j) + a = 0; + else { + o = (j - s->tx[plane]) - (j & ~7L); + a = (hp[o >> 3] >> (7 - (o & 7))) & 1; + a <<= 4; + } + assert(s->tx[plane] > 23 || + a == ((line_h1 >> (4 + s->tx[plane])) & 0x010)); + cx = (((line_h1 >> 9) & 0x003) | a | + ((line_h2 >> 13) & 0x00c) | + ((line_h3 >> 11) & 0x020)); + } else + cx = (((line_h1 >> 9) & 0x003) | + ((line_h2 >> 13) & 0x01c) | + ((line_h3 >> 11) & 0x020)); + if (j & 1) + cx |= (((line_l2 >> 9) & 0x0c0) | + ((line_l1 >> 7) & 0x300)) | (1UL << 10); + else + cx |= (((line_l2 >> 10) & 0x0c0) | + ((line_l1 >> 8) & 0x300)); + cx |= (y & 1) << 11; + + arith_encode(se, cx, (line_h1 >> 8) & 1); +#ifdef DEBUG + encoded_pixels++; +#endif + + /* statistics for adaptive template changes */ + if (!at_determined && j >= s->mx) { + c[0] += !(((line_h2 >> 6) ^ line_h1) & 0x100); + for (t = 3; t <= s->mx; t++) + c[t] += !(((line_h1 >> t) ^ line_h1) & 0x100); + ++c_all; + } + + } while (++j & 1 && j < hx); + } while (j & 7 && j < hx); + hp++; + } while (j & 15 && j < hx); + } /* for (j = ...) */ + + /* low resolution pixels are used twice */ + if ((i & 1) == 0) { + lp1 -= lbpl; + lp2 -= lbpl; + } + + } /* for (i = ...) */ + } + + arith_encode_flush(se); + jbg_buf_remove_zeros(s->sde[stripe][layer][plane]); + jbg_buf_write(MARKER_ESC, s->sde[stripe][layer][plane]); + jbg_buf_write((s->options & JBG_SDRST) ? MARKER_SDRST : MARKER_SDNORM, + s->sde[stripe][layer][plane]); + if (s->options & JBG_SDRST) + s->tx[plane] = 0; + + /* add ATMOVE */ + if (new_tx != -1) { + if (s->options & JBG_DELAY_AT) { + /* ATMOVE will become active at the first line of the next stripe */ + s->tx[plane] = new_tx; + jbg_buf_write(MARKER_ESC, s->sde[stripe][layer][plane]); + jbg_buf_write(MARKER_ATMOVE, s->sde[stripe][layer][plane]); + jbg_buf_write(0, s->sde[stripe][layer][plane]); + jbg_buf_write(0, s->sde[stripe][layer][plane]); + jbg_buf_write(0, s->sde[stripe][layer][plane]); + jbg_buf_write(0, s->sde[stripe][layer][plane]); + jbg_buf_write(s->tx[plane], s->sde[stripe][layer][plane]); + jbg_buf_write(0, s->sde[stripe][layer][plane]); + } else { + /* ATMOVE has already become active during this stripe + * => we have to prefix the SDE data with an ATMOVE marker */ + new_jbg_buf = jbg_buf_init(&s->free_list); + jbg_buf_write(MARKER_ESC, new_jbg_buf); + jbg_buf_write(MARKER_ATMOVE, new_jbg_buf); + jbg_buf_write((new_tx_line >> 24) & 0xff, new_jbg_buf); + jbg_buf_write((new_tx_line >> 16) & 0xff, new_jbg_buf); + jbg_buf_write((new_tx_line >> 8) & 0xff, new_jbg_buf); + jbg_buf_write(new_tx_line & 0xff, new_jbg_buf); + jbg_buf_write(new_tx, new_jbg_buf); + jbg_buf_write(0, new_jbg_buf); + jbg_buf_prefix(new_jbg_buf, &s->sde[stripe][layer][plane]); + } + } + +#if 0 + if (stripe == s->stripes - 1) + fprintf(stderr, "tp_lines = %ld, tp_exceptions = %ld, tp_pixels = %ld, " + "dp_pixels = %ld, encoded_pixels = %ld\n", + tp_lines, tp_exceptions, tp_pixels, dp_pixels, encoded_pixels); +#endif + + return; +} + + +/* + * Create the next lower resolution version of an image + */ +static void resolution_reduction(struct jbg_enc_state *s, int plane, + int higher_layer) +{ + unsigned long hl, ll, hx, hy, lx, ly, hbpl, lbpl; + unsigned char *hp1, *hp2, *hp3, *lp; + unsigned long line_h1, line_h2, line_h3, line_l2; + unsigned long y; /* current line number in lowres image */ + unsigned long i; /* current line number within lowres stripe */ + unsigned long j; /* current column number in lowres image */ + int pix, k, l; + + /* number of lines per stripe in highres image */ + hl = s->l0 << higher_layer; + /* number of lines per stripe in lowres image */ + ll = hl >> 1; + /* number of pixels in highres image */ + hx = jbg_ceil_half(s->xd, s->d - higher_layer); + hy = jbg_ceil_half(s->yd, s->d - higher_layer); + /* number of pixels in lowres image */ + lx = jbg_ceil_half(hx, 1); + ly = jbg_ceil_half(hy, 1); + /* bytes per line in highres and lowres image */ + hbpl = jbg_ceil_half(hx, 3); + lbpl = jbg_ceil_half(lx, 3); + /* pointers to first image bytes */ + hp2 = s->lhp[s->highres[plane]][plane]; + hp1 = hp2 + hbpl; + hp3 = hp2 - hbpl; + lp = s->lhp[1 - s->highres[plane]][plane]; + +#ifdef DEBUG + fprintf(stderr, "resolution_reduction: plane = %d, higher_layer = %d\n", + plane, higher_layer); +#endif + + /* + * Layout of the variables line_h1, line_h2, line_h3, which contain + * as bits the high resolution neighbour pixels of the currently coded + * lowres pixel /\: + * \/ + * + * 76543210 76543210 76543210 76543210 line_h3 + * 76543210 76543210 765432/\ 76543210 line_h2 + * 76543210 76543210 765432\/ 76543210 line_h1 + * + * Layout of the variable line_l2, which contains the low resolution + * pixels near the currently coded pixel as bits. The lowres pixel + * which is currently coded is marked as X: + * + * 76543210 76543210 76543210 76543210 line_l2 + * X + */ + + for (y = 0; y < ly;) { + for (i = 0; i < ll && y < ly; i++, y++) { + if (2*y + 1 >= hy) + hp1 = hp2; + pix = 0; + line_h1 = line_h2 = line_h3 = line_l2 = 0; + for (j = 0; j < lbpl * 8; j += 8) { + *lp = 0; + if (i > 0 || (y > 0 && !(s->options & JBG_SDRST))) + line_l2 |= *(lp-lbpl); + for (k = 0; k < 8 && j + k < lx; k += 4) { + if (((j + k) >> 2) < hbpl) { + if (i > 0 || (y > 0 && !(s->options & JBG_SDRST))) + line_h3 |= *hp3; + ++hp3; + line_h2 |= *(hp2++); + line_h1 |= *(hp1++); + } + for (l = 0; l < 4 && j + k + l < lx; l++) { + line_h3 <<= 2; + line_h2 <<= 2; + line_h1 <<= 2; + line_l2 <<= 1; + pix = s->res_tab[((line_h1 >> 8) & 0x007) | + ((line_h2 >> 5) & 0x038) | + ((line_h3 >> 2) & 0x1c0) | + (pix << 9) | ((line_l2 << 2) & 0xc00)]; + *lp = (*lp << 1) | pix; + } + } + ++lp; + } + *(lp - 1) <<= lbpl * 8 - lx; + hp1 += hbpl; + hp2 += hbpl; + hp3 += hbpl; + } + } + +#ifdef DEBUG + { + FILE *f; + char fn[50]; + + sprintf(fn, "dbg_d=%02d.pbm", higher_layer - 1); + f = fopen(fn, "wb"); + fprintf(f, "P4\n%lu %lu\n", lx, ly); + fwrite(s->lhp[1 - s->highres[plane]][plane], 1, lbpl * ly, f); + fclose(f); + } +#endif + + return; +} + + +/* + * This function is called inside the three loops of jbg_enc_out() in + * order to write the next SDE. It has first to generate the required + * SDE and all SDEs which have to be encoded before this SDE can be + * created. The problem here is that if we want to output a lower + * resolution layer, we have to apply the resolution reduction + * algorithm first to get it. As we try to safe as much memory as + * possible, the resolution reduction will overwrite previous higher + * resolution bitmaps. Consequently, we have to encode and buffer SDEs + * which depend on higher resolution layers before we can start the + * resolution reduction. All the logic about which SDE has to be + * encoded before resolution reduction is allowed is handled + * here. This approach may be a bit more complex than alternative ways + * of doing it, but it minimizes the amount of temporary memory used. + */ +static void output_sde(struct jbg_enc_state *s, + unsigned long stripe, int layer, int plane) +{ + int lfcl; /* lowest fully coded layer */ + long i; + unsigned long u; + + assert(s->sde[stripe][layer][plane] != SDE_DONE); + + if (s->sde[stripe][layer][plane] != SDE_TODO) { +#ifdef DEBUG + fprintf(stderr, "writing SDE: s/d/p = %2lu/%2d/%2d\n", + stripe, layer, plane); +#endif + jbg_buf_output(&s->sde[stripe][layer][plane], s->data_out, s->file); + s->sde[stripe][layer][plane] = SDE_DONE; + return; + } + + /* Determine the smallest resolution layer in this plane for which + * not yet all stripes have been encoded into SDEs. This layer will + * have to be completely coded, before we can apply the next + * resolution reduction step. */ + lfcl = 0; + for (i = s->d; i >= 0; i--) + if (s->sde[s->stripes - 1][i][plane] == SDE_TODO) { + lfcl = i + 1; + break; + } + if (lfcl > s->d && s->d > 0 && stripe == 0) { + /* perform the first resolution reduction */ + resolution_reduction(s, plane, s->d); + } + /* In case HITOLO is not used, we have to encode and store the higher + * resolution layers first, although we do not need them right now. */ + while (lfcl - 1 > layer) { + for (u = 0; u < s->stripes; u++) + encode_sde(s, u, lfcl - 1, plane); + --lfcl; + s->highres[plane] ^= 1; + if (lfcl > 1) + resolution_reduction(s, plane, lfcl - 1); + } + + encode_sde(s, stripe, layer, plane); + +#ifdef DEBUG + fprintf(stderr, "writing SDE: s/d/p = %2lu/%2d/%2d\n", stripe, layer, plane); +#endif + jbg_buf_output(&s->sde[stripe][layer][plane], s->data_out, s->file); + s->sde[stripe][layer][plane] = SDE_DONE; + + if (stripe == s->stripes - 1 && layer > 0 && + s->sde[0][layer-1][plane] == SDE_TODO) { + s->highres[plane] ^= 1; + if (layer > 1) + resolution_reduction(s, plane, layer - 1); + } + + return; +} + + +/* + * Convert the table which controls the deterministic prediction + * process from the internal format into the representation required + * for the 1728 byte long DPTABLE element of a BIH. + * + * The bit order of the DPTABLE format (see also ITU-T T.82 figure 13) is + * + * high res: 4 5 6 low res: 0 1 + * 7 8 9 2 3 + * 10 11 12 + * + * were 4 table entries are packed into one byte, while we here use + * internally an unpacked 6912 byte long table indexed by the following + * bit order: + * + * high res: 7 6 5 high res: 8 7 6 low res: 1 0 + * (phase 0) 4 . . (phase 1) 5 4 . 3 2 + * . . . . . . + * + * high res: 10 9 8 high res: 11 10 9 + * (phase 2) 7 6 5 (phase 3) 8 7 6 + * 4 . . 5 4 . + */ +void jbg_int2dppriv(unsigned char *dptable, const char *internal) +{ + int i, j, k; + int trans0[ 8] = { 1, 0, 3, 2, 7, 6, 5, 4 }; + int trans1[ 9] = { 1, 0, 3, 2, 8, 7, 6, 5, 4 }; + int trans2[11] = { 1, 0, 3, 2, 10, 9, 8, 7, 6, 5, 4 }; + int trans3[12] = { 1, 0, 3, 2, 11, 10, 9, 8, 7, 6, 5, 4 }; + + for (i = 0; i < 1728; dptable[i++] = 0) ; + +#define FILL_TABLE1(offset, len, trans) \ + for (i = 0; i < len; i++) { \ + k = 0; \ + for (j = 0; i >> j; j++) \ + k |= ((i >> j) & 1) << trans[j]; \ + dptable[(i + offset) >> 2] |= \ + (internal[k + offset] & 3) << ((3 - (i&3)) << 1); \ + } + + FILL_TABLE1( 0, 256, trans0); + FILL_TABLE1( 256, 512, trans1); + FILL_TABLE1( 768, 2048, trans2); + FILL_TABLE1(2816, 4096, trans3); + + return; +} + + +/* + * Convert the table which controls the deterministic prediction + * process from the 1728 byte long DPTABLE format into the 6912 byte long + * internal format. + */ +void jbg_dppriv2int(char *internal, const unsigned char *dptable) +{ + int i, j, k; + int trans0[ 8] = { 1, 0, 3, 2, 7, 6, 5, 4 }; + int trans1[ 9] = { 1, 0, 3, 2, 8, 7, 6, 5, 4 }; + int trans2[11] = { 1, 0, 3, 2, 10, 9, 8, 7, 6, 5, 4 }; + int trans3[12] = { 1, 0, 3, 2, 11, 10, 9, 8, 7, 6, 5, 4 }; + +#define FILL_TABLE2(offset, len, trans) \ + for (i = 0; i < len; i++) { \ + k = 0; \ + for (j = 0; i >> j; j++) \ + k |= ((i >> j) & 1) << trans[j]; \ + internal[k + offset] = \ + (dptable[(i + offset) >> 2] >> ((3 - (i & 3)) << 1)) & 3; \ + } + + FILL_TABLE2( 0, 256, trans0); + FILL_TABLE2( 256, 512, trans1); + FILL_TABLE2( 768, 2048, trans2); + FILL_TABLE2(2816, 4096, trans3); + + return; +} + + +/* + * Encode one full BIE and pass the generated data to the specified + * call-back function + */ +void jbg_enc_out(struct jbg_enc_state *s) +{ + unsigned long bpl; + unsigned char buf[20]; + unsigned long xd, yd, y; + long ii[3], is[3], ie[3]; /* generic variables for the 3 nested loops */ + unsigned long stripe; + int layer, plane; + int order; + unsigned char dpbuf[1728]; + + /* some sanity checks */ + s->order &= JBG_HITOLO | JBG_SEQ | JBG_ILEAVE | JBG_SMID; + order = s->order & (JBG_SEQ | JBG_ILEAVE | JBG_SMID); + if (iindex[order][0] < 0) + s->order = order = JBG_SMID | JBG_ILEAVE; + if (s->options & JBG_DPON && s->dppriv != jbg_dptable) + s->options |= JBG_DPPRIV; + if (s->mx > MX_MAX) + s->mx = MX_MAX; + s->my = 0; + if (s->mx && s->mx < ((s->options & JBG_LRLTWO) ? 5U : 3U)) + s->mx = 0; + if (s->d > 255 || s->d < 0 || s->dh > s->d || s->dh < 0 || + s->dl < 0 || s->dl > s->dh || s->planes < 0 || s->planes > 255) + return; + /* prevent uint32 overflow: s->l0 * 2 ^ s->d < 2 ^ 32 */ + if (s->d > 31 || (s->d != 0 && s->l0 >= (1UL << (32 - s->d)))) + return; + if (s->yd1 < s->yd) + s->yd1 = s->yd; + if (s->yd1 > s->yd) + s->options |= JBG_VLENGTH; + + /* ensure correct zero padding of bitmap at the final byte of each line */ + if (s->xd & 7) { + bpl = jbg_ceil_half(s->xd, 3); /* bytes per line */ + for (plane = 0; plane < s->planes; plane++) + for (y = 0; y < s->yd; y++) + s->lhp[0][plane][y * bpl + bpl - 1] &= ~((1 << (8 - (s->xd & 7))) - 1); + } + + /* prepare BIH */ + buf[0] = s->dl; + buf[1] = s->dh; + buf[2] = s->planes; + buf[3] = 0; + xd = jbg_ceil_half(s->xd, s->d - s->dh); + yd = jbg_ceil_half(s->yd1, s->d - s->dh); + buf[4] = xd >> 24; + buf[5] = (xd >> 16) & 0xff; + buf[6] = (xd >> 8) & 0xff; + buf[7] = xd & 0xff; + buf[8] = yd >> 24; + buf[9] = (yd >> 16) & 0xff; + buf[10] = (yd >> 8) & 0xff; + buf[11] = yd & 0xff; + buf[12] = s->l0 >> 24; + buf[13] = (s->l0 >> 16) & 0xff; + buf[14] = (s->l0 >> 8) & 0xff; + buf[15] = s->l0 & 0xff; + buf[16] = s->mx; + buf[17] = s->my; + buf[18] = s->order; + buf[19] = s->options & 0x7f; + +#if 0 + /* sanitize L0 (if it was set to 0xffffffff for T.85-style NEWLEN tests) */ + if (s->l0 > (s->yd >> s->d)) + s->l0 = s->yd >> s->d; +#endif + + /* calculate number of stripes that will be required */ + s->stripes = jbg_stripes(s->l0, s->yd, s->d); + + /* allocate buffers for SDE pointers */ + if (s->sde == NULL) { + s->sde = (struct jbg_buf ****) + checked_malloc(s->stripes, sizeof(struct jbg_buf ***)); + for (stripe = 0; stripe < s->stripes; stripe++) { + s->sde[stripe] = (struct jbg_buf ***) + checked_malloc(s->d + 1, sizeof(struct jbg_buf **)); + for (layer = 0; layer < s->d + 1; layer++) { + s->sde[stripe][layer] = (struct jbg_buf **) + checked_malloc(s->planes, sizeof(struct jbg_buf *)); + for (plane = 0; plane < s->planes; plane++) + s->sde[stripe][layer][plane] = SDE_TODO; + } + } + } + + /* output BIH */ + s->data_out(buf, 20, s->file); + if ((s->options & (JBG_DPON | JBG_DPPRIV | JBG_DPLAST)) == + (JBG_DPON | JBG_DPPRIV)) { + /* write private table */ + jbg_int2dppriv(dpbuf, s->dppriv); + s->data_out(dpbuf, 1728, s->file); + } + +#if 0 + /* + * Encode everything first. This is a simple-minded alternative to + * all the tricky on-demand encoding logic in output_sde() for + * debugging purposes. + */ + for (layer = s->dh; layer >= s->dl; layer--) { + for (plane = 0; plane < s->planes; plane++) { + if (layer > 0) + resolution_reduction(s, plane, layer); + for (stripe = 0; stripe < s->stripes; stripe++) + encode_sde(s, stripe, layer, plane); + s->highres[plane] ^= 1; + } + } +#endif + + /* + * Generic loops over all SDEs. Which loop represents layer, plane and + * stripe depends on the option flags. + */ + + /* start and end value for each loop */ + is[iindex[order][STRIPE]] = 0; + ie[iindex[order][STRIPE]] = s->stripes - 1; + is[iindex[order][LAYER]] = s->dl; + ie[iindex[order][LAYER]] = s->dh; + is[iindex[order][PLANE]] = 0; + ie[iindex[order][PLANE]] = s->planes - 1; + + for (ii[0] = is[0]; ii[0] <= ie[0]; ii[0]++) + for (ii[1] = is[1]; ii[1] <= ie[1]; ii[1]++) + for (ii[2] = is[2]; ii[2] <= ie[2]; ii[2]++) { + + stripe = ii[iindex[order][STRIPE]]; + if (s->order & JBG_HITOLO) + layer = s->dh - (ii[iindex[order][LAYER]] - s->dl); + else + layer = ii[iindex[order][LAYER]]; + plane = ii[iindex[order][PLANE]]; + + /* output comment marker segment if there is any pending */ + if (s->comment) { + buf[0] = MARKER_ESC; + buf[1] = MARKER_COMMENT; + buf[2] = s->comment_len >> 24; + buf[3] = (s->comment_len >> 16) & 0xff; + buf[4] = (s->comment_len >> 8) & 0xff; + buf[5] = s->comment_len & 0xff; + s->data_out(buf, 6, s->file); + s->data_out(s->comment, s->comment_len, s->file); + s->comment = NULL; + } + + output_sde(s, stripe, layer, plane); + + /* + * When we generate a NEWLEN test case (s->yd1 > s->yd), output + * NEWLEN after last stripe if we have only a single + * resolution layer or plane (see ITU-T T.85 profile), otherwise + * output NEWLEN before last stripe. + */ + if (s->yd1 > s->yd && + (stripe == s->stripes - 1 || + (stripe == s->stripes - 2 && + (s->dl != s->dh || s->planes > 1)))) { + s->yd1 = s->yd; + yd = jbg_ceil_half(s->yd, s->d - s->dh); + buf[0] = MARKER_ESC; + buf[1] = MARKER_NEWLEN; + buf[2] = yd >> 24; + buf[3] = (yd >> 16) & 0xff; + buf[4] = (yd >> 8) & 0xff; + buf[5] = yd & 0xff; + s->data_out(buf, 6, s->file); +#ifdef DEBUG + fprintf(stderr, "NEWLEN: yd=%lu\n", yd); +#endif + if (stripe == s->stripes - 1) { + buf[1] = MARKER_SDNORM; + s->data_out(buf, 2, s->file); + } + } + + } + + return; +} + + +void jbg_enc_free(struct jbg_enc_state *s) +{ + unsigned long stripe; + int layer, plane; + +#ifdef DEBUG + fprintf(stderr, "jbg_enc_free(%p)\n", (void *) s); +#endif + + /* clear buffers for SDEs */ + if (s->sde) { + for (stripe = 0; stripe < s->stripes; stripe++) { + for (layer = 0; layer < s->d + 1; layer++) { + for (plane = 0; plane < s->planes; plane++) + if (s->sde[stripe][layer][plane] != SDE_DONE && + s->sde[stripe][layer][plane] != SDE_TODO) + jbg_buf_free(&s->sde[stripe][layer][plane]); + checked_free(s->sde[stripe][layer]); + } + checked_free(s->sde[stripe]); + } + checked_free(s->sde); + } + + /* clear free_list */ + jbg_buf_free(&s->free_list); + + /* clear memory for arithmetic encoder states */ + checked_free(s->s); + + /* clear memory for differential-layer typical prediction buffer */ + checked_free(s->tp); + + /* clear memory for adaptive template pixel offsets */ + checked_free(s->tx); + + /* clear lowres image buffers */ + if (s->lhp[1]) { + for (plane = 0; plane < s->planes; plane++) + checked_free(s->lhp[1][plane]); + checked_free(s->lhp[1]); + } + + /* clear buffer for index of highres image in lhp */ + checked_free(s->highres); + + return; +} + + +/* + * Convert the error codes used by jbg_dec_in() into an English ASCII string + */ +const char *jbg_strerror(int errnum) +{ + errnum >>= 4; + if (errnum < 0 || (unsigned) errnum >= sizeof(errmsg)/sizeof(errmsg[0])) + return "Unknown error code passed to jbg_strerror()"; + + return errmsg[errnum]; +} + + +/* + * The constructor for a decoder + */ +void jbg_dec_init(struct jbg_dec_state *s) +{ + s->order = 0; + s->d = -1; + s->bie_len = 0; + s->buf_len = 0; + s->dppriv = NULL; + s->xmax = 4294967295UL; + s->ymax = 4294967295UL; + s->dmax = 256; + s->s = NULL; + + return; +} + + +/* + * Specify a maximum image size for the decoder. If the JBIG file has + * the order bit ILEAVE, but not the bit SEQ set, then the decoder + * will abort to decode after the image has reached the maximal + * resolution layer which is still not wider than xmax or higher than + * ymax. + */ +void jbg_dec_maxsize(struct jbg_dec_state *s, unsigned long xmax, + unsigned long ymax) +{ + if (xmax > 0) s->xmax = xmax; + if (ymax > 0) s->ymax = ymax; + + return; +} + + +/* + * Decode the new len PSDC bytes to which data points and add them to + * the current stripe. Return the number of bytes which have actually + * been read (this will be less than len if a marker segment was + * part of the data or if the final byte was 0xff, in which case + * this code cannot determine whether we have a marker segment). + */ +static size_t decode_pscd(struct jbg_dec_state *s, unsigned char *data, + size_t len) +{ + unsigned long stripe; + unsigned int layer, plane; + unsigned long hl, ll, y, hx, hy, lx, ly, hbpl, lbpl; + unsigned char *hp, *lp1, *lp2, *p1, *q1; + register unsigned long line_h1, line_h2, line_h3; + register unsigned long line_l1, line_l2, line_l3; + struct jbg_ardec_state *se; + unsigned long x; + long o; + unsigned a; + int n; + int pix, cx = 0, slntp, tx; + + /* SDE loop variables */ + stripe = s->ii[iindex[s->order & 7][STRIPE]]; + layer = s->ii[iindex[s->order & 7][LAYER]]; + plane = s->ii[iindex[s->order & 7][PLANE]]; + + /* forward data to arithmetic decoder */ + se = s->s[plane] + layer - s->dl; + se->pscd_ptr = data; + se->pscd_end = data + len; + + /* number of lines per stripe in highres image */ + hl = s->l0 << layer; + /* number of lines per stripe in lowres image */ + ll = hl >> 1; + /* current line number in highres image */ + y = stripe * hl + s->i; + /* number of pixels in highres image */ + hx = jbg_ceil_half(s->xd, s->d - layer); + hy = jbg_ceil_half(s->yd, s->d - layer); + /* number of pixels in lowres image */ + lx = jbg_ceil_half(hx, 1); + ly = jbg_ceil_half(hy, 1); + /* bytes per line in highres and lowres image */ + hbpl = jbg_ceil_half(hx, 3); + lbpl = jbg_ceil_half(lx, 3); + /* pointer to highres and lowres image bytes */ + hp = s->lhp[ layer & 1][plane] + (stripe * hl + s->i) * hbpl + + (s->x >> 3); + lp2 = s->lhp[(layer-1) & 1][plane] + (stripe * ll + (s->i >> 1)) * lbpl + + (s->x >> 4); + lp1 = lp2 + lbpl; + + /* restore a few local variables */ + line_h1 = s->line_h1; + line_h2 = s->line_h2; + line_h3 = s->line_h3; + line_l1 = s->line_l1; + line_l2 = s->line_l2; + line_l3 = s->line_l3; + x = s->x; + +#ifdef DEBUG + if (s->x == 0 && s->i == 0 && s->pseudo) + fprintf(stderr, "decode_pscd(%p, %p, %ld): s/d/p = %2lu/%2u/%2u\n", + (void *) s, (void *) data, (long) len, stripe, layer, plane); +#endif + + if (s->x == 0 && s->i == 0 && + (stripe == 0 || s->reset[plane][layer - s->dl]) && s->pseudo) { + s->tx[plane][layer - s->dl] = s->ty[plane][layer - s->dl] = 0; + s->lntp[plane][layer - s->dl] = 1; + } + + if (layer == 0) { + + /* + * Decode lowest resolution layer + */ + + for (; s->i < hl && y < hy; s->i++, y++) { + + /* adaptive template changes */ + if (x == 0 && s->pseudo) + for (n = 0; n < s->at_moves; n++) + if (s->at_line[n] == s->i) { + s->tx[plane][layer - s->dl] = s->at_tx[n]; + s->ty[plane][layer - s->dl] = s->at_ty[n]; +#ifdef DEBUG + fprintf(stderr, "ATMOVE: line=%lu, tx=%d, ty=%d.\n", s->i, + s->tx[plane][layer - s->dl], s->ty[plane][layer - s->dl]); +#endif + } + tx = s->tx[plane][layer - s->dl]; + assert(tx >= 0); /* i.e., tx can safely be cast to unsigned */ + + /* typical prediction */ + if (s->options & JBG_TPBON && s->pseudo) { + slntp = arith_decode(se, (s->options & JBG_LRLTWO) ? TPB2CX : TPB3CX); + if (slntp < 0) + goto leave; + s->lntp[plane][layer - s->dl] = + !(slntp ^ s->lntp[plane][layer - s->dl]); + if (!s->lntp[plane][layer - s->dl]) { + /* this line is 'typical' (i.e. identical to the previous one) */ + p1 = hp; + if (s->i == 0 && (stripe == 0 || s->reset[plane][layer - s->dl])) + while (p1 < hp + hbpl) *p1++ = 0; + else { + q1 = hp - hbpl; + while (q1 < hp) *p1++ = *q1++; + } + hp += hbpl; + continue; + } + /* this line is 'not typical' and has to be coded completely */ + } + s->pseudo = 0; + + /* + * Layout of the variables line_h1, line_h2, line_h3, which contain + * as bits the neighbour pixels of the currently decoded pixel X: + * + * 76543210 76543210 76543210 76543210 line_h3 + * 76543210 76543210 76543210 76543210 line_h2 + * 76543210 76543210 76543210 76543210 X line_h1 + */ + + if (x == 0) { + line_h1 = line_h2 = line_h3 = 0; + if (s->i > 0 || (y > 0 && !s->reset[plane][layer - s->dl])) + line_h2 = (long)*(hp - hbpl) << 8; + if (s->i > 1 || (y > 1 && !s->reset[plane][layer - s->dl])) + line_h3 = (long)*(hp - hbpl - hbpl) << 8; + } + + /* + * Another tiny JBIG standard bug: + * + * While implementing the line_h3 handling here, I discovered + * another problem with the ITU-T T.82(1993 E) specification. + * This might be a somewhat pathological case, however. The + * standard is unclear about how a decoder should behave in the + * following situation: + * + * Assume we are in layer 0 and all stripes are single lines + * (L0=1 allowed by table 9). We are now decoding the first (and + * only) line of the third stripe. Assume, the first stripe was + * terminated by SDRST and the second stripe was terminated by + * SDNORM. While decoding the only line of the third stripe with + * the three-line template, we need access to pixels from the + * previous two stripes. We know that the previous stripe + * terminated with SDNROM, so we access the pixel from the + * second stripe. But do we have to replace the pixels from the + * first stripe by background pixels, because this stripe ended + * with SDRST? The standard, especially clause 6.2.5 does never + * mention this case, so the behaviour is undefined here. My + * current implementation remembers only the marker used to + * terminate the previous stripe. In the above example, the + * pixels of the first stripe are accessed despite the fact that + * this stripe ended with SDRST. An alternative (only slightly + * more complicated) implementation would be to remember the end + * marker (SDNORM or SDRST) of the previous two stripes in a + * plane/layer and to act accordingly when accessing the two + * previous lines. What am I supposed to do here? + * + * As the standard is unclear about the correct behaviour in the + * situation of the above example, I strongly suggest to avoid + * the following situation while encoding data with JBIG: + * + * LRLTWO = 0, L0=1 and both SDNORM and SDRST appear in layer 0. + * + * I guess that only a very few if any encoders will switch + * between SDNORM and SDRST, so let us hope that this ambiguity + * in the standard will never cause any interoperability + * problems. + * + * Markus Kuhn -- 1995-04-30 + */ + + /* decode line */ + while (x < hx) { + if ((x & 7) == 0) { + if (x < hbpl * 8 - 8 && + (s->i > 0 || (y > 0 && !s->reset[plane][layer - s->dl]))) { + line_h2 |= *(hp - hbpl + 1); + if (s->i > 1 || (y > 1 && !s->reset[plane][layer - s->dl])) + line_h3 |= *(hp - hbpl - hbpl + 1); + } + } + if (s->options & JBG_LRLTWO) { + /* two line template */ + do { + if (tx) { + if ((unsigned) tx > x) + a = 0; + else if (tx < 8) + a = ((line_h1 >> (tx - 5)) & 0x010); + else { + o = (x - tx) - (x & ~7L); + a = (hp[o >> 3] >> (7 - (o & 7))) & 1; + a <<= 4; + } + assert(tx > 31 || + a == ((line_h1 >> (tx - 5)) & 0x010)); + pix = arith_decode(se, (((line_h2 >> 9) & 0x3e0) | a | + (line_h1 & 0x00f))); + } else + pix = arith_decode(se, (((line_h2 >> 9) & 0x3f0) | + (line_h1 & 0x00f))); + if (pix < 0) + goto leave; + line_h1 = (line_h1 << 1) | pix; + line_h2 <<= 1; + } while ((++x & 7) && x < hx); + } else { + /* three line template */ + do { + if (tx) { + if ((unsigned) tx > x) + a = 0; + else if (tx < 8) + a = ((line_h1 >> (tx - 3)) & 0x004); + else { + o = (x - tx) - (x & ~7L); + a = (hp[o >> 3] >> (7 - (o & 7))) & 1; + a <<= 2; + } + assert(tx > 31 || + a == ((line_h1 >> (tx - 3)) & 0x004)); + pix = arith_decode(se, (((line_h3 >> 7) & 0x380) | + ((line_h2 >> 11) & 0x078) | a | + (line_h1 & 0x003))); + } else + pix = arith_decode(se, (((line_h3 >> 7) & 0x380) | + ((line_h2 >> 11) & 0x07c) | + (line_h1 & 0x003))); + if (pix < 0) + goto leave; + + line_h1 = (line_h1 << 1) | pix; + line_h2 <<= 1; + line_h3 <<= 1; + } while ((++x & 7) && x < hx); + } /* if (s->options & JBG_LRLTWO) */ + *hp++ = line_h1; + } /* while */ + *(hp - 1) <<= hbpl * 8 - hx; + x = 0; + s->pseudo = 1; + } /* for (i = ...) */ + + } else { + + /* + * Decode differential layer + */ + + for (; s->i < hl && y < hy; s->i++, y++) { + + /* adaptive template changes */ + if (x == 0) + for (n = 0; n < s->at_moves; n++) + if (s->at_line[n] == s->i) { + s->tx[plane][layer - s->dl] = s->at_tx[n]; + s->ty[plane][layer - s->dl] = s->at_ty[n]; +#ifdef DEBUG + fprintf(stderr, "ATMOVE: line=%lu, tx=%d, ty=%d.\n", s->i, + s->tx[plane][layer - s->dl], s->ty[plane][layer - s->dl]); +#endif + } + tx = s->tx[plane][layer - s->dl]; + + /* handle lower border of low-resolution image */ + if ((s->i >> 1) >= ll - 1 || (y >> 1) >= ly - 1) + lp1 = lp2; + + /* typical prediction */ + if ((s->options & JBG_TPDON) && s->pseudo) { + if ((s->lntp[plane][layer - s->dl] = arith_decode(se, TPDCX)) < 0) + goto leave; + } + s->pseudo = 0; + + /* + * Layout of the variables line_h1, line_h2, line_h3, which contain + * as bits the high resolution neighbour pixels of the currently + * decoded highres pixel X: + * + * 76543210 76543210 76543210 76543210 line_h3 + * 76543210 76543210 76543210 76543210 line_h2 + * 76543210 76543210 76543210 76543210 X line_h1 + * + * Layout of the variables line_l1, line_l2, line_l3, which contain + * the low resolution pixels near the currently decoded pixel as bits. + * The lowres pixel in which the currently coded highres pixel is + * located is marked as Y: + * + * 76543210 76543210 76543210 76543210 line_l3 + * 76543210 76543210 Y6543210 76543210 line_l2 + * 76543210 76543210 76543210 76543210 line_l1 + */ + + + if (x == 0) { + line_h1 = line_h2 = line_h3 = line_l1 = line_l2 = line_l3 = 0; + if (s->i > 0 || (y > 0 && !s->reset[plane][layer - s->dl])) { + line_h2 = (long)*(hp - hbpl) << 8; + if (s->i > 1 || (y > 1 && !s->reset[plane][layer - s->dl])) + line_h3 = (long)*(hp - hbpl - hbpl) << 8; + } + if (s->i > 1 || (y > 1 && !s->reset[plane][layer-s->dl])) + line_l3 = (long)*(lp2 - lbpl) << 8; + line_l2 = (long)*lp2 << 8; + line_l1 = (long)*lp1 << 8; + } + + /* decode line */ + while (x < hx) { + if ((x & 15) == 0) + if ((x >> 1) < lbpl * 8 - 8) { + line_l1 |= *(lp1 + 1); + line_l2 |= *(lp2 + 1); + if (s->i > 1 || + (y > 1 && !s->reset[plane][layer - s->dl])) + line_l3 |= *(lp2 - lbpl + 1); + } + do { + + assert(hp - (s->lhp[ layer &1][plane] + (stripe * hl + s->i) + * hbpl) == (ptrdiff_t) x >> 3); + assert(lp2 - (s->lhp[(layer-1) &1][plane] + (stripe * ll + (s->i>>1)) + * lbpl) == (ptrdiff_t) x >> 4); + + if ((x & 7) == 0) + if (x < hbpl * 8 - 8) { + if (s->i > 0 || (y > 0 && !s->reset[plane][layer - s->dl])) { + line_h2 |= *(hp + 1 - hbpl); + if (s->i > 1 || (y > 1 && !s->reset[plane][layer - s->dl])) + line_h3 |= *(hp + 1 - hbpl - hbpl); + } + } + do { + if (!s->lntp[plane][layer - s->dl]) + cx = (((line_l3 >> 14) & 0x007) | + ((line_l2 >> 11) & 0x038) | + ((line_l1 >> 8) & 0x1c0)); + if (!s->lntp[plane][layer - s->dl] && + (cx == 0x000 || cx == 0x1ff)) { + /* pixels are typical and have not to be decoded */ + do { + line_h1 = (line_h1 << 1) | (cx & 1); + } while ((++x & 1) && x < hx); + line_h2 <<= 2; line_h3 <<= 2; + } else + do { + + /* deterministic prediction */ + if (s->options & JBG_DPON) + if ((y & 1) == 0) + if ((x & 1) == 0) + /* phase 0 */ + pix = s->dppriv[((line_l3 >> 15) & 0x003) | + ((line_l2 >> 13) & 0x00c) | + ((line_h1 << 4) & 0x010) | + ((line_h2 >> 9) & 0x0e0)]; + else + /* phase 1 */ + pix = s->dppriv[(((line_l3 >> 15) & 0x003) | + ((line_l2 >> 13) & 0x00c) | + ((line_h1 << 4) & 0x030) | + ((line_h2 >> 9) & 0x1c0)) + 256]; + else + if ((x & 1) == 0) + /* phase 2 */ + pix = s->dppriv[(((line_l3 >> 15) & 0x003) | + ((line_l2 >> 13) & 0x00c) | + ((line_h1 << 4) & 0x010) | + ((line_h2 >> 9) & 0x0e0) | + ((line_h3 >> 6) & 0x700)) + 768]; + else + /* phase 3 */ + pix = s->dppriv[(((line_l3 >> 15) & 0x003) | + ((line_l2 >> 13) & 0x00c) | + ((line_h1 << 4) & 0x030) | + ((line_h2 >> 9) & 0x1c0) | + ((line_h3 >> 6) & 0xe00)) + 2816]; + else + pix = 2; + + if (pix & 2) { + if (tx) + cx = ((line_h1 & 0x003) | + (((line_h1 << 2) >> (tx - 3)) & 0x010) | + ((line_h2 >> 12) & 0x00c) | + ((line_h3 >> 10) & 0x020)); + else + cx = ((line_h1 & 0x003) | + ((line_h2 >> 12) & 0x01c) | + ((line_h3 >> 10) & 0x020)); + if (x & 1) + cx |= (((line_l2 >> 8) & 0x0c0) | + ((line_l1 >> 6) & 0x300)) | (1UL << 10); + else + cx |= (((line_l2 >> 9) & 0x0c0) | + ((line_l1 >> 7) & 0x300)); + cx |= (y & 1) << 11; + + pix = arith_decode(se, cx); + if (pix < 0) + goto leave; + } + + line_h1 = (line_h1 << 1) | pix; + line_h2 <<= 1; + line_h3 <<= 1; + + } while ((++x & 1) && x < hx); + line_l1 <<= 1; line_l2 <<= 1; line_l3 <<= 1; + } while ((x & 7) && x < hx); + *hp++ = line_h1; + } while ((x & 15) && x < hx); + ++lp1; + ++lp2; + } /* while */ + x = 0; + + *(hp - 1) <<= hbpl * 8 - hx; + if ((s->i & 1) == 0) { + /* low resolution pixels are used twice */ + lp1 -= lbpl; + lp2 -= lbpl; + } else + s->pseudo = 1; + + } /* for (i = ...) */ + + } + + leave: + + /* save a few local variables */ + s->line_h1 = line_h1; + s->line_h2 = line_h2; + s->line_h3 = line_h3; + s->line_l1 = line_l1; + s->line_l2 = line_l2; + s->line_l3 = line_l3; + s->x = x; + + return se->pscd_ptr - data; +} + + +/* + * Provide to the decoder a new BIE fragment of len bytes starting at data. + * + * Unless cnt is NULL, *cnt will contain the number of actually read bytes + * on return. + * + * Normal return values: + * + * JBG_EAGAIN All data bytes provided so far have been processed + * (*cnt == len) but the end of the data stream has + * not yet been recognized. Call the function again + * with additional BIE bytes. + * JBG_EOK The function has reached the end of a and + * a full image has been decoded. The function can + * be called again with data from the next BIE, if + * there exists one, in order to get to a higher + * resolution layer. The remaining len - *cnt bytes + * of the previous data block will then have to passed + * to this function again if len > *cnt. + * JBG_EOK_INTR Parsing the BIE has been interrupted as had been + * requested by a jbg_dec_maxsize() specification. + * This function can be called again with the + * rest of the BIE to continue the decoding process. + * The remaining len - *cnt bytes of the previous + * data block will then have to be passed to this + * function again if len > *cnt. + * + * Any other return value indicates that the decoding process was + * aborted by a serious problem and the only function you can then + * still call is jbg_dec_free() in order to remove the mess, and + * jbg85_strerror() to find out what to tell the user. (Looking at the + * least significant bits of the return value will provide additional + * information by identifying which test exactly has failed.) + */ +int jbg_dec_in(struct jbg_dec_state *s, unsigned char *data, size_t len, + size_t *cnt) +{ + int i, j, required_length; + unsigned long x, y; + unsigned long is[3], ie[3]; + size_t dummy_cnt; + unsigned char *dppriv; + + if (!cnt) cnt = &dummy_cnt; + *cnt = 0; + if (len < 1) return JBG_EAGAIN; + + /* read in 20-byte BIH */ + if (s->bie_len < 20) { + while (s->bie_len < 20 && *cnt < len) + s->buffer[s->bie_len++] = data[(*cnt)++]; + if (s->bie_len < 20) + return JBG_EAGAIN; + /* test whether this looks like a valid JBIG header at all */ + if (s->buffer[1] < s->buffer[0]) + return JBG_EINVAL | 1; + if (s->buffer[3] != 0) return JBG_EINVAL | 2; /* padding != 0 */ + if ((s->buffer[18] & 0xf0) != 0) return JBG_EINVAL | 3; /* padding != 0 */ + if ((s->buffer[19] & 0x80) != 0) return JBG_EINVAL | 4; /* padding != 0 */ + if (s->buffer[0] != s->d + 1) + return JBG_ENOCONT | 1; + s->dl = s->buffer[0]; + s->d = s->buffer[1]; + if (s->dl == 0) + s->planes = s->buffer[2]; + else + if (s->planes != s->buffer[2]) + return JBG_ENOCONT | 2; + x = (((long) s->buffer[ 4] << 24) | ((long) s->buffer[ 5] << 16) | + ((long) s->buffer[ 6] << 8) | (long) s->buffer[ 7]); + y = (((long) s->buffer[ 8] << 24) | ((long) s->buffer[ 9] << 16) | + ((long) s->buffer[10] << 8) | (long) s->buffer[11]); + if (s->dl != 0 && ((s->xd << (s->d - s->dl + 1)) != x && + (s->yd << (s->d - s->dl + 1)) != y)) + return JBG_ENOCONT | 3; + s->xd = x; + s->yd = y; + s->l0 = (((long) s->buffer[12] << 24) | ((long) s->buffer[13] << 16) | + ((long) s->buffer[14] << 8) | (long) s->buffer[15]); + /* ITU-T T.85 trick not directly implemented by decoder; for full + * T.85 compatibility with respect to all NEWLEN marker scenarios, + * preprocess BIE with jbg_newlen() before passing it to the decoder, + * or consider using the decoder found in jbig85.c instead. */ + if (s->yd == 0xffffffff) + return JBG_EIMPL | 1; + if (!s->planes) return JBG_EINVAL | 5; + if (!s->xd) return JBG_EINVAL | 6; + if (!s->yd) return JBG_EINVAL | 7; + if (!s->l0) return JBG_EINVAL | 8; + /* prevent uint32 overflow: s->l0 * 2 ^ s->d < 2 ^ 32 */ + if (s->d > 31) + return JBG_EIMPL | 2; + if ((s->d != 0 && s->l0 >= (1UL << (32 - s->d)))) + return JBG_EIMPL | 3; + s->mx = s->buffer[16]; + if (s->mx > 127) + return JBG_EINVAL | 9; + s->my = s->buffer[17]; +#if 0 + if (s->my > 0) + return JBG_EIMPL | 4; +#endif + s->order = s->buffer[18]; + if (iindex[s->order & 7][0] < 0) + return JBG_EINVAL | 10; + /* HITOLO and SEQ currently not yet implemented */ + if (s->dl != s->d && (s->order & JBG_HITOLO || s->order & JBG_SEQ)) + return JBG_EIMPL | 5; + s->options = s->buffer[19]; + + /* calculate number of stripes that will be required */ + s->stripes = jbg_stripes(s->l0, s->yd, s->d); + + /* some initialization */ + s->ii[iindex[s->order & 7][STRIPE]] = 0; + s->ii[iindex[s->order & 7][LAYER]] = s->dl; + s->ii[iindex[s->order & 7][PLANE]] = 0; + if (s->dl == 0) { + s->s = (struct jbg_ardec_state **) + checked_malloc(s->planes, sizeof(struct jbg_ardec_state *)); + s->tx = (int **) checked_malloc(s->planes, sizeof(int *)); + s->ty = (int **) checked_malloc(s->planes, sizeof(int *)); + s->reset = (int **) checked_malloc(s->planes, sizeof(int *)); + s->lntp = (int **) checked_malloc(s->planes, sizeof(int *)); + s->lhp[0] = (unsigned char **) + checked_malloc(s->planes, sizeof(unsigned char *)); + s->lhp[1] = (unsigned char **) + checked_malloc(s->planes, sizeof(unsigned char *)); + for (i = 0; i < s->planes; i++) { + s->s[i] = (struct jbg_ardec_state *) + checked_malloc(s->d - s->dl + 1, sizeof(struct jbg_ardec_state)); + s->tx[i] = (int *) checked_malloc(s->d - s->dl + 1, sizeof(int)); + s->ty[i] = (int *) checked_malloc(s->d - s->dl + 1, sizeof(int)); + s->reset[i] = (int *) checked_malloc(s->d - s->dl + 1, sizeof(int)); + s->lntp[i] = (int *) checked_malloc(s->d - s->dl + 1, sizeof(int)); + s->lhp[ s->d & 1][i] = (unsigned char *) + checked_malloc(s->yd, jbg_ceil_half(s->xd, 3)); + s->lhp[(s->d-1) & 1][i] = (unsigned char *) + checked_malloc(jbg_ceil_half(s->yd, 1), jbg_ceil_half(s->xd, 1+3)); + } + } else { + for (i = 0; i < s->planes; i++) { + s->s[i] = (struct jbg_ardec_state *) + checked_realloc(s->s[i], s->d - s->dl + 1, + sizeof(struct jbg_ardec_state)); + s->tx[i] = (int *) checked_realloc(s->tx[i], + s->d - s->dl + 1, sizeof(int)); + s->ty[i] = (int *) checked_realloc(s->ty[i], + s->d - s->dl + 1, sizeof(int)); + s->reset[i] = (int *) checked_realloc(s->reset[i], + s->d - s->dl + 1, sizeof(int)); + s->lntp[i] = (int *) checked_realloc(s->lntp[i], + s->d - s->dl + 1, sizeof(int)); + s->lhp[ s->d & 1][i] = (unsigned char *) + checked_realloc(s->lhp[ s->d & 1][i], + s->yd, jbg_ceil_half(s->xd, 3)); + s->lhp[(s->d-1) & 1][i] = (unsigned char *) + checked_realloc(s->lhp[(s->d-1) & 1][i], + jbg_ceil_half(s->yd, 1), jbg_ceil_half(s->xd, 1+3)); + } + } + for (i = 0; i < s->planes; i++) + for (j = 0; j <= s->d - s->dl; j++) + arith_decode_init(s->s[i] + j, 0); + if (s->dl == 0 || (s->options & JBG_DPON && !(s->options & JBG_DPPRIV))) + s->dppriv = jbg_dptable; + s->comment_skip = 0; + s->buf_len = 0; + s->x = 0; + s->i = 0; + s->pseudo = 1; + s->at_moves = 0; + } + + /* read in DPTABLE */ + if (s->bie_len < 20 + 1728 && + (s->options & (JBG_DPON | JBG_DPPRIV | JBG_DPLAST)) == + (JBG_DPON | JBG_DPPRIV)) { + assert(s->bie_len >= 20); + if (!s->dppriv || s->dppriv == jbg_dptable) + s->dppriv = (char *) checked_malloc(1728, sizeof(char)); + while (s->bie_len < 20 + 1728 && *cnt < len) + s->dppriv[s->bie_len++ - 20] = data[(*cnt)++]; + if (s->bie_len < 20 + 1728) + return JBG_EAGAIN; + dppriv = (unsigned char *) s->dppriv; + s->dppriv = (char *) checked_malloc(6912, sizeof(char)); + jbg_dppriv2int(s->dppriv, dppriv); + checked_free(dppriv); + } + + /* + * BID processing loop + */ + + while (*cnt < len) { + + /* process floating marker segments */ + + /* skip COMMENT contents */ + if (s->comment_skip) { + if (s->comment_skip <= len - *cnt) { + *cnt += s->comment_skip; + s->comment_skip = 0; + } else { + s->comment_skip -= len - *cnt; + *cnt = len; + } + continue; + } + + /* load complete marker segments into s->buffer for processing */ + if (s->buf_len > 0) { + assert(s->buffer[0] == MARKER_ESC); + while (s->buf_len < 2 && *cnt < len) + s->buffer[s->buf_len++] = data[(*cnt)++]; + if (s->buf_len < 2) continue; + switch (s->buffer[1]) { + case MARKER_COMMENT: required_length = 6; break; + case MARKER_ATMOVE: required_length = 8; break; + case MARKER_NEWLEN: required_length = 6; break; + case MARKER_ABORT: + case MARKER_SDNORM: + case MARKER_SDRST: required_length = 2; break; + case MARKER_STUFF: + /* forward stuffed 0xff to arithmetic decoder */ + s->buf_len = 0; + decode_pscd(s, s->buffer, 2); + continue; + default: + return JBG_EMARKER; + } + while (s->buf_len < required_length && *cnt < len) + s->buffer[s->buf_len++] = data[(*cnt)++]; + if (s->buf_len < required_length) continue; + /* now the buffer is filled with exactly one marker segment */ + switch (s->buffer[1]) { + case MARKER_COMMENT: + s->comment_skip = + (((long) s->buffer[2] << 24) | ((long) s->buffer[3] << 16) | + ((long) s->buffer[4] << 8) | (long) s->buffer[5]); + break; + case MARKER_ATMOVE: + if (s->at_moves < JBG_ATMOVES_MAX) { + s->at_line[s->at_moves] = + (((long) s->buffer[2] << 24) | ((long) s->buffer[3] << 16) | + ((long) s->buffer[4] << 8) | (long) s->buffer[5]); + s->at_tx[s->at_moves] = (signed char) s->buffer[6]; + s->at_ty[s->at_moves] = s->buffer[7]; + if (s->at_tx[s->at_moves] < - (int) s->mx || + s->at_tx[s->at_moves] > (int) s->mx || + s->at_ty[s->at_moves] > (int) s->my || + (s->at_ty[s->at_moves] == 0 && s->at_tx[s->at_moves] < 0)) + return JBG_EINVAL | 11; + if (s->at_ty[s->at_moves] != 0) + return JBG_EIMPL | 6; + s->at_moves++; + } else + return JBG_EIMPL | 7; /* more than JBG_ATMOVES_MAX ATMOVES */ + break; + case MARKER_NEWLEN: + y = (((long) s->buffer[2] << 24) | ((long) s->buffer[3] << 16) | + ((long) s->buffer[4] << 8) | (long) s->buffer[5]); + if (y > s->yd) return JBG_EINVAL | 12; + if (!(s->options & JBG_VLENGTH)) return JBG_EINVAL | 13; + s->yd = y; + /* calculate again number of stripes that will be required */ + s->stripes = jbg_stripes(s->l0, s->yd, s->d); + break; + case MARKER_ABORT: + return JBG_EABORT; + + case MARKER_SDNORM: + case MARKER_SDRST: + /* decode final pixels based on trailing zero bytes */ + decode_pscd(s, s->buffer, 2); + + arith_decode_init(s->s[s->ii[iindex[s->order & 7][PLANE]]] + + s->ii[iindex[s->order & 7][LAYER]] - s->dl, + s->ii[iindex[s->order & 7][STRIPE]] != s->stripes - 1 + && s->buffer[1] != MARKER_SDRST); + + s->reset[s->ii[iindex[s->order & 7][PLANE]]] + [s->ii[iindex[s->order & 7][LAYER]] - s->dl] = + (s->buffer[1] == MARKER_SDRST); + + /* prepare for next SDE */ + s->x = 0; + s->i = 0; + s->pseudo = 1; + s->at_moves = 0; + + /* increment layer/stripe/plane loop variables */ + /* start and end value for each loop: */ + is[iindex[s->order & 7][STRIPE]] = 0; + ie[iindex[s->order & 7][STRIPE]] = s->stripes - 1; + is[iindex[s->order & 7][LAYER]] = s->dl; + ie[iindex[s->order & 7][LAYER]] = s->d; + is[iindex[s->order & 7][PLANE]] = 0; + ie[iindex[s->order & 7][PLANE]] = s->planes - 1; + i = 2; /* index to innermost loop */ + do { + j = 0; /* carry flag */ + if (++s->ii[i] > ie[i]) { + /* handling overflow of loop variable */ + j = 1; + if (i > 0) + s->ii[i] = is[i]; + } + } while (--i >= 0 && j); + + s->buf_len = 0; + + /* check whether this have been all SDEs */ + if (j) { +#ifdef DEBUG + fprintf(stderr, "This was the final SDE in this BIE, " + "%ld bytes left.\n", (long) (len - *cnt)); +#endif + s->bie_len = 0; + return JBG_EOK; + } + + /* check whether we have to abort because of xmax/ymax */ + if (iindex[s->order & 7][LAYER] == 0 && i < 0) { + /* LAYER is the outermost loop and we have just gone to next layer */ + if (jbg_ceil_half(s->xd, s->d - s->ii[0]) > s->xmax || + jbg_ceil_half(s->yd, s->d - s->ii[0]) > s->ymax) { + s->xmax = 4294967295UL; + s->ymax = 4294967295UL; + return JBG_EOK_INTR; + } + if (s->ii[0] > (unsigned long) s->dmax) { + s->dmax = 256; + return JBG_EOK_INTR; + } + } + + break; + } + s->buf_len = 0; + + } else if (data[*cnt] == MARKER_ESC) + s->buffer[s->buf_len++] = data[(*cnt)++]; + + else { + + /* we have found PSCD bytes */ + *cnt += decode_pscd(s, data + *cnt, len - *cnt); + if (*cnt < len && data[*cnt] != 0xff) { +#ifdef DEBUG + fprintf(stderr, "PSCD was longer than expected, unread bytes " + "%02x %02x %02x %02x ...\n", data[*cnt], data[*cnt+1], + data[*cnt+2], data[*cnt+3]); +#endif + return JBG_EINVAL | 14; + } + + } + } /* of BID processing loop 'while (*cnt < len) ...' */ + + return JBG_EAGAIN; +} + + +/* + * After jbg_dec_in() returned JBG_EOK or JBG_EOK_INTR, you can call this + * function in order to find out the width of the image. Returns 0 if + * there is no image available yet. + */ +unsigned long jbg_dec_getwidth(const struct jbg_dec_state *s) +{ + if (s->d < 0) + return 0; + if (iindex[s->order & 7][LAYER] == 0) { + if (s->ii[0] < 1) + return 0; + else + return jbg_ceil_half(s->xd, s->d - (s->ii[0] - 1)); + } + + return s->xd; +} + + +/* + * After jbg_dec_in() returned JBG_EOK or JBG_EOK_INTR, you can call this + * function in order to find out the height of the image. Returns 0 if + * there is no image available yet. + */ +unsigned long jbg_dec_getheight(const struct jbg_dec_state *s) +{ + if (s->d < 0) + return 0; + if (iindex[s->order & 7][LAYER] == 0) { + if (s->ii[0] < 1) + return 0; + else + return jbg_ceil_half(s->yd, s->d - (s->ii[0] - 1)); + } + + return s->yd; +} + + +/* + * After jbg_dec_in() returned JBG_EOK or JBG_EOK_INTR, you can call this + * function in order to get a pointer to the image. Returns NULL if + * there is no image available yet. + */ +unsigned char *jbg_dec_getimage(const struct jbg_dec_state *s, int plane) +{ + if (s->d < 0) + return NULL; + if (iindex[s->order & 7][LAYER] == 0) { + if (s->ii[0] < 1) + return NULL; + else + return s->lhp[(s->ii[0] - 1) & 1][plane]; + } + + return s->lhp[s->d & 1][plane]; +} + + +/* + * After jbg_dec_in() returned JBG_EOK or JBG_EOK_INTR, you can call + * this function in order to find out the size in bytes of one + * bitplane of the image. + */ +unsigned long jbg_dec_getsize(const struct jbg_dec_state *s) +{ + if (s->d < 0) + return 0; + if (iindex[s->order & 7][LAYER] == 0) { + if (s->ii[0] < 1) + return 0; + else + return + jbg_ceil_half(s->xd, s->d - (s->ii[0] - 1) + 3) * /* overflow risk? */ + jbg_ceil_half(s->yd, s->d - (s->ii[0] - 1)); + } + + return jbg_ceil_half(s->xd, 3) * s->yd; +} + + +/* + * After jbg_dec_in() returned JBG_EOK or JBG_EOK_INTR, you can call + * this function in order to find out the size of the image that you + * can retrieve with jbg_merge_planes(). + */ +unsigned long jbg_dec_getsize_merged(const struct jbg_dec_state *s) +{ + if (s->d < 0) + return 0; + if (iindex[s->order & 7][LAYER] == 0) { + if (s->ii[0] < 1) + return 0; + else + return + jbg_ceil_half(s->xd, s->d - (s->ii[0] - 1)) * /* overflow risk? */ + jbg_ceil_half(s->yd, s->d - (s->ii[0] - 1)) * + ((s->planes + 7) / 8); + } + + return s->xd * s->yd * ((s->planes + 7) / 8); +} + + +/* + * The destructor function which releases any resources obtained by the + * other decoder functions. + */ +void jbg_dec_free(struct jbg_dec_state *s) +{ + int i; + + if (s->d < 0 || s->s == NULL) + return; + s->d = -2; + + for (i = 0; i < s->planes; i++) { + checked_free(s->s[i]); + checked_free(s->tx[i]); + checked_free(s->ty[i]); + checked_free(s->reset[i]); + checked_free(s->lntp[i]); + checked_free(s->lhp[0][i]); + checked_free(s->lhp[1][i]); + } + + checked_free(s->s); + checked_free(s->tx); + checked_free(s->ty); + checked_free(s->reset); + checked_free(s->lntp); + checked_free(s->lhp[0]); + checked_free(s->lhp[1]); + if (s->dppriv && s->dppriv != jbg_dptable) + checked_free(s->dppriv); + + s->s = NULL; + + return; +} + + +/* + * Split bigendian integer pixel field into separate bit planes. In the + * src array, every pixel is represented by a ((has_planes + 7) / 8) byte + * long word, most significant byte first. While has_planes describes + * the number of used bits per pixel in the source image, encode_plane + * is the number of most significant bits among those that we + * actually transfer to dest. + */ +void jbg_split_planes(unsigned long x, unsigned long y, int has_planes, + int encode_planes, + const unsigned char *src, unsigned char **dest, + int use_graycode) +{ + unsigned long bpl = jbg_ceil_half(x, 3); /* bytes per line in dest plane */ + unsigned long line, i; + unsigned k = 8; + int p; + unsigned prev; /* previous *src byte shifted by 8 bit to the left */ + register int bits, msb = has_planes - 1; + int bitno; + + /* sanity checks */ + if (encode_planes > has_planes) + encode_planes = has_planes; + use_graycode = use_graycode != 0 && encode_planes > 1; + + for (p = 0; p < encode_planes; p++) + memset(dest[p], 0, bpl * y); + + for (line = 0; line < y; line++) { /* lines loop */ + for (i = 0; i * 8 < x; i++) { /* dest bytes loop */ + for (k = 0; k < 8 && i * 8 + k < x; k++) { /* pixel loop */ + prev = 0; + for (p = 0; p < encode_planes; p++) { /* bit planes loop */ + /* calculate which bit in *src do we want */ + bitno = (msb - p) & 7; + /* put this bit with its left neighbor right adjusted into bits */ + bits = (prev | *src) >> bitno; + /* go to next *src byte, but keep old */ + if (bitno == 0) + prev = *src++ << 8; + /* make space for inserting new bit */ + dest[p][bpl * line + i] <<= 1; + /* insert bit, if requested apply Gray encoding */ + dest[p][bpl * line + i] |= (bits ^ (use_graycode & (bits>>1))) & 1; + /* + * Theorem: Let b(n),...,b(1),b(0) be the digits of a + * binary word and let g(n),...,g(1),g(0) be the digits of the + * corresponding Gray code word, then g(i) = b(i) xor b(i+1). + */ + } + /* skip unused *src bytes */ + for (;p < has_planes; p++) + if (((msb - p) & 7) == 0) + src++; + } + } + for (p = 0; p < encode_planes; p++) /* right padding loop */ + dest[p][bpl * (line + 1) - 1] <<= 8 - k; + } + + return; +} + +/* + * Merge the separate bit planes decoded by the JBIG decoder into an + * integer pixel field. This is essentially the counterpart to + * jbg_split_planes(). + */ +void jbg_dec_merge_planes(const struct jbg_dec_state *s, int use_graycode, + void (*data_out)(unsigned char *start, size_t len, + void *file), void *file) +{ +#define BUFLEN 4096 + unsigned long bpl, line, i; + unsigned k = 8; + int p; + unsigned char buf[BUFLEN]; + unsigned char *bp = buf; + unsigned char **src; + unsigned long x, y; + unsigned v; + + /* sanity check */ + use_graycode = use_graycode != 0; + + x = jbg_dec_getwidth(s); + y = jbg_dec_getheight(s); + if (x == 0 || y == 0) + return; + bpl = jbg_ceil_half(x, 3); /* bytes per line in src plane */ + + if (iindex[s->order & 7][LAYER] == 0) + if (s->ii[0] < 1) + return; + else + src = s->lhp[(s->ii[0] - 1) & 1]; + else + src = s->lhp[s->d & 1]; + + for (line = 0; line < y; line++) { /* lines loop */ + for (i = 0; i * 8 < x; i++) { /* src bytes loop */ + for (k = 0; k < 8 && i * 8 + k < x; k++) { /* pixel loop */ + v = 0; + for (p = 0; p < s->planes;) { /* dest bytes loop */ + do { + v = (v << 1) | + (((src[p][bpl * line + i] >> (7 - k)) & 1) ^ + (use_graycode & v)); + } while ((s->planes - ++p) & 7); + *bp++ = v; + if (bp - buf == BUFLEN) { + data_out(buf, BUFLEN, file); + bp = buf; + } + } + } + } + } + + if (bp - buf > 0) + data_out(buf, bp - buf, file); + + return; +} + + +/* + * Given a pointer p to the first byte of either a marker segment or a + * PSCD, as well as the length len of the remaining data, return + * either the pointer to the first byte of the next marker segment or + * PSCD, or p+len if this was the last one, or NULL if some error was + * encountered. Possible errors are: + * + * - not enough bytes left for complete marker segment + * - no marker segment terminates the PSCD + * - unknown marker code encountered + * + */ +static unsigned char *jbg_next_pscdms(unsigned char *p, size_t len) +{ + unsigned char *pp; + unsigned long l; + + if (len < 2) + return NULL; /* not enough bytes left for complete marker segment */ + + if (p[0] != MARKER_ESC || p[1] == MARKER_STUFF) { + do { + while (p[0] == MARKER_ESC && p[1] == MARKER_STUFF) { + p += 2; + len -= 2; + if (len < 2) + return NULL; /* not enough bytes left for complete marker segment */ + } + assert(len >= 2); + pp = (unsigned char *) memchr(p, MARKER_ESC, len - 1); + if (!pp) + return NULL; /* no marker segment terminates the PSCD */ + l = pp - p; + assert(l < len); + p += l; + len -= l; + } while (p[1] == MARKER_STUFF); + } else { + switch (p[1]) { + case MARKER_SDNORM: + case MARKER_SDRST: + case MARKER_ABORT: + return p + 2; + case MARKER_NEWLEN: + if (len < 6) + return NULL; /* not enough bytes left for complete marker segment */ + return p + 6; + case MARKER_ATMOVE: + if (len < 8) + return NULL; /* not enough bytes left for complete marker segment */ + return p + 8; + case MARKER_COMMENT: + if (len < 6) + return NULL; /* not enough bytes left for complete marker segment */ + l = (((long) p[2] << 24) | ((long) p[3] << 16) | + ((long) p[4] << 8) | (long) p[5]); + if (len - 6 < l) + return NULL; /* not enough bytes left for complete marker segment */ + return p + 6 + l; + default: + /* unknown marker sequence encountered */ + return NULL; + } + } + + return p; +} + + +/* + * Scan a complete BIE for a NEWLEN marker segment, then read the new + * YD value found in it and use it to overwrite the one in the BIE + * header. Use this procedure if a BIE initially declares an + * unreasonably high provisional YD value (e.g., 0xffffffff) or + * depends on the fact that section 6.2.6.2 of ITU-T T.82 says that a + * NEWLEN marker segment "could refer to a line in the immediately + * preceding stripe due to an unexpected termination of the image or + * the use of only such stripe". ITU-T.85 explicitely suggests the + * use of this for fax machines that start transmission before having + * encountered the end of the page. None of this is necessary for + * BIEs produced by JBIG-KIT, which normally does not use NEWLEN. + */ +int jbg_newlen(unsigned char *bie, size_t len) +{ + unsigned char *p = bie + 20; + int i; + unsigned long y, yn; + + if (len < 20) + return JBG_EAGAIN; + if ((bie[19] & (JBG_DPON | JBG_DPPRIV | JBG_DPLAST)) + == (JBG_DPON | JBG_DPPRIV)) + p += 1728; /* skip DPTABLE */ + if (p >= bie + len) + return JBG_EAGAIN; + + while ((p = jbg_next_pscdms(p, len - (p - bie)))) { + if (p == bie + len) + return JBG_EOK; + else if (p[0] == MARKER_ESC) + switch (p[1]) { + case MARKER_NEWLEN: + y = (((long) bie[ 8] << 24) | ((long) bie[ 9] << 16) | + ((long) bie[10] << 8) | (long) bie[11]); + yn = (((long) p[2] << 24) | ((long) p[3] << 16) | + ((long) p[4] << 8) | (long) p[5]); + if (yn > y) return JBG_EINVAL | 12; + /* overwrite YD in BIH with YD from NEWLEN */ + for (i = 0; i < 4; i++) { + bie[8+i] = p[2+i]; + } + return JBG_EOK; + case MARKER_ABORT: + return JBG_EABORT; + } + } + return JBG_EINVAL | 0; +} diff --git a/converter/other/jbig/libjbig/jbig.txt b/converter/other/jbig/libjbig/jbig.txt new file mode 100644 index 00000000..bdc14b17 --- /dev/null +++ b/converter/other/jbig/libjbig/jbig.txt @@ -0,0 +1,810 @@ + +Using the JBIG-KIT library +-------------------------- + +Markus Kuhn -- 2013-09-10 + + +This text explains how to use the functions provided by the JBIG-KIT +portable image compression library jbig.c in your application +software. The jbig.c library is a full-featured implementation of the +JBIG1 standard aimed at applications that can hold the entire +uncompressed and compressed image in RAM. + +[For applications that require only the single-bit-per-pixel "fax +subset" of the JBIG1 standard defined in ITU-T Recommendation T.85 +, the alternative implementation +found in jbig85.c may be preferable. It keeps not more than three +lines of the uncompressed image in RAM, which makes it particularly +suitable for embedded applications. For information on how to use +jbig85.c, please refer to the separate documentation file jbig85.txt.] + + +1 Introduction to JBIG + +We start with a short introduction to JBIG1. More detailed information +is provided in the "Introduction and overview" section of the JBIG1 +standard. Information on how to obtain a copy of the standard is +available from or +. + +Image data encoded with the JBIG algorithm is separated into planes, +layers, and stripes. Each plane contains one bit per pixel. The number +of planes stored in a JBIG data stream is the number of bits per +pixel. Resolution layers are numbered from 0 to D with 0 being the +layer with the lowest resolution and D the one with the highest. Each +next higher resolution layer has twice the number of rows and columns. +Layer 0 is encoded independently of any other data, all other +resolution layers are encoded as only the difference between the next +lower and the current layer. For applications that require very quick +access to parts of an image, it is possible to divide an image into +several horizontal stripes. All stripes of one resolution layer have +equal size, except perhaps the final one. The number of stripes of an +image is equal in all resolution layers and in all bit planes. + +The compressed data stream specified by the JBIG standard is called a +bi-level image entity (BIE). A BIE consists of a 20-byte header, +followed by an optional 1728-byte table (usually not present, except +in special applications) followed by a sequence of stripe data +entities (SDE). Each SDE encodes the content of one single stripe in +one plane of one resolution layer. Between the SDEs, other information +blocks (called floating marker segments) can also be present. They are +used to change certain parameters of the algorithm in the middle of an +image or contain additional application specific information. A BIE +looks like this: + + + +------------------------------------------------+ + | | + | 20-byte header (with image size, #planes, | + | #layers, stripe size, first layer, options, | + | SDE ordering, ...) | + | | + +------------------------------------------------+ + | | + | optional 1728-byte table | + | | + +------------------------------------------------+ + | | + | optional floating marker segments | + | | + +------------------------------------------------+ + | | + | stripe data entity | + | | + +------------------------------------------------+ + | | + | optional floating marker segments | + | | + +------------------------------------------------+ + | | + | stripe data entity | + | | + +------------------------------------------------+ + ... + +------------------------------------------------+ + | | + | stripe data entity | + | | + +------------------------------------------------+ + + +One BIE can contain all resolution layers of an image, but it is also +possible to store various resolution layers in several BIEs. The BIE +header contains the number of the first and the last resolution layer +stored in this BIE, as well as the size of the highest resolution +layer stored in this BIE. Progressive coding is deactivated by simply +storing the image in one single resolution layer. + +Different applications might have different requirements for the order +in which the SDEs for stripes of various planes and layers are stored +in the BIE, so all possible sensible orderings are allowed by the +standard and indicated by four bits in the header. + +It is possible to use the raw BIE data stream as specified by the JBIG +standard directly as the format of a file used for storing images. +This is what the pbmtojbg, jbgtopbm, pbmtojbg85, and jbgtopbm85 +conversion tools do that are provided in this package as demonstration +applications. However, as the BIE format has been designed for a large +number of very different applications, and to allow efficient direct +processing by special JBIG hardware chip implementations, the BIE +header contains only the minimum amount of information absolutely +required by the decompression algorithm. Many features expected from a +good file format are missing in the BIE data stream: + + - no "magic code" in the first few bytes to allow identification + of the file format on a typeless file system and to allow + automatic distinction from other compression algorithms + + - no standardized way to encode additional information such as a + textual description, information about the meaning of various bit + planes, the physical size and resolution of the document, etc. + + - a checksum to ensure image integrity + + - encryption and signature mechanisms + + - many things more + +Raw BIE data streams alone may therefore not be a suitable format for +document archiving and exchange. A standard format for this purpose +would typically combine a BIE representing the image data with an +additional header providing auxiliary information into one file. +Existing established multi-purpose file formats with a rich set of +auxiliary information attributes like TIFF could be extended easily to +also hold JBIG compressed data. + +On the other hand, in e.g. database applications, a BIE might be +stored directly in a binary variable-length field. Auxiliary +information would then be stored in other fields of the same record, +to simplify search operations. + + +2 Compressing an image + +2.1 Format of the source image + +To be processed by the jbig.c encoder, the image has to be present in +memory as separate bitmap planes. Each byte of a bitmap contains eight +pixels, where the most significant bit represents the leftmost of +these. Each line of a bitmap has to be stored in an integral number of +bytes. If the image width is not an integral multiple of eight, then +the final byte has to be padded with zero bits. + +For example the 23x5 pixels large single plane image: + + .XXXXX..XXX...X...XXX.. + .....X..X..X..X..X..... + .....X..XXX...X..X.XXX. + .X...X..X..X..X..X...X. + ..XXX...XXX...X...XXX.. + +is represented by the 15 bytes + + 01111100 11100010 00111000 + 00000100 10010010 01000000 + 00000100 11100010 01011100 + 01000100 10010010 01000100 + 00111000 11100010 00111000 + +or in hexadecimal notation + + 7c e2 38 04 92 40 04 e2 5c 44 92 44 38 e2 38 + +This is the format used in binary PBM files and it can also be handled +directly by the Xlib library of the X Window System. + +As JBIG can also handle images with multiple bit planes, the jbig.c +library functions accept and return always arrays of pointers to +bitmaps with one pointer per plane. + +For single-plane images, the standard recommends that a 0 pixel +represents the background and a 1 pixel represents the foreground +colour of an image, in other words, 0 is white and 1 is black for +scanned paper documents. For images with several bits per pixel, the +JBIG standard makes no recommendations about how various colours should +be encoded. + +For grey-scale images, by using a Gray code instead of a simple binary +weighted representation of the pixel intensity, some increase in +coding efficiency can be reached. + +A Gray code is also a binary representation of integer numbers, but it +has the property that the representations of the integer numbers i and +(i+1) always differ in exactly one bit. For example, the numbers 0 to +7 can be represented in normal binary code and Gray code as in the +following table: + + normal + number binary code Gray code + --------------------------------------- + 0 000 000 + 1 001 001 + 2 010 011 + 3 011 010 + 4 100 110 + 5 101 111 + 6 110 101 + 7 111 100 + +The form of Gray code shown above has the property that the second +half of the code (numbers 4 - 7) is simply the mirrored first half +(numbers 3 - 0) with the first bit set to one. This way, arbitrarily +large Gray codes can be generated quickly by mirroring the above +example and prefixing the first half with zeros and the second half +with ones as often as required. In grey-scale images, it is common +practise to use the all-0 code for black and the all-1 code for white. + +No matter whether a Gray code or a binary code is used for encoding a +pixel intensity in several bit planes, it always makes sense to store +the most significant (leftmost) bit in plane 0, which is transmitted +first. This way, a decoder could increase the precision of the +displayed pixel intensities while data is still being received and the +basic structure of the image will become visible as early as possible +during the transmission. + + +2.2 A simple compression application + +In order to use jbig.c in your application, just link libjbig.a to +your executable (on Unix systems just add -ljbig and -L. to the +command line options of your compiler, on other systems you will have +to write a new Makefile anyway), copy the file jbig.h into your source +directory and put the line + + #include "jbig.h" + +into your source code. + +The library interface follows object-oriented programming principles. +You have to declare a variable (object) + + struct jbg_enc_state s; + +which contains the current status of an encoder. Then you initialize +the encoder by calling the constructor function + + void jbg_enc_init(struct jbg_enc_state *s, unsigned long x, unsigned long y, + int pl, unsigned char **p, + void (*data_out)(unsigned char *start, size_t len, + void *file), + void *file); + +The parameters have the following meaning: + + s A pointer to the jbg_enc_state structure that you want + to initialize. + + x The width of your image in pixels. + + y The height of your image in pixels (lines). + + pl the number of bitmap planes you want to encode. + + p A pointer to an array of pl pointers, where each is again + pointing to the first byte of a bitmap as described in + section 2.1. + + data_out This is a call-back function that the encoder will + call during the compression process by in order to + deliver the BIE data to your application. The + parameters of the function data_out are a pointer + start to the new block of data being delivered, as + well as the number len of delivered bytes. The pointer + file is transparently delivered to data_out, as + specified in jbg_enc_init(). Typically, data_out will + write the BIE portion to a file, send it to a network + connection, or append it to some memory buffer. + + file A pointer parameter that is passed on to data_out() + and can be used, for instance, to allow data_out() to + distinguish by which compression task it has been + called in multi-threaded applications. + +In the simplest case, the compression is then started by calling the +function + + void jbg_enc_out(struct jbg_enc_state *s); + +which will deliver the complete BIE to data_out() in several calls. +After jbg_enc_out has returned, a call to the destructor function + + void jbg_enc_free(struct jbg_enc_state *s); + +will release any heap memory allocated by the previous functions. + + +A minimal example application, which sends the BIE of the above bitmap +to stdout, looks like this: + +--------------------------------------------------------------------------- +/* A sample JBIG encoding application */ + +#include +#include "jbig.h" + +void output_bie(unsigned char *start, size_t len, void *file) +{ + fwrite(start, 1, len, (FILE *) file); + + return; +} + +int main() +{ + unsigned char bitmap[15] = { + /* 23 x 5 pixels, "JBIG" */ + 0x7c, 0xe2, 0x38, 0x04, 0x92, 0x40, 0x04, 0xe2, + 0x5c, 0x44, 0x92, 0x44, 0x38, 0xe2, 0x38 + }; + unsigned char *bitmaps[1] = { bitmap }; + struct jbg_enc_state se; + + jbg_enc_init(&se, 23, 5, 1, bitmaps, + output_bie, stdout); /* initialize encoder */ + jbg_enc_out(&se); /* encode image */ + jbg_enc_free(&se); /* release allocated resources */ + + return 0; +} +--------------------------------------------------------------------------- + +This software produces a 42 byte long BIE. (JBIG is not very good at +compressing extremely small images like in this example, because the +arithmetic encoder requires some startup data in order to generate +reasonable statistics which influence the compression process and +because there is some header overhead.) + + +2.3 More about compression + +If jbg_enc_out() is called directly after jbg_enc_init(), the +following default values are used for various compression parameters: + + - Only one single resolution layer is used, i.e. no progressive + mode. + + - The number of lines per stripe is selected so that approximately + 35 stripes per image are used (as recommended in annex C of the + standard together with the suggested adaptive template change + algorithm). However, not less than 2 and not more than 128 lines + are used in order to stay within the suggested minimum parameter + support range specified in annex A of the standard). + + - All optional parts of the JBIG algorithm are activated (TPBON, + TPDON and DPON). + + - The default resolution reduction table and the default deterministic + prediction table are used + + - The maximal vertical offset of the adaptive template pixel is 0 + and the maximal horizontal offset is 8 (mx = 8, my = 0). + +In order to change any of these default parameters, additional +functions have to be called between jbg_enc_init() and jbg_enc_out(). + +In order to activate progressive encoding, it is possible to specify +with + + void jbg_enc_layers(struct jbg_enc_state *s, int d); + +the number d of differential resolution layers which shall be encoded +in addition to the lowest resolution layer 0. For example, if a +document with 60-micrometer pixels has to be stored, and the lowest +resolution layer shall have 240-micrometer pixels, so that a screen +previewer can directly decompress only the required resolution, then a +call + + jbg_enc_layers(&se, 2); + +will cause three layers with 240, 120 and 60 micrometers resolution to +be generated. + +If the application does not know what typical resolutions are used and +simply wants to ensure that the lowest resolution layer will fit into +a given maximal window size, then as an alternative, a call to + + int jbg_enc_lrlmax(struct jbg_enc_state *s, unsigned long mwidth, + unsigned long mheight); + +will cause the library to automatically determine the suitable number +of resolutions so that the lowest resolution layer 0 will not be +larger than mwidth x mheight pixels. E.g. if one wants to ensure that +systems with a 640 x 480 pixel large screen can decode the required +resolution directly, then call + + jbg_enc_lrlmax(&se, 640, 480); + +The return value is the number of differential layers selected. + +After the number of resolution layers has been specified by calls to +jbg_enc_layers() or jbg_enc_lrlmax(), by default, all these layers +will be written into the BIE. This can be changed with a call to + + int jbg_enc_lrange(struct jbg_enc_state *s, int dl, int dh); + +Parameter dl specifies the lowest resolution layer and dh the highest +resolution layer that will appear in the BIE. For instance, if layer 0 +shall be written to the first BIE and layer 1 and 2 shall be written +to a second one, then before writing the first BIE, call + + jbg_enc_lrange(&se, 0, 0); + +and before writing the second BIE with jbg_enc_out(), call + + jbg_enc_lrange(&se, 1, 2); + +If any of the parameters is negative, it will be ignored. The return +value is the total number of differential layers that will represent +the input image. This way, jbg_enc_lrange(&se, -1, -1) can be used to +query the layer of the full image resolution. + +A number of other more exotic options of the JBIG algorithm can be +modified by calling + + void jbg_enc_options(struct jbg_enc_state *s, int order, int options, + long l0, int mx, int my); + +before calling jbg_enc_out(). + +The order parameter can be a combination of the bits JBG_HITOLO, +JBG_SEQ, JBG_ILEAVE and JBG_SMID and it determines in which order +the SDEs are stored in the BIE. The bits have the following meaning: + + JBG_HITOLO Usually, the lower resolution layers are stored before + the higher resolution layers, so that a decoder can + already start to display a low resolution version of + the full image once a prefix of the BIE has been + received. When this bit is set, however, the BIE will + contain the higher layers before the lower layers. This + avoids additional buffer memory in the encoder and is + intended for applications where the encoder is connected + to a database which can easily reorder the SDEs before + sending them to a decoder. Warning: JBIG decoders are + not expected to support the HITOLO option (e.g. the + jbig.c decoder currently does not) so you should + normally not use it. + + JBG_SEQ Usually, at first all stripes of one resolution layer + are written to the BIE and then all stripes of the next + layer, and so on. When the SEQ bit is set however, then + all layers of the first stripe will be written, + followed by all layers of the second stripe, etc. This + option also should normally never be required and is + not supported by the current jbig.c decoder. + + JBG_SMID In case there exist several bit planes, then the order of + the stripes is determined by three loops over all stripes, + all planes and all layers. When SMID is set, the loop + over all stripes is the middle loop. + + JBG_ILEAVE If this bit is set, then at first all layers of one + plane are written before the encoder starts with the next + plane. + +The above description may be somewhat confusing, but the following +table (see also Table 11 in ITU-T T.82) clarifies how the three bits +JBG_SEQ, JBIG_ILEAVE and JBG_SMID influence the ordering of the loops +over all stripes, planes and layers: + + + Loops: + JBG_SEQ JBG_ILEAVE JBG_SMID | Outer Middle Inner + ------------------------------------+--------------------------- + 0 0 0 | p d s + 0 1 0 | d p s + 0 1 1 | d s p + 1 0 0 | s p d + 1 0 1 | p s d + 1 1 0 | s d p + + p: plane, s: stripe, d: layer + + +By default, the order combination JBG_ILEAVE | JBG_SMID is used. + +The options value can contain the following bits, which activate +some of the optional algorithms defined by JBIG: + + JBG_LRLTWO Normally, in the lowest resolution layer, pixels + from three lines around the next pixel are used + in order to determine the context in which the next + pixel is encoded. Some people in the JBIG committee + seem to have argued that using only 2 lines will + make software implementations a little bit faster, + however others have argued that using only two lines + will decrease compression efficiency by around 5%. + As you might expect from a committee, now both + alternatives are allowed and if JBG_LRLTWO is set, + the slightly faster but 5% less well compressing two + line alternative is selected. God bless the committees. + Although probably nobody will ever need this option, + it has been implemented in jbig.c and is off by + default. + + JBG_TPDON This activates the "typical prediction" algorithm + for differential layers which avoids that large + areas of equal colour have to be encoded at all. + This is on by default and there is no good reason to + switch it off except for debugging or preparing data + for cheap JBIG hardware that might not support this + option. + + JBG_TPBON Like JBG_TPDON this activates the "typical prediction" + algorithm in the lowest resolution layer. Also activated + by default. + + JBG_DPON This bit activates for the differential resolution + layers the "deterministic prediction" algorithm, + which avoids that higher resolution layer pixels are + encoded when their value can already be determined + with the knowledge of the neighbour pixels, the + corresponding lower resolution pixels and the + resolution reduction algorithm. This is also + activated by default and one reason for deactivating + it would be if the default resolution reduction + algorithm were replaced by another one. + + JBG_DELAY_AT Use a slightly less efficient algorithm to determine + when an adaptive template change is necessary. With + this bit set, the encoder output is compatible to the + conformance test examples in cause 7.2 of ITU-T T.82. + Then all adaptive template changes are delayed until + the first line of the next stripe. This option is by + default deactivated and is only required for passing a + special compatibility test suite. + +In addition, parameter l0 in jbg_enc_options() allows you to specify +the number of lines per stripe in resolution layer 0. The parameters +mx and my change the maximal offset allowed for the adaptive template +pixel. JBIG-KIT now supports the full range of possible mx values up +to 127 in the encoder and decoder, but my is at the moment ignored and +always set to 0. As the standard requires of all decoder +implementations only to support maximum values mx = 16 and my = 0, +higher values should normally be avoided in order to guarantee +interoperability. The ITU-T T.85 profile for JBIG in fax machines +requires support for mx = 127 and my = 0. Default is mx = 8 and my = +0. If any of the parameters order, options, mx or my is negative, or +l0 is zero, then the corresponding current value remains unmodified. + +The resolution reduction and deterministic prediction tables can also +be replaced. However as these options are anyway only for experts, +please have a look at the source code of jbg_enc_out() and the struct +members dppriv and res_tab of struct jbg_enc_state for the details of +how to do this, in case you really need it. The functions +jbg_int2dppriv and jbg_dppriv2int are provided in order to convert the +DPTABLE data from the format used in the standard into the more +efficient format used internally by JBIG-KIT. + +If you want to encode a grey-scale image, you can use the library +function + + void jbg_split_planes(unsigned long x, unsigned long y, int has_planes, + int encode_planes, + const unsigned char *src, unsigned char **dest, + int use_graycode); + +It separates an image in which each pixel is represented by one or +more bytes into separate bit planes. The dest array of pointers to +these bit planes can then be handed over to jbg_enc_init(). The +variables x and y specify the width and height of the image in pixels, +and has_planes specifies how many bits per pixel are used. As each +pixel is represented by an integral number of consecutive bytes, of +which each contains up to eight bits, the total length of the input +image array src[] will therefore be x * y * ((has_planes + 7) / 8) +bytes. The pixels are stored as usually in English reading order, and +for each pixel the integer value is stored with the most significant +byte coming first (Bigendian). This is exactly the format used in raw +PGM files. In encode_planes, the number of bit planes that shall be +extracted can be specified. This allows for instance to extract only +the most significant 8 bits of a 12-bit image, where each pixel is +represented by two bytes, by specifying has_planes = 12 and +encode_planes = 8. If use_graycode is zero, then the binary code of +the pixel integer values will be used instead of the Gray code. Plane +0 contains always the most significant bit. + + +3 Decompressing an image + +Like with the compression functions, if you want to use the jbig.c +library, you have to put the line + + #include "jbig.h" + +into your source code and link your executable with libjbig.a. + +The state of a JBIG decoder is stored completely in a struct and you +will have to define a variable like + + struct jbg_dec_state sd; + +which is initialized by a call to + + void jbg_dec_init(struct jbg_dec_state *s); + +After this, you can directly start to pass data from the BIE to the decoder +by calling the function + + int jbg_dec_in(struct jbg_dec_state *s, unsigned char *data, size_t len, + size_t *cnt); + +The pointer data points to the first byte of a data block with length +len, which contains bytes from a BIE. It is not necessary to pass a +whole BIE at once to jbg_dec_in(), it can arrive fragmented in any way +by calling jbg_dec_in() several times. It is also possible to send +several BIEs concatenated to jbg_dec_in(), however these then have to +fit together. If you send several BIEs to the decoder, the lowest +resolution layer in each following BIE has to be the highest +resolution layer in the previous BIE plus one and the image sizes and +number of planes also have to fit together, otherwise jbg_dec_in() +will return the error JBG_ENOCONT after the header of the new BIE has +been received completely. + +If pointer cnt is not NULL, then the number of bytes actually read +from the data block will be stored there. In case the data block did +not contain the end of the BIE, then the value JBG_EAGAIN will be +returned and *cnt equals len. + +Once the end of a BIE has been reached, the return value of +jbg_dec_in() will be JBG_EOK. After this has happened, the functions +and macros + + unsigned long jbg_dec_getwidth(struct jbg_dec_state *s); + unsigned long jbg_dec_getheight(struct jbg_dec_state *s); + int jbg_dec_getplanes(struct jbg_dec_state *s); + unsigned char *jbg_dec_getimage(struct jbg_dec_state *s, int plane); + unsigned long jbg_dec_getsize(struct jbg_dec_state *s); + +can be used to query the dimensions of the now completely decoded +image and to get a pointer to all bitmap planes. The bitmaps are +stored as described in section 2.1. The function jbg_dec_getsize() +calculates the number of bytes which one bitmap requires. + +The function + + void jbg_dec_merge_planes(const struct jbg_dec_state *s, int use_graycode, + void (*data_out)(unsigned char *start, size_t len, + void *file), void *file); + +allows you to merge the bit planes that can be accessed individually +with jbg_dec_getimage() into an array with one or more bytes per pixel +(i.e., the format provided to jbg_split_planes()). If use_graycode is +zero, then a binary encoding will be used. The output array will be +delivered via the callback function data_out, exactly in the same way +in which the encoder provides the BIE. The function + + unsigned long jbg_dec_getsize_merged(const struct jbg_dec_state *s); + +determines how long the data array delivered by jbg_dec_merge_planes() +is going to be. + +Before calling jbg_dec_in() the first time, it is possible to specify with +a call to + + void jbg_dec_maxsize(struct jbg_dec_state *s, unsigned long xmax, + unsigned long ymax); + +an abort criterion for progressively encoded images. For instance if an +application will display a whole document on a screen which is 1024 x +768 pixels large, then this application should call + + jbg_dec_maxsize(&sd, 1024, 768); + +before the decoding process starts. If the image has been encoded in +progressive mode (i.e. with several resolution layers), then the +decoder will stop with a return value JBG_EOK_INTR after the largest +resolution layer that is still smaller than 1024 x 768. However this +is no guarantee that the image which can then be read out using +jbg_dec_getimage(), etc. is really not larger than the specified +maximal size. The application will have to check the size of the +image, because the decoder does not automatically apply a resolution +reduction if no suitable resolution layer is available in the BIE. + +If jbg_dec_in() returned JBG_EOK_INTR or JBG_EOK, then it is possible +to continue calling jbg_dec_in() with the remaining data in order to +either decode the remaining resolution layers of the current BIE or in +order to add another BIE with additional resolution layers. In both +cases, after jbg_dec_in() returned JBG_EOK_INTR or JBG_EOK, *cnt is +probably not equal to len and the remainder of the data block which +has not yet been processed by the decoder has to be delivered to +jbg_dec_in() again. + +If any other return value than JBG_EOK, JBG_EOK_INTR or JBG_EAGAIN +has been returned by jbg_dec_in(), then an error has occurred and + + void jbg_dec_free(struct jbg_dec_state *s); + +should be called in order to release any allocated memory. The +destructor jbg_dec_free() should of course also be called, once the +decoded bitmap returned by jbg_dec_getimage() is no longer required +and the memory can be released. + +The function + + const char *jbg_strerror(int errnum); + +returns a pointer to a short single line test message that explains +the return value of jbg_dec_in(). This message can be used in order to +provide the user a brief informative message about what when wrong +while decompressing a JBIG image. The po/ subdirectory contains *.po +files that translate the English ASCII strings returned by +jbg_strerror() into other languages (e.g., for use with GNU gettext). +The four least-significant bits of the return value of jbg_dec_in() +may contain additional detailed technical information about the exact +test that spotted the error condition (see source code for details), +i.e. more than the text message returned by jbg_strerror() reveals. +Therefore it may be useful to display the return value itself as a +hexadecimal number, in addition to the string returned by +jbg_strerror(). + +The current implementation of the jbig.c decoder has the following +limitations: + + - The maximal vertical offset MY of the adaptive template pixel + must be zero. + + - HITOLO and SEQ bits must not be set in the order value. + + - Not more than JBG_ATMOVES_MAX (currently set to 64) ATMOVE + marker segments can be handled per stripe. + + - the number D of differential layers must be less than 32 + +None of the above limitations can be exceeded by a JBIG data stream +that conforms to the ITU-T T.85 application profile for the use of +JBIG1 in fax machines. + +The current implementation of the jbig.c decoder does not impose any +limits on the image size that it will process, as long as malloc() is +able to allocate enough heap space for the resulting bitmaps. The only +exception is that jbg_dec_in() will return "Input data stream uses +unimplemented JBIG features" (JBG_EIMPL | 1) if Y_D equals 0xffffffff, +which is an extreme value commonly used to encode images according to +ITU-T T.85 where the height was unknown when the BIH was emitted. +After jbg_dec_in() received the 20-byte long BIH at the start of the +BIE, it will malloc() to allocate enough memory to hold the requested +image planes and layers. If you want to defend your application +against excessive image-size parameters in a received BIH, then do +make sure that you check X_D, Y_D, and P against appropriate safety +limits before handing over the BIH to jbg_dec_in(). + +There are two more limitations of the current implementation of the +jbig.c decoder that might cause problems with processing JBIG data +stream that conform to ITU-T T.85: + + - The jbig.c decoder was designed to operate incrementally. + Each received byte is processed immediately as soon as it arrives. + As a result, it does not look beyond the SDRST/SDNORM at the end + of all stripes for any immediately following NEWLEN marker that + might reduce the number of lines encoded by the current stripe. + However section 6.2.6.2 of ITU-T T.82 says that a NEWLEN marker + segment "could refer to a line in the immediately preceding stripe + due to an unexpected termination of the image or the use of only + such stripe", and ITU-T.85 explicitly suggests the use of this + for fax machines that start transmission before having encountered + the end of the page. + + - The image size initially indicated in the BIE header is used to + allocate memory for a bitmap of this size. This means that BIEs + that set initially Y_D = 0xffffffff (as suggested in ITU-T T.85 + for fax machines that do not know the height of the page at the + start of the transmission) cannot be decoded directly by this + version. + +For both issues, there is a workaround available: + +If you encounter a BIE that has in the header the VLENGTH=1 option bit +set, then first wait until you have received the entire BIE and stored +it in memory. Then call the function + + int jbg_newlen(unsigned char *bie, size_t len); + +where bie is a pointer to the first byte of the BIE and len its length +in bytes. This function will scan the entire BIE for the first NEWLEN +marker segment. It will then take the updated image-height value YD +from it and use it to overwrite the YD value in the BIE header. The +jbg_newlen() can return some of the same error codes as jbg_dec_in(), +namely JBG_EOK if everything went fine, JBG_EAGAIN is the data +provided is too short to be a valid BIE, JBG_EINVAL if a format error +was encountered, and JBG_EABORT if an ABORT marker segment was found. +After having patched the image-height value in the BIE using +jbg_newlen(), simply hand over the BIE as usual to jbg_dec_in(). + +In general, for applications where NEWLEN markers can appear, in +particular fax reception, you should consider using the jbig85.c +decoder instead, as it can process BIEs with NEWLEN markers in a +single pass. + +A more detailed description of the JBIG-KIT implementation is + + Markus Kuhn: Effiziente Kompression von bi-level Bilddaten durch + kontextsensitive arithmetische Codierung. Studienarbeit, Lehrstuhl + für Betriebssysteme, IMMD IV, Universität Erlangen-Nürnberg, + Erlangen, July 1995. (German, 62 pages) + + +Please quote the above if you use JBIG-KIT in your research project. + +*** Happy compressing *** + +[end] diff --git a/converter/other/jbig/libjbig/jbig_ar.c b/converter/other/jbig/libjbig/jbig_ar.c new file mode 100644 index 00000000..d23a317d --- /dev/null +++ b/converter/other/jbig/libjbig/jbig_ar.c @@ -0,0 +1,417 @@ +/* + * Arithmetic encoder and decoder of the portable JBIG + * compression library + * + * Markus Kuhn -- http://www.cl.cam.ac.uk/~mgk25/jbigkit/ + * + * This module implements a portable standard C arithmetic encoder + * and decoder used by the JBIG lossless bi-level image compression + * algorithm as specified in International Standard ISO 11544:1993 + * and ITU-T Recommendation T.82. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * If you want to use this program under different license conditions, + * then contact the author for an arrangement. + */ + +#include +#include "jbig_ar.h" + +/* + * Probability estimation tables for the arithmetic encoder/decoder + * given by ITU T.82 Table 24. + */ + +static short lsztab[113] = { + 0x5a1d, 0x2586, 0x1114, 0x080b, 0x03d8, 0x01da, 0x00e5, 0x006f, + 0x0036, 0x001a, 0x000d, 0x0006, 0x0003, 0x0001, 0x5a7f, 0x3f25, + 0x2cf2, 0x207c, 0x17b9, 0x1182, 0x0cef, 0x09a1, 0x072f, 0x055c, + 0x0406, 0x0303, 0x0240, 0x01b1, 0x0144, 0x00f5, 0x00b7, 0x008a, + 0x0068, 0x004e, 0x003b, 0x002c, 0x5ae1, 0x484c, 0x3a0d, 0x2ef1, + 0x261f, 0x1f33, 0x19a8, 0x1518, 0x1177, 0x0e74, 0x0bfb, 0x09f8, + 0x0861, 0x0706, 0x05cd, 0x04de, 0x040f, 0x0363, 0x02d4, 0x025c, + 0x01f8, 0x01a4, 0x0160, 0x0125, 0x00f6, 0x00cb, 0x00ab, 0x008f, + 0x5b12, 0x4d04, 0x412c, 0x37d8, 0x2fe8, 0x293c, 0x2379, 0x1edf, + 0x1aa9, 0x174e, 0x1424, 0x119c, 0x0f6b, 0x0d51, 0x0bb6, 0x0a40, + 0x5832, 0x4d1c, 0x438e, 0x3bdd, 0x34ee, 0x2eae, 0x299a, 0x2516, + 0x5570, 0x4ca9, 0x44d9, 0x3e22, 0x3824, 0x32b4, 0x2e17, 0x56a8, + 0x4f46, 0x47e5, 0x41cf, 0x3c3d, 0x375e, 0x5231, 0x4c0f, 0x4639, + 0x415e, 0x5627, 0x50e7, 0x4b85, 0x5597, 0x504f, 0x5a10, 0x5522, + 0x59eb +}; + +static unsigned char nmpstab[113] = { + 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 13, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 9, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 32, + 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 48, + 81, 82, 83, 84, 85, 86, 87, 71, + 89, 90, 91, 92, 93, 94, 86, 96, + 97, 98, 99, 100, 93, 102, 103, 104, + 99, 106, 107, 103, 109, 107, 111, 109, + 111 +}; + +/* + * least significant 7 bits (mask 0x7f) of nlpstab[] contain NLPS value, + * most significant bit (mask 0x80) contains SWTCH bit + */ +static unsigned char nlpstab[113] = { + 129, 14, 16, 18, 20, 23, 25, 28, + 30, 33, 35, 9, 10, 12, 143, 36, + 38, 39, 40, 42, 43, 45, 46, 48, + 49, 51, 52, 54, 56, 57, 59, 60, + 62, 63, 32, 33, 165, 64, 65, 67, + 68, 69, 70, 72, 73, 74, 75, 77, + 78, 79, 48, 50, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 61, 61, + 193, 80, 81, 82, 83, 84, 86, 87, + 87, 72, 72, 74, 74, 75, 77, 77, + 208, 88, 89, 90, 91, 92, 93, 86, + 216, 95, 96, 97, 99, 99, 93, 223, + 101, 102, 103, 104, 99, 105, 106, 107, + 103, 233, 108, 109, 110, 111, 238, 112, + 240 +}; + +/* + * The next functions implement the arithmedic encoder and decoder + * required for JBIG. The same algorithm is also used in the arithmetic + * variant of JPEG. + */ + +/* marker codes */ +#define MARKER_STUFF 0x00 +#define MARKER_ESC 0xff + +void arith_encode_init(struct jbg_arenc_state *s, int reuse_st) +{ + int i; + + if (!reuse_st) + for (i = 0; i < 4096; s->st[i++] = 0) ; + s->c = 0; + s->a = 0x10000L; + s->sc = 0; + s->ct = 11; + s->buffer = -1; /* empty */ + + return; +} + + +void arith_encode_flush(struct jbg_arenc_state *s) +{ + unsigned long temp; + + /* find the s->c in the coding interval with the largest + * number of trailing zero bits */ + if ((temp = (s->a - 1 + s->c) & 0xffff0000L) < s->c) + s->c = temp + 0x8000; + else + s->c = temp; + /* send remaining bytes to output */ + s->c <<= s->ct; + if (s->c & 0xf8000000L) { + /* one final overflow has to be handled */ + if (s->buffer >= 0) { + s->byte_out(s->buffer + 1, s->file); + if (s->buffer + 1 == MARKER_ESC) + s->byte_out(MARKER_STUFF, s->file); + } + /* output 0x00 bytes only when more non-0x00 will follow */ + if (s->c & 0x7fff800L) + for (; s->sc; --s->sc) + s->byte_out(0x00, s->file); + } else { + if (s->buffer >= 0) + s->byte_out(s->buffer, s->file); + /* T.82 figure 30 says buffer+1 for the above line! Typo? */ + for (; s->sc; --s->sc) { + s->byte_out(0xff, s->file); + s->byte_out(MARKER_STUFF, s->file); + } + } + /* output final bytes only if they are not 0x00 */ + if (s->c & 0x7fff800L) { + s->byte_out((s->c >> 19) & 0xff, s->file); + if (((s->c >> 19) & 0xff) == MARKER_ESC) + s->byte_out(MARKER_STUFF, s->file); + if (s->c & 0x7f800L) { + s->byte_out((s->c >> 11) & 0xff, s->file); + if (((s->c >> 11) & 0xff) == MARKER_ESC) + s->byte_out(MARKER_STUFF, s->file); + } + } + + return; +} + + +void arith_encode(struct jbg_arenc_state *s, int cx, int pix) +{ + register unsigned lsz, ss; + register unsigned char *st; + long temp; + + assert(cx >= 0 && cx < 4096); + st = s->st + cx; + ss = *st & 0x7f; + assert(ss < 113); + lsz = lsztab[ss]; + +#if 0 + fprintf(stderr, "pix = %d, cx = %d, mps = %d, st = %3d, lsz = 0x%04x, " + "a = 0x%05lx, c = 0x%08lx, ct = %2d, buf = 0x%02x\n", + pix, cx, !!(s->st[cx] & 0x80), ss, lsz, s->a, s->c, s->ct, + s->buffer); +#endif + + if (((pix << 7) ^ s->st[cx]) & 0x80) { + /* encode the less probable symbol */ + if ((s->a -= lsz) >= lsz) { + /* If the interval size (lsz) for the less probable symbol (LPS) + * is larger than the interval size for the MPS, then exchange + * the two symbols for coding efficiency, otherwise code the LPS + * as usual: */ + s->c += s->a; + s->a = lsz; + } + /* Check whether MPS/LPS exchange is necessary + * and chose next probability estimator status */ + *st &= 0x80; + *st ^= nlpstab[ss]; + } else { + /* encode the more probable symbol */ + if ((s->a -= lsz) & 0xffff8000L) + return; /* A >= 0x8000 -> ready, no renormalization required */ + if (s->a < lsz) { + /* If the interval size (lsz) for the less probable symbol (LPS) + * is larger than the interval size for the MPS, then exchange + * the two symbols for coding efficiency: */ + s->c += s->a; + s->a = lsz; + } + /* chose next probability estimator status */ + *st &= 0x80; + *st |= nmpstab[ss]; + } + + /* renormalization of coding interval */ + do { + s->a <<= 1; + s->c <<= 1; + --s->ct; + if (s->ct == 0) { + /* another byte is ready for output */ + temp = s->c >> 19; + if (temp & 0xffffff00L) { + /* handle overflow over all buffered 0xff bytes */ + if (s->buffer >= 0) { + ++s->buffer; + s->byte_out(s->buffer, s->file); + if (s->buffer == MARKER_ESC) + s->byte_out(MARKER_STUFF, s->file); + } + for (; s->sc; --s->sc) + s->byte_out(0x00, s->file); + s->buffer = temp & 0xff; /* new output byte, might overflow later */ + assert(s->buffer != 0xff); + /* can s->buffer really never become 0xff here? */ + } else if (temp == 0xff) { + /* buffer 0xff byte (which might overflow later) */ + ++s->sc; + } else { + /* output all buffered 0xff bytes, they will not overflow any more */ + if (s->buffer >= 0) + s->byte_out(s->buffer, s->file); + for (; s->sc; --s->sc) { + s->byte_out(0xff, s->file); + s->byte_out(MARKER_STUFF, s->file); + } + s->buffer = temp; /* buffer new output byte (can still overflow) */ + } + s->c &= 0x7ffffL; + s->ct = 8; + } + } while (s->a < 0x8000); + + return; +} + + +void arith_decode_init(struct jbg_ardec_state *s, int reuse_st) +{ + int i; + + if (!reuse_st) + for (i = 0; i < 4096; s->st[i++] = 0) ; + s->c = 0; + s->a = 1; + s->ct = 0; + s->startup = 1; + s->nopadding = 0; + return; +} + +/* + * Decode and return one symbol from the provided PSCD byte stream + * that starts in s->pscd_ptr and ends in the byte before s->pscd_end. + * The context cx is a 12-bit integer in the range 0..4095. This + * function will advance s->pscd_ptr each time it has consumed all + * information from that PSCD byte. + * + * If a symbol has been decoded successfully, the return value will be + * 0 or 1 (depending on the symbol). + * + * If the decoder was not able to decode a symbol from the provided + * PSCD, then the return value will be -1, and two cases can be + * distinguished: + * + * s->pscd_ptr == s->pscd_end: + * + * The decoder has used up all information in the provided PSCD + * bytes. Further PSCD bytes have to be provided (via new values of + * s->pscd_ptr and/or s->pscd_end) before another symbol can be + * decoded. + * + * s->pscd_ptr == s->pscd_end - 1: + * + * The decoder has used up all provided PSCD bytes except for the + * very last byte, because that has the value 0xff. The decoder can + * at this point not yet tell whether this 0xff belongs to a + * MARKER_STUFF sequence or marks the end of the PSCD. Further PSCD + * bytes have to be provided (via new values of s->pscd_ptr and/or + * s->pscd_end), including the not yet processed 0xff byte, before + * another symbol can be decoded successfully. + * + * If s->nopadding != 0, the decoder will return -2 when it reaches + * the first two bytes of the marker segment that follows (and + * terminates) the PSCD, but before decoding the first symbol that + * depends on a bit in the input data that could have been the result + * of zero padding, and might, therefore, never have been encoded. + * This gives the caller the opportunity to lookahead early enough + * beyond a terminating SDNORM/SDRST for a trailing NEWLEN (as + * required by T.85) before decoding remaining symbols. Call the + * decoder again afterwards as often as necessary (leaving s->pscd_ptr + * pointing to the start of the marker segment) to retrieve any + * required remaining symbols that might depend on padding. + * + * [Note that each PSCD can be decoded into an infinitely long + * sequence of symbols, because the encoder might have truncated away + * an arbitrarily long sequence of trailing 0x00 bytes, which the + * decoder will append automatically as needed when it reaches the end + * of the PSCD. Therefore, the decoder cannot report any end of the + * symbol sequence and other means (external to the PSCD and + * arithmetic decoding process) are needed to determine that.] + */ + +int arith_decode(struct jbg_ardec_state *s, int cx) +{ + register unsigned lsz, ss; + register unsigned char *st; + int pix; + + /* renormalization */ + while (s->a < 0x8000 || s->startup) { + while (s->ct <= 8 && s->ct >= 0) { + /* first we can move a new byte into s->c */ + if (s->pscd_ptr >= s->pscd_end) { + return -1; /* more bytes needed */ + } + if (*s->pscd_ptr == 0xff) + if (s->pscd_ptr + 1 >= s->pscd_end) { + return -1; /* final 0xff byte not processed */ + } else { + if (*(s->pscd_ptr + 1) == MARKER_STUFF) { + s->c |= 0xffL << (8 - s->ct); + s->ct += 8; + s->pscd_ptr += 2; + } else { + s->ct = -1; /* start padding with zero bytes */ + if (s->nopadding) { + s->nopadding = 0; + return -2; /* subsequent symbols might depend on zero padding */ + } + } + } + else { + s->c |= (long)*(s->pscd_ptr++) << (8 - s->ct); + s->ct += 8; + } + } + s->c <<= 1; + s->a <<= 1; + if (s->ct >= 0) s->ct--; + if (s->a == 0x10000L) + s->startup = 0; + } + + st = s->st + cx; + ss = *st & 0x7f; + assert(ss < 113); + lsz = lsztab[ss]; + +#if 0 + fprintf(stderr, "cx = %d, mps = %d, st = %3d, lsz = 0x%04x, a = 0x%05lx, " + "c = 0x%08lx, ct = %2d\n", + cx, !!(s->st[cx] & 0x80), ss, lsz, s->a, s->c, s->ct); +#endif + + if ((s->c >> 16) < (s->a -= lsz)) + if (s->a & 0xffff8000L) + return *st >> 7; + else { + /* MPS_EXCHANGE */ + if (s->a < lsz) { + pix = 1 - (*st >> 7); + /* Check whether MPS/LPS exchange is necessary + * and chose next probability estimator status */ + *st &= 0x80; + *st ^= nlpstab[ss]; + } else { + pix = *st >> 7; + *st &= 0x80; + *st |= nmpstab[ss]; + } + } + else { + /* LPS_EXCHANGE */ + if (s->a < lsz) { + s->c -= s->a << 16; + s->a = lsz; + pix = *st >> 7; + *st &= 0x80; + *st |= nmpstab[ss]; + } else { + s->c -= s->a << 16; + s->a = lsz; + pix = 1 - (*st >> 7); + /* Check whether MPS/LPS exchange is necessary + * and chose next probability estimator status */ + *st &= 0x80; + *st ^= nlpstab[ss]; + } + } + + return pix; +} diff --git a/converter/other/jbig/pnmtojbig.c b/converter/other/jbig/pnmtojbig.c index 9dbef3fa..f5188c7b 100644 --- a/converter/other/jbig/pnmtojbig.c +++ b/converter/other/jbig/pnmtojbig.c @@ -195,7 +195,7 @@ readPnm(FILE * const fin, free(image); /* Invert the image if it is just one plane. See top of this file - for an explanation why. Due to the separate handling of PBM, + for an explanation why. Because of the separate handling of PBM, this is for exceptional PGM files. */ diff --git a/converter/other/jpeg2000/Makefile b/converter/other/jpeg2000/Makefile index f4fee87f..6e5af8e7 100644 --- a/converter/other/jpeg2000/Makefile +++ b/converter/other/jpeg2000/Makefile @@ -5,21 +5,23 @@ endif SUBDIR = converter/other/jpeg2000 VPATH=.:$(SRCDIR)/$(SUBDIR) -SUBDIRS = libjasper +SUBDIRS = include $(BUILDDIR)/config.mk EXTERN_INCLUDES = -ifneq ($(JASPERHDR_DIR),NONE) - EXTERN_INCLUDES += -I$(JASPERHDR_DIR) -endif - # INTERNAL_JASPERLIB must be relative to the current directory, because it # may end up in MERGE_OBJECTS, which must be relative. INTERNAL_JASPERLIB = libjasper/libjasper.a INTERNAL_JASPERHDR_DIR = $(SRCDIR)/$(SUBDIR)/libjasper/include +ifneq ($(JASPERHDR_DIR),NONE) + ifneq ($(JASPERHDR_DIR)x,x) + EXTERN_INCLUDES += -I$(JASPERHDR_DIR) + endif +endif + ifeq ($(JASPERLIB),$(INTERNAL_JASPERLIB)) ifeq ($(HAVE_INT64),Y) JASPERLIB_DEP = $(JASPERLIB) @@ -38,17 +40,19 @@ endif ifneq ($(JASPERHDR_DIR),NONE) ifneq ($(JASPERLIB_USE),NONE) - BINARIES = pamtojpeg2k jpeg2ktopam + PORTBINARIES = pamtojpeg2k jpeg2ktopam endif endif +BINARIES = $(PORTBINARIES) OBJECTS = $(BINARIES:%=%.o) MERGE_OBJECTS = $(BINARIES:%=%.o2) ifeq ($(JASPERLIB),$(INTERNAL_JASPERLIB)) # MERGE_OBJECTS contains relative paths, so $(INTERNAL_JASPERLIB) had better - # be relative to the current relative to the current directory. + # be relative to the current directory. MERGE_OBJECTS += $(JASPERLIB) + SUBDIRS += libjasper endif MERGEBINARIES = $(BINARIES) @@ -57,12 +61,10 @@ all: $(BINARIES) include $(SRCDIR)/common.mk -LIBOPTS = $(shell $(LIBOPT) $(NETPBMLIB) $(JASPERLIB_USE)) +LIBOPTS = $(shell $(LIBOPT) $(JASPERLIB_USE)) -$(BINARIES): %: %.o $(JASPERLIB_DEP) $(NETPBMLIB) $(LIBOPT) - $(LD) -o $@ $< \ - $(LIBOPTS) $(JASPERDEPLIBS) $(MATHLIB) $(RPATH) \ - $(LDFLAGS) $(LDLIBS) $(LADD) +$(BINARIES): %: %.o $(JASPERLIB_DEP) $(LIBOPT) +$(BINARIES): LDFLAGS_TARGET = $(LIBOPTS) $(JASPERDEPLIBS) $(INTERNAL_JASPERLIB): $(BUILDDIR)/$(SUBDIR)/libjasper FORCE $(MAKE) -f $(SRCDIR)/$(SUBDIR)/libjasper/Makefile \ diff --git a/converter/other/jpeg2000/jpeg2ktopam.c b/converter/other/jpeg2000/jpeg2ktopam.c index e6db7658..405de9c9 100644 --- a/converter/other/jpeg2000/jpeg2ktopam.c +++ b/converter/other/jpeg2000/jpeg2ktopam.c @@ -9,17 +9,23 @@ *****************************************************************************/ #define _BSD_SOURCE 1 /* Make sure strdup() is in string.h */ -/* Make sure strdup() is in string.h and int_fast32_t is in inttypes.h */ -#define _XOPEN_SOURCE 600 +#define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */ + /* In 2014.09, this was _XOPEN_SOURCE 600, with a comment saying it was + necessary to make define int_fast32_t, etc. on AIX. + does use int_fast32_t and does include , + but plenty of source files of libjasper do to0, and they did not have + _XOPEN_SOURCE 600, so it would seem to be superfluous here too. + */ #include +#include + #include "pm_c_util.h" #include "pam.h" #include "shhopt.h" #include "nstring.h" #include "mallocvar.h" -#include #include "libjasper_compat.h" enum compmode {COMPMODE_INTEGER, COMPMODE_REAL}; @@ -41,7 +47,7 @@ parseCommandLine(int argc, char ** argv, struct cmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- Note that many of the strings that this function returns in the - *cmdline_p structure are actually in the supplied argv array. And + *cmdlineP structure are actually in the supplied argv array. And sometimes, one of these strings is actually just a suffix of an entry in argv! -----------------------------------------------------------------------------*/ @@ -64,7 +70,7 @@ parseCommandLine(int argc, char ** argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); if (!debuglevelSpec) cmdlineP->debuglevel = 0; @@ -82,36 +88,57 @@ parseCommandLine(int argc, char ** argv, static void -readJpc(const char * const inputFilename, +validateJ2k(jas_stream_t * const instreamP) { +/*---------------------------------------------------------------------------- + Abort program with error message if *instreamP is not a JPEG-2000 code + stream (JPC) or image file (JP2). +-----------------------------------------------------------------------------*/ + assert(jas_image_lookupfmtbyname("jpc")); + assert(jas_image_lookupfmtbyname("jp2")); + + if (jas_image_lookupfmtbyname("jpc")->ops.validate(instreamP) != 0 && + jas_image_lookupfmtbyname("jp2")->ops.validate(instreamP) != 0) { + + pm_error("Input is not JPEG-2000 image file (JP2) " + "or code stream (JPC). " + "(the first few bytes of the file are not the required " + "signature)"); + } +} + + + + +static void +readJ2k(const char * const inputFilename, jas_image_t ** const jasperPP) { jas_image_t * jasperP; - jas_stream_t *instream; + jas_stream_t * instreamP; const char * options; - if ( strcmp(inputFilename, "-") == 0) { + if (streq(inputFilename, "-")) { /* The input image is to be read from standard input. */ - instream = jas_stream_fdopen(fileno(stdin), "rb"); - if (instream == NULL) + instreamP = jas_stream_fdopen(fileno(stdin), "rb"); + if (instreamP == NULL) pm_error("error: cannot reopen standard input"); } else { - instream = jas_stream_fopen(inputFilename, "rb"); - if (instream == NULL ) + instreamP = jas_stream_fopen(inputFilename, "rb"); + if (instreamP == NULL ) pm_error("cannot open input image file '%s'", inputFilename); } - if (jas_image_getfmt(instream) != jas_image_strtofmt((char*)"jpc")) - pm_error("Input is not JPEG-2000 code stream"); + validateJ2k(instreamP); options = ""; - jasperP = jas_image_decode(instream, jas_image_strtofmt((char*)"jpc"), + jasperP = jas_image_decode(instreamP, jas_image_getfmt(instreamP), (char*)options); if (jasperP == NULL) pm_error("Unable to interpret JPEG-2000 input. " "The Jasper library jas_image_decode() subroutine failed."); - jas_stream_close(instream); + jas_stream_close(instreamP); *jasperPP = jasperP; } @@ -189,7 +216,7 @@ static void validateComponentsAlike(jas_image_t * const jasperP) { /*---------------------------------------------------------------------------- JPC allows each component to have its own width and height. But - PAM requires all planes to the same shape. So we validate now that + PAM requires all planes to have the same shape. So we validate now that all the channels are the same, and abort the program if not. -----------------------------------------------------------------------------*/ int cmptNo; @@ -406,8 +433,9 @@ convertToPamPnm(struct pam * const outpamP, unsigned int row; tuple * tuplerow; jas_seqent_t ** jasperRow; /* malloc'ed */ - /* A row of a plane of the raster from the Jasper library - This is an array of pointers into the 'matrix' data structures. + /* A row of the raster from the Jasper library This is an array of + pointers into the 'matrix' data structures, one for each plane in + the row. */ bool singleMaxval; @@ -479,7 +507,7 @@ main(int argc, char **argv) jas_setdbglevel(cmdline.debuglevel); - readJpc(cmdline.inputFilename, &jasperP); + readJ2k(cmdline.inputFilename, &jasperP); outpam.file = stdout; outpam.size = sizeof(outpam); diff --git a/converter/other/jpeg2000/libjasper/README b/converter/other/jpeg2000/libjasper/README index ad3e019b..b0512fe8 100644 --- a/converter/other/jpeg2000/libjasper/README +++ b/converter/other/jpeg2000/libjasper/README @@ -6,10 +6,12 @@ The adaptation was done by Bryan Henderson on 2002.10.26. The adaptation involved: - - remove stuff for formats other than PNM. + - Remove stuff for formats other than JPEG-2000. - Replace build stuff (Jasper uses GNU Autoconf/Automake/Libtool). + - Make JP2 decoder not dump the box to stderr unless debug is turned on. + See . diff --git a/converter/other/jpeg2000/libjasper/base/jas_image.c b/converter/other/jpeg2000/libjasper/base/jas_image.c index e6439fcd..903b45c6 100644 --- a/converter/other/jpeg2000/libjasper/base/jas_image.c +++ b/converter/other/jpeg2000/libjasper/base/jas_image.c @@ -375,9 +375,9 @@ static void jas_image_cmpt_destroy(jas_image_cmpt_t *cmpt) jas_free(cmpt); } -/******************************************************************************\ +/*****************************************************************************\ * Load and save operations. -\******************************************************************************/ +\*****************************************************************************/ jas_image_t *jas_image_decode(jas_stream_t *in, int fmt, char *optstr) { @@ -623,7 +623,7 @@ int jas_image_getfmt(jas_stream_t *in) int found; int i; - /* Check for data in each of the supported formats. */ + /* Check for data in each of the formats we know. */ found = 0; for (i = 0, fmtinfo = jas_image_fmtinfos; i < jas_image_numfmts; ++i, ++fmtinfo) { @@ -857,7 +857,7 @@ void jas_image_dump(jas_image_t *image, FILE *out) } for (cmptno = 0; cmptno < image->numcmpts_; ++cmptno) { cmpt = image->cmpts_[cmptno]; - fprintf(out, "prec=%d sgnd=%d\n", cmpt->prec_, cmpt->sgnd_); + fprintf(out, "prec=%d sgnd=%d\n", (int)cmpt->prec_, cmpt->sgnd_); if (jas_image_readcmpt(image, cmptno, 0, 0, 1, 1, data)) { abort(); } diff --git a/converter/other/jpeg2000/libjasper/base/jas_seq.c b/converter/other/jpeg2000/libjasper/base/jas_seq.c index b8e3c94b..12dc1595 100644 --- a/converter/other/jpeg2000/libjasper/base/jas_seq.c +++ b/converter/other/jpeg2000/libjasper/base/jas_seq.c @@ -414,7 +414,8 @@ int jas_matrix_output(jas_matrix_t *matrix, FILE *out) int j; jas_seqent_t x; - fprintf(out, "%d %d\n", jas_matrix_numrows(matrix), jas_matrix_numcols(matrix)); + fprintf(out, "%d %d\n", + (int)jas_matrix_numrows(matrix), (int)jas_matrix_numcols(matrix)); for (i = 0; i < jas_matrix_numrows(matrix); ++i) { for (j = 0; j < jas_matrix_numcols(matrix); ++j) { x = jas_matrix_get(matrix, i, j); diff --git a/converter/other/jpeg2000/libjasper/base/jas_stream.c b/converter/other/jpeg2000/libjasper/base/jas_stream.c index 4c84e6c2..16c948eb 100644 --- a/converter/other/jpeg2000/libjasper/base/jas_stream.c +++ b/converter/other/jpeg2000/libjasper/base/jas_stream.c @@ -117,6 +117,7 @@ */ #define _XOPEN_SOURCE 500 /* Make sure P_tmpdir is defined */ +#include "pm_config.h" #include #include #include @@ -126,11 +127,11 @@ #if defined(HAVE_UNISTD_H) #include #endif -#if defined(WIN32) || defined(HAVE_IO_H) +#if HAVE_IO_H #include #endif -#include "pm.h" +#include "netpbm/pm.h" #include "jasper/jas_types.h" #include "jasper/jas_stream.h" @@ -440,7 +441,7 @@ jas_stream_t *jas_stream_fdopen(int fd, const char *mode) /* Parse the mode string. */ stream->openmode_ = jas_strtoopenmode(mode); -#if defined(WIN32) +#if defined(HAVE_SETMODE) && defined(O_BINARY) /* Argh!!! Someone ought to banish text mode (i.e., O_TEXT) to the greatest depths of purgatory! */ /* Ensure that the file descriptor is in binary mode, if the caller @@ -902,7 +903,7 @@ int jas_stream_copy(jas_stream_t *out, jas_stream_t *in, int n) while (all || m > 0) { if ((c = jas_stream_getc_macro(in)) == EOF) { /* The next character of input could not be read. */ - /* Return with an error if an I/O error occured + /* Return with an error if an I/O error occurred (not including EOF) or if an explicit copy count was specified. */ return (!all || jas_stream_error(in)) ? (-1) : 0; diff --git a/converter/other/jpeg2000/libjasper/common.mk b/converter/other/jpeg2000/libjasper/common.mk index 687a9f3f..a333f5d6 100644 --- a/converter/other/jpeg2000/libjasper/common.mk +++ b/converter/other/jpeg2000/libjasper/common.mk @@ -13,19 +13,19 @@ partlist: $(SUBDIRS:%=%/partlist) cat /dev/null $(SUBDIRS:%=%/partlist) >$@ echo $(LIB_OBJECTS:%=$(CURDIR)/%) >>$@ -.PHONY: $(SUBDIRS:%=%/partlist) -$(SUBDIRS:%=%/partlist): %/partlist: $(CURDIR)/% +$(SUBDIRS:%=%/partlist): $(MAKE) -C $(dir $@) -f $(SRCDIR)/$(SUBDIR)/$(dir $@)Makefile \ SRCDIR=$(SRCDIR) BUILDDIR=$(BUILDDIR) $(notdir $@) include $(SRCDIR)/common.mk -INCLUDES = -I$(JASPERSRCDIR)/include -Iimportinc +INCLUDES := -I$(JASPERSRCDIR)/include $(INCLUDES) DEFS = -DHAVE_LIBM=1 -DSTDC_HEADERS=1 -DHAVE_FCNTL_H=1 -DHAVE_LIMITS_H=1 -DHAVE_UNISTD_H=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STDDEF_H=1 -DEXCLUDE_BMP_SUPPORT -DEXCLUDE_RAS_SUPPORT -DEXCLUDE_MIF_SUPPORT -DEXCLUDE_JPG_SUPPORT -DEXCLUDE_PGX_SUPPORT -DEXCLUDE_PNM_SUPPORT $(LIB_OBJECTS):%.o:%.c - $(CC) -c $(INCLUDES) $(DEFS) $(CPPFLAGS) $(CFLAGS) $(CADD) $< + $(CC) -c $(INCLUDES) $(DEFS) $(CPPFLAGS) $(CFLAGS) \ + $(CFLAGS_PERSONAL) $(CADD) $< $(LIB_OBJECTS): importinc diff --git a/converter/other/jpeg2000/libjasper/include/jasper/jas_image.h b/converter/other/jpeg2000/libjasper/include/jasper/jas_image.h index d6456f7c..6e914efd 100644 --- a/converter/other/jpeg2000/libjasper/include/jasper/jas_image.h +++ b/converter/other/jpeg2000/libjasper/include/jasper/jas_image.h @@ -123,7 +123,7 @@ * Includes. \******************************************************************************/ -#include "pm_c_util.h" +#include "netpbm/pm_c_util.h" #include #include @@ -171,9 +171,9 @@ extern "C" { #define JAS_IMAGE_CT_GRAY_Y 0 -/******************************************************************************\ +/*****************************************************************************\ * Image class and supporting classes. -\******************************************************************************/ +\*****************************************************************************/ /* Image component class. */ @@ -294,7 +294,7 @@ typedef struct { \******************************************************************************/ #define JAS_IMAGE_MAXFMTS 32 -/* The maximum number of image data formats supported. */ +/* The maximum number of image data formats we can handle. */ /* Image format-dependent operations. */ @@ -530,57 +530,57 @@ int jas_image_getfmt(jas_stream_t *in); * Image format-dependent operations. \******************************************************************************/ -#if !defined(EXCLUDE_JPG_SUPPORT) -/* Format-dependent operations for JPG support. */ +#if !defined(EXCLUDE_JPG_CAPABILITY) +/* Format-dependent operations for JPG capability. */ jas_image_t *jpg_decode(jas_stream_t *in, char *optstr); int jpg_encode(jas_image_t *image, jas_stream_t *out, char *optstr); int jpg_validate(jas_stream_t *in); #endif -#if !defined(EXCLUDE_MIF_SUPPORT) -/* Format-dependent operations for MIF support. */ +#if !defined(EXCLUDE_MIF_CAPABILITY) +/* Format-dependent operations for MIF capability. */ jas_image_t *mif_decode(jas_stream_t *in, char *optstr); int mif_encode(jas_image_t *image, jas_stream_t *out, char *optstr); int mif_validate(jas_stream_t *in); #endif -#if !defined(EXCLUDE_PNM_SUPPORT) -/* Format-dependent operations for PNM support. */ +#if !defined(EXCLUDE_PNM_CAPABILITY) +/* Format-dependent operations for PNM capability. */ jas_image_t *pnm_decode(jas_stream_t *in, char *optstr); int pnm_encode(jas_image_t *image, jas_stream_t *out, char *optstr); int pnm_validate(jas_stream_t *in); #endif -#if !defined(EXCLUDE_RAS_SUPPORT) -/* Format-dependent operations for Sun Rasterfile support. */ +#if !defined(EXCLUDE_RAS_CAPABILITY) +/* Format-dependent operations for Sun Rasterfile capability. */ jas_image_t *ras_decode(jas_stream_t *in, char *optstr); int ras_encode(jas_image_t *image, jas_stream_t *out, char *optstr); int ras_validate(jas_stream_t *in); #endif -#if !defined(EXCLUDE_BMP_SUPPORT) -/* Format-dependent operations for BMP support. */ +#if !defined(EXCLUDE_BMP_CAPABILITY) +/* Format-dependent operations for BMP capability. */ jas_image_t *bmp_decode(jas_stream_t *in, char *optstr); int bmp_encode(jas_image_t *image, jas_stream_t *out, char *optstr); int bmp_validate(jas_stream_t *in); #endif -#if !defined(EXCLUDE_JP2_SUPPORT) -/* Format-dependent operations for JP2 support. */ +#if !defined(EXCLUDE_JP2_CAPABILITY) +/* Format-dependent operations for JP2 capability. */ jas_image_t *jp2_decode(jas_stream_t *in, char *optstr); int jp2_encode(jas_image_t *image, jas_stream_t *out, char *optstr); int jp2_validate(jas_stream_t *in); #endif -#if !defined(EXCLUDE_JPC_SUPPORT) -/* Format-dependent operations for JPEG-2000 code stream support. */ +#if !defined(EXCLUDE_JPC_CAPABILITY) +/* Format-dependent operations for JPEG-2000 code stream capability. */ jas_image_t *jpc_decode(jas_stream_t *in, char *optstr); int jpc_encode(jas_image_t *image, jas_stream_t *out, char *optstr); int jpc_validate(jas_stream_t *in); #endif -#if !defined(EXCLUDE_PGX_SUPPORT) -/* Format-dependent operations for PGX support. */ +#if !defined(EXCLUDE_PGX_CAPABILITY) +/* Format-dependent operations for PGX capability. */ jas_image_t *pgx_decode(jas_stream_t *in, char *optstr); int pgx_encode(jas_image_t *image, jas_stream_t *out, char *optstr); int pgx_validate(jas_stream_t *in); diff --git a/converter/other/jpeg2000/libjasper/include/jasper/jas_types.h b/converter/other/jpeg2000/libjasper/include/jasper/jas_types.h index 4d3a4988..fbcb2ffb 100644 --- a/converter/other/jpeg2000/libjasper/include/jasper/jas_types.h +++ b/converter/other/jpeg2000/libjasper/include/jasper/jas_types.h @@ -4,7 +4,7 @@ In Netpbm, we do that with pm_config.h, and the original Jasper method doesn't work. */ -#include "pm_config.h" +#include "netpbm/pm_config.h" /* The below macro is intended to be used for type casts. By using this diff --git a/converter/other/jpeg2000/libjasper/include/jasper/jas_types.h.orig b/converter/other/jpeg2000/libjasper/include/jasper/jas_types.h.orig deleted file mode 100644 index 10c1152d..00000000 --- a/converter/other/jpeg2000/libjasper/include/jasper/jas_types.h.orig +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (c) 1999-2000 Image Power, Inc. and the University of - * British Columbia. - * Copyright (c) 2001-2002 Michael David Adams. - * All rights reserved. - */ - -/* __START_OF_JASPER_LICENSE__ - * - * JasPer Software License - * - * IMAGE POWER JPEG-2000 PUBLIC LICENSE - * ************************************ - * - * GRANT: - * - * Permission is hereby granted, free of charge, to any person (the "User") - * obtaining a copy of this software and associated documentation, to deal - * in the JasPer Software without restriction, including without limitation - * the right to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the JasPer Software (in source and binary forms), - * and to permit persons to whom the JasPer Software is furnished to do so, - * provided further that the License Conditions below are met. - * - * License Conditions - * ****************** - * - * A. Redistributions of source code must retain the above copyright notice, - * and this list of conditions, and the following disclaimer. - * - * B. Redistributions in binary form must reproduce the above copyright - * notice, and this list of conditions, and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * C. Neither the name of Image Power, Inc. nor any other contributor - * (including, but not limited to, the University of British Columbia and - * Michael David Adams) may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * D. User agrees that it shall not commence any action against Image Power, - * Inc., the University of British Columbia, Michael David Adams, or any - * other contributors (collectively "Licensors") for infringement of any - * intellectual property rights ("IPR") held by the User in respect of any - * technology that User owns or has a right to license or sublicense and - * which is an element required in order to claim compliance with ISO/IEC - * 15444-1 (i.e., JPEG-2000 Part 1). "IPR" means all intellectual property - * rights worldwide arising under statutory or common law, and whether - * or not perfected, including, without limitation, all (i) patents and - * patent applications owned or licensable by User; (ii) rights associated - * with works of authorship including copyrights, copyright applications, - * copyright registrations, mask work rights, mask work applications, - * mask work registrations; (iii) rights relating to the protection of - * trade secrets and confidential information; (iv) any right analogous - * to those set forth in subsections (i), (ii), or (iii) and any other - * proprietary rights relating to intangible property (other than trademark, - * trade dress, or service mark rights); and (v) divisions, continuations, - * renewals, reissues and extensions of the foregoing (as and to the extent - * applicable) now existing, hereafter filed, issued or acquired. - * - * E. If User commences an infringement action against any Licensor(s) then - * such Licensor(s) shall have the right to terminate User's license and - * all sublicenses that have been granted hereunder by User to other parties. - * - * F. This software is for use only in hardware or software products that - * are compliant with ISO/IEC 15444-1 (i.e., JPEG-2000 Part 1). No license - * or right to this Software is granted for products that do not comply - * with ISO/IEC 15444-1. The JPEG-2000 Part 1 standard can be purchased - * from the ISO. - * - * THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. - * NO USE OF THE JASPER SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER - * THIS DISCLAIMER. THE JASPER SOFTWARE IS PROVIDED BY THE LICENSORS AND - * CONTRIBUTORS UNDER THIS LICENSE ON AN ``AS-IS'' BASIS, WITHOUT WARRANTY - * OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, - * WARRANTIES THAT THE JASPER SOFTWARE IS FREE OF DEFECTS, IS MERCHANTABLE, - * IS FIT FOR A PARTICULAR PURPOSE OR IS NON-INFRINGING. THOSE INTENDING - * TO USE THE JASPER SOFTWARE OR MODIFICATIONS THEREOF FOR USE IN HARDWARE - * OR SOFTWARE PRODUCTS ARE ADVISED THAT THEIR USE MAY INFRINGE EXISTING - * PATENTS, COPYRIGHTS, TRADEMARKS, OR OTHER INTELLECTUAL PROPERTY RIGHTS. - * THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE JASPER SOFTWARE - * IS WITH THE USER. SHOULD ANY PART OF THE JASPER SOFTWARE PROVE DEFECTIVE - * IN ANY RESPECT, THE USER (AND NOT THE INITIAL DEVELOPERS, THE UNIVERSITY - * OF BRITISH COLUMBIA, IMAGE POWER, INC., MICHAEL DAVID ADAMS, OR ANY - * OTHER CONTRIBUTOR) SHALL ASSUME THE COST OF ANY NECESSARY SERVICING, - * REPAIR OR CORRECTION. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, - * WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL THE - * INITIAL DEVELOPER, THE UNIVERSITY OF BRITISH COLUMBIA, IMAGE POWER, INC., - * MICHAEL DAVID ADAMS, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF THE - * JASPER SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO - * THE USER OR ANY OTHER PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR - * CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, - * DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR - * MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF - * SUCH PARTY HAD BEEN INFORMED, OR OUGHT TO HAVE KNOWN, OF THE POSSIBILITY - * OF SUCH DAMAGES. THE JASPER SOFTWARE AND UNDERLYING TECHNOLOGY ARE NOT - * FAULT-TOLERANT AND ARE NOT DESIGNED, MANUFACTURED OR INTENDED FOR USE OR - * RESALE AS ON-LINE CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING - * FAIL-SAFE PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, - * AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT - * LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE - * JASPER SOFTWARE OR UNDERLYING TECHNOLOGY OR PRODUCT COULD LEAD DIRECTLY - * TO DEATH, PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE - * ("HIGH RISK ACTIVITIES"). LICENSOR SPECIFICALLY DISCLAIMS ANY EXPRESS - * OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES. USER WILL NOT - * KNOWINGLY USE, DISTRIBUTE OR RESELL THE JASPER SOFTWARE OR UNDERLYING - * TECHNOLOGY OR PRODUCTS FOR HIGH RISK ACTIVITIES AND WILL ENSURE THAT ITS - * CUSTOMERS AND END-USERS OF ITS PRODUCTS ARE PROVIDED WITH A COPY OF THE - * NOTICE SPECIFIED IN THIS SECTION. - * - * __END_OF_JASPER_LICENSE__ - */ - -/* - * Primitive Types - * - * $Id$ - */ - -#ifndef JAS_TYPES_H -#define JAS_TYPES_H - -#if defined(HAVE_STDLIB_H) -#include -#endif -#if defined(HAVE_STDDEF_H) -#include -#endif -#if defined(HAVE_SYS_TYPES_H) -#include -#endif - -#if defined(HAVE_STDBOOL_H) -/* - * The C language implementation does correctly provide the standard header - * file "stdbool.h". - */ -#include -#else - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * The C language implementation does not provide the standard header file - * "stdbool.h" as required by ISO/IEC 9899:1999. Try to compensate for this - * braindamage below. - */ -#if !defined(bool) -#define bool int -#endif -#if !defined(true) -#define true 1 -#endif -#if !defined(false) -#define false 0 -#endif - -#ifdef __cplusplus -} -#endif - -/* pm_config.h defines the FAST integer types if possible (typically by - including . If not, the following try to take care - of it. -*/ -/**********/ -#if !defined(INT_FAST8_MAX) -typedef signed char int_fast8_t; -#define INT_FAST8_MIN (-127) -#define INT_FAST8_MAX 128 -#endif -/**********/ -#if !defined(UINT_FAST8_MAX) -typedef unsigned char uint_fast8_t; -#define UINT_FAST8_MAX 255 -#endif -/**********/ -#if !defined(INT_FAST16_MAX) -typedef short int_fast16_t; -#define INT_FAST16_MIN SHRT_MIN -#define INT_FAST16_MAX SHRT_MAX -#endif -/**********/ -#if !defined(UINT_FAST16_MAX) -typedef unsigned short uint_fast16_t; -#define UINT_FAST16_MAX USHRT_MAX -#endif -/**********/ -#if !defined(INT_FAST32_MAX) -typedef int int_fast32_t; -#define INT_FAST32_MIN INT_MIN -#define INT_FAST32_MAX INT_MAX -#endif -/**********/ -#if !defined(UINT_FAST32_MAX) -typedef unsigned int uint_fast32_t; -#define UINT_FAST32_MAX UINT_MAX -#endif -/**********/ -#if !defined(INT_FAST64_MAX) -typedef int int_fast64_t; -#define INT_FAST64_MIN LLONG_MIN -#define INT_FAST64_MAX LLONG_MAX -#endif -/**********/ -#if !defined(UINT_FAST64_MAX) -typedef unsigned int uint_fast64_t; -#define UINT_FAST64_MAX ULLONG_MAX -#endif -/**********/ -#endif - -/* The below macro is intended to be used for type casts. By using this - macro, type casts can be easily located in the source code with - tools like "grep". */ -#define JAS_CAST(t, e) \ - ((t) (e)) - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/converter/other/jpeg2000/libjasper/jp2/jp2_cod.c b/converter/other/jpeg2000/libjasper/jp2/jp2_cod.c index 4769c408..c99c9608 100644 --- a/converter/other/jpeg2000/libjasper/jp2/jp2_cod.c +++ b/converter/other/jpeg2000/libjasper/jp2/jp2_cod.c @@ -123,7 +123,7 @@ #include #include -#include "pm_c_util.h" +#include "netpbm/pm_c_util.h" #include "jasper/jas_stream.h" #include "jasper/jas_malloc.h" @@ -135,7 +135,7 @@ * Function prototypes. \******************************************************************************/ -#define ONES(n) ((1 << (n)) - 1) +#define ONES(n) ((1 << (n)) - 1) jp2_boxinfo_t *jp2_boxinfolookup(int type); @@ -183,49 +183,49 @@ static void jp2_pclr_dumpdata(jp2_box_t *box, FILE *out); \******************************************************************************/ jp2_boxinfo_t jp2_boxinfos[] = { - {JP2_BOX_JP, "JP", 0, - {0, 0, jp2_jp_getdata, jp2_jp_putdata, 0}}, - {JP2_BOX_FTYP, "FTYP", 0, - {0, 0, jp2_ftyp_getdata, jp2_ftyp_putdata, 0}}, - {JP2_BOX_JP2H, "JP2H", JP2_BOX_SUPER, - {0, 0, 0, 0, 0}}, - {JP2_BOX_IHDR, "IHDR", 0, - {0, 0, jp2_ihdr_getdata, jp2_ihdr_putdata, 0}}, - {JP2_BOX_BPCC, "BPCC", 0, - {0, jp2_bpcc_destroy, jp2_bpcc_getdata, jp2_bpcc_putdata, 0}}, - {JP2_BOX_COLR, "COLR", 0, - {0, jp2_colr_destroy, jp2_colr_getdata, jp2_colr_putdata, jp2_colr_dumpdata}}, - {JP2_BOX_PCLR, "PCLR", 0, - {0, jp2_pclr_destroy, jp2_pclr_getdata, jp2_pclr_putdata, jp2_pclr_dumpdata}}, - {JP2_BOX_CMAP, "CMAP", 0, - {0, jp2_cmap_destroy, jp2_cmap_getdata, jp2_cmap_putdata, jp2_cmap_dumpdata}}, - {JP2_BOX_CDEF, "CDEF", 0, - {0, jp2_cdef_destroy, jp2_cdef_getdata, jp2_cdef_putdata, jp2_cdef_dumpdata}}, - {JP2_BOX_RES, "RES", JP2_BOX_SUPER, - {0, 0, 0, 0, 0}}, - {JP2_BOX_RESC, "RESC", 0, - {0, 0, 0, 0, 0}}, - {JP2_BOX_RESD, "RESD", 0, - {0, 0, 0, 0, 0}}, - {JP2_BOX_JP2C, "JP2C", JP2_BOX_NODATA, - {0, 0, 0, 0, 0}}, - {JP2_BOX_JP2I, "JP2I", 0, - {0, 0, 0, 0, 0}}, - {JP2_BOX_XML, "XML", 0, - {0, 0, 0, 0, 0}}, - {JP2_BOX_UUID, "UUID", 0, - {0, 0, 0, 0, 0}}, - {JP2_BOX_UINF, "UINF", JP2_BOX_SUPER, - {0, 0, 0, 0, 0}}, - {JP2_BOX_ULST, "ULST", 0, - {0, 0, 0, 0, 0}}, - {JP2_BOX_URL, "URL", 0, - {0, 0, 0, 0, 0}}, - {0, 0, 0, {0, 0, 0, 0, 0}}, + {JP2_BOX_JP, "JP", 0, + {0, 0, jp2_jp_getdata, jp2_jp_putdata, 0}}, + {JP2_BOX_FTYP, "FTYP", 0, + {0, 0, jp2_ftyp_getdata, jp2_ftyp_putdata, 0}}, + {JP2_BOX_JP2H, "JP2H", JP2_BOX_SUPER, + {0, 0, 0, 0, 0}}, + {JP2_BOX_IHDR, "IHDR", 0, + {0, 0, jp2_ihdr_getdata, jp2_ihdr_putdata, 0}}, + {JP2_BOX_BPCC, "BPCC", 0, + {0, jp2_bpcc_destroy, jp2_bpcc_getdata, jp2_bpcc_putdata, 0}}, + {JP2_BOX_COLR, "COLR", 0, + {0, jp2_colr_destroy, jp2_colr_getdata, jp2_colr_putdata, jp2_colr_dumpdata}}, + {JP2_BOX_PCLR, "PCLR", 0, + {0, jp2_pclr_destroy, jp2_pclr_getdata, jp2_pclr_putdata, jp2_pclr_dumpdata}}, + {JP2_BOX_CMAP, "CMAP", 0, + {0, jp2_cmap_destroy, jp2_cmap_getdata, jp2_cmap_putdata, jp2_cmap_dumpdata}}, + {JP2_BOX_CDEF, "CDEF", 0, + {0, jp2_cdef_destroy, jp2_cdef_getdata, jp2_cdef_putdata, jp2_cdef_dumpdata}}, + {JP2_BOX_RES, "RES", JP2_BOX_SUPER, + {0, 0, 0, 0, 0}}, + {JP2_BOX_RESC, "RESC", 0, + {0, 0, 0, 0, 0}}, + {JP2_BOX_RESD, "RESD", 0, + {0, 0, 0, 0, 0}}, + {JP2_BOX_JP2C, "JP2C", JP2_BOX_NODATA, + {0, 0, 0, 0, 0}}, + {JP2_BOX_JP2I, "JP2I", 0, + {0, 0, 0, 0, 0}}, + {JP2_BOX_XML, "XML", 0, + {0, 0, 0, 0, 0}}, + {JP2_BOX_UUID, "UUID", 0, + {0, 0, 0, 0, 0}}, + {JP2_BOX_UINF, "UINF", JP2_BOX_SUPER, + {0, 0, 0, 0, 0}}, + {JP2_BOX_ULST, "ULST", 0, + {0, 0, 0, 0, 0}}, + {JP2_BOX_URL, "URL", 0, + {0, 0, 0, 0, 0}}, + {0, 0, 0, {0, 0, 0, 0, 0}}, }; jp2_boxinfo_t jp2_boxinfo_unk = { - 0, "Unknown", 0, {0, 0, 0, 0} + 0, "Unknown", 0, {0, 0, 0, 0} }; /******************************************************************************\ @@ -234,21 +234,21 @@ jp2_boxinfo_t jp2_boxinfo_unk = { jp2_box_t *jp2_box_create(int type) { - jp2_box_t *box; - jp2_boxinfo_t *boxinfo; + jp2_box_t *box; + jp2_boxinfo_t *boxinfo; - if (!(box = jas_malloc(sizeof(jp2_box_t)))) { - return 0; - } - memset(box, 0, sizeof(jp2_box_t)); - box->type = type; - box->len = 0; - if (!(boxinfo = jp2_boxinfolookup(type))) { - return 0; - } - box->info = boxinfo; - box->ops = &boxinfo->ops; - return box; + if (!(box = jas_malloc(sizeof(jp2_box_t)))) { + return 0; + } + memset(box, 0, sizeof(jp2_box_t)); + box->type = type; + box->len = 0; + if (!(boxinfo = jp2_boxinfolookup(type))) { + return 0; + } + box->info = boxinfo; + box->ops = &boxinfo->ops; + return box; } /******************************************************************************\ @@ -257,28 +257,28 @@ jp2_box_t *jp2_box_create(int type) void jp2_box_destroy(jp2_box_t *box) { - if (box->ops->destroy) { - (*box->ops->destroy)(box); - } - jas_free(box); + if (box->ops->destroy) { + (*box->ops->destroy)(box); + } + jas_free(box); } static void jp2_bpcc_destroy(jp2_box_t *box) { - jp2_bpcc_t *bpcc = &box->data.bpcc; - if (bpcc->bpcs) { - jas_free(bpcc->bpcs); - bpcc->bpcs = 0; - } + jp2_bpcc_t *bpcc = &box->data.bpcc; + if (bpcc->bpcs) { + jas_free(bpcc->bpcs); + bpcc->bpcs = 0; + } } static void jp2_cdef_destroy(jp2_box_t *box) { - jp2_cdef_t *cdef = &box->data.cdef; - if (cdef->ents) { - jas_free(cdef->ents); - cdef->ents = 0; - } + jp2_cdef_t *cdef = &box->data.cdef; + if (cdef->ents) { + jas_free(cdef->ents); + cdef->ents = 0; + } } /******************************************************************************\ @@ -287,222 +287,224 @@ static void jp2_cdef_destroy(jp2_box_t *box) jp2_box_t *jp2_box_get(jas_stream_t *in) { - jp2_box_t *box; - jp2_boxinfo_t *boxinfo; - jas_stream_t *tmpstream; - uint_fast32_t len; + jp2_box_t *box; + jp2_boxinfo_t *boxinfo; + jas_stream_t *tmpstream; + uint_fast32_t len; uint_fast64_t extlen; - bool dataflag; - - box = 0; - tmpstream = 0; - - if (!(box = jas_malloc(sizeof(jp2_box_t)))) { - goto error; - } - box->ops = &jp2_boxinfo_unk.ops; - if (jp2_getuint32(in, &len) || jp2_getuint32(in, &box->type)) { - goto error; - } - boxinfo = jp2_boxinfolookup(box->type); - box->info = boxinfo; - box->ops = &boxinfo->ops; - box->len = len; - if (box->len == 1) { - if (jp2_getuint64(in, &extlen)) { - goto error; - } - box->len = extlen; - } - if (box->len != 0 && box->len < 8) { - goto error; - } - - dataflag = !(box->info->flags & (JP2_BOX_SUPER | JP2_BOX_NODATA)); - - if (dataflag) { - if (!(tmpstream = jas_stream_memopen(0, 0))) { - goto error; - } - if (jas_stream_copy(tmpstream, in, box->len - JP2_BOX_HDRLEN)) { - goto error; - } - jas_stream_rewind(tmpstream); - - if (box->ops->getdata) { - if ((*box->ops->getdata)(box, tmpstream)) { - goto error; - } - } - jas_stream_close(tmpstream); - } - - jp2_box_dump(box, stderr); - - return box; - abort(); + bool dataflag; + + box = 0; + tmpstream = 0; + + if (!(box = jas_malloc(sizeof(jp2_box_t)))) { + goto error; + } + box->ops = &jp2_boxinfo_unk.ops; + if (jp2_getuint32(in, &len) || jp2_getuint32(in, &box->type)) { + goto error; + } + boxinfo = jp2_boxinfolookup(box->type); + box->info = boxinfo; + box->ops = &boxinfo->ops; + box->len = len; + if (box->len == 1) { + if (jp2_getuint64(in, &extlen)) { + goto error; + } + box->len = extlen; + } + if (box->len != 0 && box->len < 8) { + goto error; + } + + dataflag = !(box->info->flags & (JP2_BOX_SUPER | JP2_BOX_NODATA)); + + if (dataflag) { + if (!(tmpstream = jas_stream_memopen(0, 0))) { + goto error; + } + if (jas_stream_copy(tmpstream, in, box->len - JP2_BOX_HDRLEN)) { + goto error; + } + jas_stream_rewind(tmpstream); + + if (box->ops->getdata) { + if ((*box->ops->getdata)(box, tmpstream)) { + goto error; + } + } + jas_stream_close(tmpstream); + } + + if (jas_getdbglevel() > 0) { + jp2_box_dump(box, stderr); + } + return box; + abort(); error: - if (box) { - jp2_box_destroy(box); - } - if (tmpstream) { - jas_stream_close(tmpstream); - } - return 0; + if (box) { + jp2_box_destroy(box); + } + if (tmpstream) { + jas_stream_close(tmpstream); + } + return 0; } void jp2_box_dump(jp2_box_t *box, FILE *out) { - jp2_boxinfo_t *boxinfo; - boxinfo = jp2_boxinfolookup(box->type); - assert(boxinfo); + jp2_boxinfo_t *boxinfo; + boxinfo = jp2_boxinfolookup(box->type); + assert(boxinfo); - fprintf(out, "JP2 box: "); - fprintf(out, "type=%c%s%c (0x%08x); length=%d\n", '"', boxinfo->name, - '"', box->type, box->len); - if (box->ops->dumpdata) { - (*box->ops->dumpdata)(box, out); - } + fprintf(out, "JP2 box: "); + fprintf(out, "type=%c%s%c (0x%08x); length=%d\n", '"', boxinfo->name, + '"', (unsigned int) box->type, (int)box->len); + if (box->ops->dumpdata) { + (*box->ops->dumpdata)(box, out); + } } static int jp2_jp_getdata(jp2_box_t *box, jas_stream_t *in) { - jp2_jp_t *jp = &box->data.jp; - if (jp2_getuint32(in, &jp->magic)) { - return -1; - } - return 0; + jp2_jp_t *jp = &box->data.jp; + if (jp2_getuint32(in, &jp->magic)) { + return -1; + } + return 0; } static int jp2_ftyp_getdata(jp2_box_t *box, jas_stream_t *in) { - jp2_ftyp_t *ftyp = &box->data.ftyp; - int i; - if (jp2_getuint32(in, &ftyp->majver) || jp2_getuint32(in, &ftyp->minver)) { - return -1; - } - ftyp->numcompatcodes = ((box->len - JP2_BOX_HDRLEN) - 8) / 4; - if (ftyp->numcompatcodes > JP2_FTYP_MAXCOMPATCODES) { - return -1; - } - for (i = 0; i < ftyp->numcompatcodes; ++i) { - if (jp2_getuint32(in, &ftyp->compatcodes[i])) { - return -1; - } - } - return 0; + jp2_ftyp_t *ftyp = &box->data.ftyp; + int i; + if (jp2_getuint32(in, &ftyp->majver) || jp2_getuint32(in, &ftyp->minver)) { + return -1; + } + ftyp->numcompatcodes = ((box->len - JP2_BOX_HDRLEN) - 8) / 4; + if (ftyp->numcompatcodes > JP2_FTYP_MAXCOMPATCODES) { + return -1; + } + for (i = 0; i < ftyp->numcompatcodes; ++i) { + if (jp2_getuint32(in, &ftyp->compatcodes[i])) { + return -1; + } + } + return 0; } static int jp2_ihdr_getdata(jp2_box_t *box, jas_stream_t *in) { - jp2_ihdr_t *ihdr = &box->data.ihdr; - if (jp2_getuint32(in, &ihdr->height) || jp2_getuint32(in, &ihdr->width) || - jp2_getuint16(in, &ihdr->numcmpts) || jp2_getuint8(in, &ihdr->bpc) || - jp2_getuint8(in, &ihdr->comptype) || jp2_getuint8(in, &ihdr->csunk) || - jp2_getuint8(in, &ihdr->ipr)) { - return -1; - } - return 0; + jp2_ihdr_t *ihdr = &box->data.ihdr; + if (jp2_getuint32(in, &ihdr->height) || jp2_getuint32(in, &ihdr->width) || + jp2_getuint16(in, &ihdr->numcmpts) || jp2_getuint8(in, &ihdr->bpc) || + jp2_getuint8(in, &ihdr->comptype) || jp2_getuint8(in, &ihdr->csunk) || + jp2_getuint8(in, &ihdr->ipr)) { + return -1; + } + return 0; } static int jp2_bpcc_getdata(jp2_box_t *box, jas_stream_t *in) { - jp2_bpcc_t *bpcc = &box->data.bpcc; - int i; - bpcc->numcmpts = box->len - JP2_BOX_HDRLEN; - if (!(bpcc->bpcs = jas_malloc(bpcc->numcmpts * sizeof(uint_fast8_t)))) { - return -1; - } - for (i = 0; i < bpcc->numcmpts; ++i) { - if (jp2_getuint8(in, &bpcc->bpcs[i])) { - return -1; - } - } - return 0; + jp2_bpcc_t *bpcc = &box->data.bpcc; + int i; + bpcc->numcmpts = box->len - JP2_BOX_HDRLEN; + if (!(bpcc->bpcs = jas_malloc(bpcc->numcmpts * sizeof(uint_fast8_t)))) { + return -1; + } + for (i = 0; i < bpcc->numcmpts; ++i) { + if (jp2_getuint8(in, &bpcc->bpcs[i])) { + return -1; + } + } + return 0; } static void jp2_colr_dumpdata(jp2_box_t *box, FILE *out) { - jp2_colr_t *colr = &box->data.colr; - fprintf(out, "method=%d; pri=%d; approx=%d\n", (int)colr->method, (int)colr->pri, (int)colr->approx); - switch (colr->method) { - case JP2_COLR_ENUM: - fprintf(out, "csid=%d\n", (int)colr->csid); - break; - case JP2_COLR_ICC: - jas_memdump(out, colr->iccp, colr->iccplen); - break; - } + jp2_colr_t *colr = &box->data.colr; + fprintf(out, "method=%d; pri=%d; approx=%d\n", (int)colr->method, (int)colr->pri, (int)colr->approx); + switch (colr->method) { + case JP2_COLR_ENUM: + fprintf(out, "csid=%d\n", (int)colr->csid); + break; + case JP2_COLR_ICC: + jas_memdump(out, colr->iccp, colr->iccplen); + break; + } } static int jp2_colr_getdata(jp2_box_t *box, jas_stream_t *in) { - jp2_colr_t *colr = &box->data.colr; - colr->csid = 0; - colr->iccp = 0; - colr->iccplen = 0; - - if (jp2_getuint8(in, &colr->method) || jp2_getuint8(in, &colr->pri) || - jp2_getuint8(in, &colr->approx)) { - return -1; - } - switch (colr->method) { - case JP2_COLR_ENUM: - if (jp2_getuint32(in, &colr->csid)) { - return -1; - } - break; - case JP2_COLR_ICC: - colr->iccplen = box->len - JP2_BOX_HDRLEN - 3; - if (!(colr->iccp = jas_malloc(colr->iccplen * sizeof(uint_fast8_t)))) { - return -1; - } - if (jas_stream_read(in, colr->iccp, colr->iccplen) != colr->iccplen) { - return -1; - } - break; - } - return 0; + jp2_colr_t *colr = &box->data.colr; + colr->csid = 0; + colr->iccp = 0; + colr->iccplen = 0; + + if (jp2_getuint8(in, &colr->method) || jp2_getuint8(in, &colr->pri) || + jp2_getuint8(in, &colr->approx)) { + return -1; + } + switch (colr->method) { + case JP2_COLR_ENUM: + if (jp2_getuint32(in, &colr->csid)) { + return -1; + } + break; + case JP2_COLR_ICC: + colr->iccplen = box->len - JP2_BOX_HDRLEN - 3; + if (!(colr->iccp = jas_malloc(colr->iccplen * sizeof(uint_fast8_t)))) { + return -1; + } + if (jas_stream_read(in, colr->iccp, colr->iccplen) != colr->iccplen) { + return -1; + } + break; + } + return 0; } static void jp2_cdef_dumpdata(jp2_box_t *box, FILE *out) { - jp2_cdef_t *cdef = &box->data.cdef; - int i; - for (i = 0; i < cdef->numchans; ++i) { - fprintf(out, "channo=%d; type=%d; assoc=%d\n", - cdef->ents[i].channo, cdef->ents[i].type, cdef->ents[i].assoc); - } + jp2_cdef_t *cdef = &box->data.cdef; + int i; + for (i = 0; i < cdef->numchans; ++i) { + fprintf(out, "channo=%d; type=%d; assoc=%d\n", + (int)cdef->ents[i].channo, (int)cdef->ents[i].type, + (int)cdef->ents[i].assoc); + } } static void jp2_colr_destroy(jp2_box_t *box) { - jp2_colr_t *colr = &box->data.colr; - if (colr->iccp) { - free(colr->iccp); - } + jp2_colr_t *colr = &box->data.colr; + if (colr->iccp) { + free(colr->iccp); + } } static int jp2_cdef_getdata(jp2_box_t *box, jas_stream_t *in) { - jp2_cdef_t *cdef = &box->data.cdef; - jp2_cdefchan_t *chan; - int channo; - if (jp2_getuint16(in, &cdef->numchans)) { - return -1; - } - if (!(cdef->ents = jas_malloc(cdef->numchans * sizeof(jp2_cdefchan_t)))) { - return -1; - } - for (channo = 0; channo < cdef->numchans; ++channo) { - chan = &cdef->ents[channo]; - if (jp2_getuint16(in, &chan->channo) || jp2_getuint16(in, &chan->type) || - jp2_getuint16(in, &chan->assoc)) { - return -1; - } - } - return 0; + jp2_cdef_t *cdef = &box->data.cdef; + jp2_cdefchan_t *chan; + int channo; + if (jp2_getuint16(in, &cdef->numchans)) { + return -1; + } + if (!(cdef->ents = jas_malloc(cdef->numchans * sizeof(jp2_cdefchan_t)))) { + return -1; + } + for (channo = 0; channo < cdef->numchans; ++channo) { + chan = &cdef->ents[channo]; + if (jp2_getuint16(in, &chan->channo) || jp2_getuint16(in, &chan->type) || + jp2_getuint16(in, &chan->assoc)) { + return -1; + } + } + return 0; } /******************************************************************************\ @@ -511,23 +513,23 @@ static int jp2_cdef_getdata(jp2_box_t *box, jas_stream_t *in) int jp2_box_put(jp2_box_t *box, jas_stream_t *out) { - jas_stream_t *tmpstream; - bool dataflag; + jas_stream_t *tmpstream; + bool dataflag; - tmpstream = 0; + tmpstream = 0; - dataflag = !(box->info->flags & (JP2_BOX_SUPER | JP2_BOX_NODATA)); + dataflag = !(box->info->flags & (JP2_BOX_SUPER | JP2_BOX_NODATA)); - if (dataflag) { - tmpstream = jas_stream_memopen(0, 0); - if (box->ops->putdata) { - if ((*box->ops->putdata)(box, tmpstream)) { - goto error; - } - } - box->len = jas_stream_tell(tmpstream) + JP2_BOX_HDRLEN; - jas_stream_rewind(tmpstream); - } + if (dataflag) { + tmpstream = jas_stream_memopen(0, 0); + if (box->ops->putdata) { + if ((*box->ops->putdata)(box, tmpstream)) { + goto error; + } + } + box->len = jas_stream_tell(tmpstream) + JP2_BOX_HDRLEN; + jas_stream_rewind(tmpstream); + } /* There was code here in official Jasper to handle 64 bit lengths, but it was based on determining whether box->len fits in 32 bits. But box->len is a 32 bit data type, so it fits in 32 bits by @@ -535,119 +537,119 @@ int jp2_box_put(jp2_box_t *box, jas_stream_t *out) lengths that don't fit in 32 bits, or it passes invalid values of box->len to us. We assume the former because it's easier. */ - if (jp2_putuint32(out, box->len)) { - goto error; - } - if (jp2_putuint32(out, box->type)) { - goto error; - } - - if (dataflag) { - if (jas_stream_copy(out, tmpstream, box->len - JP2_BOX_HDRLEN)) { - goto error; - } - jas_stream_close(tmpstream); - } - - return 0; - abort(); + if (jp2_putuint32(out, box->len)) { + goto error; + } + if (jp2_putuint32(out, box->type)) { + goto error; + } + + if (dataflag) { + if (jas_stream_copy(out, tmpstream, box->len - JP2_BOX_HDRLEN)) { + goto error; + } + jas_stream_close(tmpstream); + } + + return 0; + abort(); error: - if (tmpstream) { - jas_stream_close(tmpstream); - } - return -1; + if (tmpstream) { + jas_stream_close(tmpstream); + } + return -1; } static int jp2_jp_putdata(jp2_box_t *box, jas_stream_t *out) { - jp2_jp_t *jp = &box->data.jp; - if (jp2_putuint32(out, jp->magic)) { - return -1; - } - return 0; + jp2_jp_t *jp = &box->data.jp; + if (jp2_putuint32(out, jp->magic)) { + return -1; + } + return 0; } static int jp2_ftyp_putdata(jp2_box_t *box, jas_stream_t *out) { - jp2_ftyp_t *ftyp = &box->data.ftyp; - int i; - if (jp2_putuint32(out, ftyp->majver) || jp2_putuint32(out, ftyp->minver)) { - return -1; - } - for (i = 0; i < ftyp->numcompatcodes; ++i) { - if (jp2_putuint32(out, ftyp->compatcodes[i])) { - return -1; - } - } - return 0; + jp2_ftyp_t *ftyp = &box->data.ftyp; + int i; + if (jp2_putuint32(out, ftyp->majver) || jp2_putuint32(out, ftyp->minver)) { + return -1; + } + for (i = 0; i < ftyp->numcompatcodes; ++i) { + if (jp2_putuint32(out, ftyp->compatcodes[i])) { + return -1; + } + } + return 0; } static int jp2_ihdr_putdata(jp2_box_t *box, jas_stream_t *out) { - jp2_ihdr_t *ihdr = &box->data.ihdr; - if (jp2_putuint32(out, ihdr->height) || jp2_putuint32(out, ihdr->width) || - jp2_putuint16(out, ihdr->numcmpts) || jp2_putuint8(out, ihdr->bpc) || - jp2_putuint8(out, ihdr->comptype) || jp2_putuint8(out, ihdr->csunk) || - jp2_putuint8(out, ihdr->ipr)) { - return -1; - } - return 0; + jp2_ihdr_t *ihdr = &box->data.ihdr; + if (jp2_putuint32(out, ihdr->height) || jp2_putuint32(out, ihdr->width) || + jp2_putuint16(out, ihdr->numcmpts) || jp2_putuint8(out, ihdr->bpc) || + jp2_putuint8(out, ihdr->comptype) || jp2_putuint8(out, ihdr->csunk) || + jp2_putuint8(out, ihdr->ipr)) { + return -1; + } + return 0; } static int jp2_bpcc_putdata(jp2_box_t *box, jas_stream_t *out) { - jp2_bpcc_t *bpcc = &box->data.bpcc; - int i; - for (i = 0; i < bpcc->numcmpts; ++i) { - if (jp2_putuint8(out, bpcc->bpcs[i])) { - return -1; - } - } - return 0; + jp2_bpcc_t *bpcc = &box->data.bpcc; + int i; + for (i = 0; i < bpcc->numcmpts; ++i) { + if (jp2_putuint8(out, bpcc->bpcs[i])) { + return -1; + } + } + return 0; } static int jp2_colr_putdata(jp2_box_t *box, jas_stream_t *out) { - jp2_colr_t *colr = &box->data.colr; - if (jp2_putuint8(out, colr->method) || jp2_putuint8(out, colr->pri) || - jp2_putuint8(out, colr->approx)) { - return -1; - } - switch (colr->method) { - case JP2_COLR_ENUM: - if (jp2_putuint32(out, colr->csid)) { - return -1; - } - break; - case JP2_COLR_ICC: - /* XXX - not implemented */ - abort(); - break; - } - return 0; + jp2_colr_t *colr = &box->data.colr; + if (jp2_putuint8(out, colr->method) || jp2_putuint8(out, colr->pri) || + jp2_putuint8(out, colr->approx)) { + return -1; + } + switch (colr->method) { + case JP2_COLR_ENUM: + if (jp2_putuint32(out, colr->csid)) { + return -1; + } + break; + case JP2_COLR_ICC: + /* XXX - not implemented */ + abort(); + break; + } + return 0; } static int jp2_cdef_putdata(jp2_box_t *box, jas_stream_t *out) { - jp2_cdef_t *cdef = &box->data.cdef; - int i; - jp2_cdefchan_t *ent; + jp2_cdef_t *cdef = &box->data.cdef; + int i; + jp2_cdefchan_t *ent; - if (jp2_putuint16(out, cdef->numchans)) { - return -1; - } + if (jp2_putuint16(out, cdef->numchans)) { + return -1; + } - for (i = 0; i < cdef->numchans; ++i) { - ent = &cdef->ents[i]; - if (jp2_putuint16(out, ent->channo) || - jp2_putuint16(out, ent->type) || - jp2_putuint16(out, ent->assoc)) { - return -1; - } - } - return 0; + for (i = 0; i < cdef->numchans; ++i) { + ent = &cdef->ents[i]; + if (jp2_putuint16(out, ent->channo) || + jp2_putuint16(out, ent->type) || + jp2_putuint16(out, ent->assoc)) { + return -1; + } + } + return 0; } /******************************************************************************\ @@ -656,63 +658,63 @@ static int jp2_cdef_putdata(jp2_box_t *box, jas_stream_t *out) static int jp2_getuint8(jas_stream_t *in, uint_fast8_t *val) { - int c; - if ((c = jas_stream_getc(in)) == EOF) { - return -1; - } - if (val) { - *val = c; - } - return 0; + int c; + if ((c = jas_stream_getc(in)) == EOF) { + return -1; + } + if (val) { + *val = c; + } + return 0; } static int jp2_getuint16(jas_stream_t *in, uint_fast16_t *val) { - uint_fast16_t v; - int c; - if ((c = jas_stream_getc(in)) == EOF) { - return -1; - } - v = c; - if ((c = jas_stream_getc(in)) == EOF) { - return -1; - } - v = (v << 8) | c; - if (val) { - *val = v; - } - return 0; + uint_fast16_t v; + int c; + if ((c = jas_stream_getc(in)) == EOF) { + return -1; + } + v = c; + if ((c = jas_stream_getc(in)) == EOF) { + return -1; + } + v = (v << 8) | c; + if (val) { + *val = v; + } + return 0; } static int jp2_getuint32(jas_stream_t *in, uint_fast32_t *val) { - uint_fast32_t v; - int c; - if ((c = jas_stream_getc(in)) == EOF) { - return -1; - } - v = c; - if ((c = jas_stream_getc(in)) == EOF) { - return -1; - } - v = (v << 8) | c; - if ((c = jas_stream_getc(in)) == EOF) { - return -1; - } - v = (v << 8) | c; - if ((c = jas_stream_getc(in)) == EOF) { - return -1; - } - v = (v << 8) | c; - if (val) { - *val = v; - } - return 0; + uint_fast32_t v; + int c; + if ((c = jas_stream_getc(in)) == EOF) { + return -1; + } + v = c; + if ((c = jas_stream_getc(in)) == EOF) { + return -1; + } + v = (v << 8) | c; + if ((c = jas_stream_getc(in)) == EOF) { + return -1; + } + v = (v << 8) | c; + if ((c = jas_stream_getc(in)) == EOF) { + return -1; + } + v = (v << 8) | c; + if (val) { + *val = v; + } + return 0; } static int jp2_getuint64(jas_stream_t *in, uint_fast64_t *val) { - abort(); + abort(); } /******************************************************************************\ @@ -721,30 +723,30 @@ static int jp2_getuint64(jas_stream_t *in, uint_fast64_t *val) static int jp2_putuint8(jas_stream_t *out, uint_fast8_t val) { - if (jas_stream_putc(out, val & 0xff) == EOF) { - return -1; - } - return 0; + if (jas_stream_putc(out, val & 0xff) == EOF) { + return -1; + } + return 0; } static int jp2_putuint16(jas_stream_t *out, uint_fast16_t val) { - if (jas_stream_putc(out, (val >> 8) & 0xff) == EOF || - jas_stream_putc(out, val & 0xff) == EOF) { - return -1; - } - return 0; + if (jas_stream_putc(out, (val >> 8) & 0xff) == EOF || + jas_stream_putc(out, val & 0xff) == EOF) { + return -1; + } + return 0; } static int jp2_putuint32(jas_stream_t *out, uint_fast32_t val) { - if (jas_stream_putc(out, (val >> 24) & 0xff) == EOF || - jas_stream_putc(out, (val >> 16) & 0xff) == EOF || - jas_stream_putc(out, (val >> 8) & 0xff) == EOF || - jas_stream_putc(out, val & 0xff) == EOF) { - return -1; - } - return 0; + if (jas_stream_putc(out, (val >> 24) & 0xff) == EOF || + jas_stream_putc(out, (val >> 16) & 0xff) == EOF || + jas_stream_putc(out, (val >> 8) & 0xff) == EOF || + jas_stream_putc(out, val & 0xff) == EOF) { + return -1; + } + return 0; } /******************************************************************************\ @@ -753,13 +755,13 @@ static int jp2_putuint32(jas_stream_t *out, uint_fast32_t val) jp2_boxinfo_t *jp2_boxinfolookup(int type) { - jp2_boxinfo_t *boxinfo; - for (boxinfo = jp2_boxinfos; boxinfo->name; ++boxinfo) { - if (boxinfo->type == type) { - return boxinfo; - } - } - return &jp2_boxinfo_unk; + jp2_boxinfo_t *boxinfo; + for (boxinfo = jp2_boxinfos; boxinfo->name; ++boxinfo) { + if (boxinfo->type == type) { + return boxinfo; + } + } + return &jp2_boxinfo_unk; } @@ -768,161 +770,162 @@ jp2_boxinfo_t *jp2_boxinfolookup(int type) static void jp2_cmap_destroy(jp2_box_t *box) { - jp2_cmap_t *cmap = &box->data.cmap; - if (cmap->ents) { - jas_free(cmap->ents); - } + jp2_cmap_t *cmap = &box->data.cmap; + if (cmap->ents) { + jas_free(cmap->ents); + } } static int jp2_cmap_getdata(jp2_box_t *box, jas_stream_t *in) { - jp2_cmap_t *cmap = &box->data.cmap; - jp2_cmapent_t *ent; - int i; - - cmap->numchans = (box->len - JP2_BOX_HDRLEN) / 4; - if (!(cmap->ents = jas_malloc(cmap->numchans * sizeof(jp2_cmapent_t)))) { - return -1; - } - for (i = 0; i < cmap->numchans; ++i) { - ent = &cmap->ents[i]; - if (jp2_getuint16(in, &ent->cmptno) || - jp2_getuint8(in, &ent->map) || - jp2_getuint8(in, &ent->pcol)) { - return -1; - } - } - - return 0; + jp2_cmap_t *cmap = &box->data.cmap; + jp2_cmapent_t *ent; + int i; + + cmap->numchans = (box->len - JP2_BOX_HDRLEN) / 4; + if (!(cmap->ents = jas_malloc(cmap->numchans * sizeof(jp2_cmapent_t)))) { + return -1; + } + for (i = 0; i < cmap->numchans; ++i) { + ent = &cmap->ents[i]; + if (jp2_getuint16(in, &ent->cmptno) || + jp2_getuint8(in, &ent->map) || + jp2_getuint8(in, &ent->pcol)) { + return -1; + } + } + + return 0; } static int jp2_cmap_putdata(jp2_box_t *box, jas_stream_t *out) { - return -1; + return -1; } static void jp2_cmap_dumpdata(jp2_box_t *box, FILE *out) { - jp2_cmap_t *cmap = &box->data.cmap; - int i; - jp2_cmapent_t *ent; - fprintf(stderr, "numchans = %d\n", (int) cmap->numchans); - for (i = 0; i < cmap->numchans; ++i) { - ent = &cmap->ents[i]; - fprintf(stderr, "cmptno=%d; map=%d; pcol=%d\n", - (int) ent->cmptno, (int) ent->map, (int) ent->pcol); - } + jp2_cmap_t *cmap = &box->data.cmap; + int i; + jp2_cmapent_t *ent; + fprintf(stderr, "numchans = %d\n", (int) cmap->numchans); + for (i = 0; i < cmap->numchans; ++i) { + ent = &cmap->ents[i]; + fprintf(stderr, "cmptno=%d; map=%d; pcol=%d\n", + (int) ent->cmptno, (int) ent->map, (int) ent->pcol); + } } static void jp2_pclr_destroy(jp2_box_t *box) { - jp2_pclr_t *pclr = &box->data.pclr; - if (pclr->lutdata) { - jas_free(pclr->lutdata); - } + jp2_pclr_t *pclr = &box->data.pclr; + if (pclr->lutdata) { + jas_free(pclr->lutdata); + } } static int jp2_pclr_getdata(jp2_box_t *box, jas_stream_t *in) { - jp2_pclr_t *pclr = &box->data.pclr; - int lutsize; - int i; - int j; - int_fast32_t x; - - pclr->lutdata = 0; - - if (jp2_getuint16(in, &pclr->numlutents) || - jp2_getuint8(in, &pclr->numchans)) { - return -1; - } - lutsize = pclr->numlutents * pclr->numchans; - if (!(pclr->lutdata = jas_malloc(lutsize * sizeof(int_fast32_t)))) { - return -1; - } - if (!(pclr->bpc = jas_malloc(pclr->numchans * sizeof(uint_fast8_t)))) { - return -1; - } - for (i = 0; i < pclr->numchans; ++i) { - if (jp2_getuint8(in, &pclr->bpc[i])) { - return -1; - } - } - for (i = 0; i < pclr->numlutents; ++i) { - for (j = 0; j < pclr->numchans; ++j) { - if (jp2_getint(in, (pclr->bpc[j] & 0x80) != 0, - (pclr->bpc[j] & 0x7f) + 1, &x)) { - return -1; - } - pclr->lutdata[i * pclr->numchans + j] = x; - } - } - return 0; + jp2_pclr_t *pclr = &box->data.pclr; + int lutsize; + int i; + int j; + int_fast32_t x; + + pclr->lutdata = 0; + + if (jp2_getuint16(in, &pclr->numlutents) || + jp2_getuint8(in, &pclr->numchans)) { + return -1; + } + lutsize = pclr->numlutents * pclr->numchans; + if (!(pclr->lutdata = jas_malloc(lutsize * sizeof(int_fast32_t)))) { + return -1; + } + if (!(pclr->bpc = jas_malloc(pclr->numchans * sizeof(uint_fast8_t)))) { + return -1; + } + for (i = 0; i < pclr->numchans; ++i) { + if (jp2_getuint8(in, &pclr->bpc[i])) { + return -1; + } + } + for (i = 0; i < pclr->numlutents; ++i) { + for (j = 0; j < pclr->numchans; ++j) { + if (jp2_getint(in, (pclr->bpc[j] & 0x80) != 0, + (pclr->bpc[j] & 0x7f) + 1, &x)) { + return -1; + } + pclr->lutdata[i * pclr->numchans + j] = x; + } + } + return 0; } static int jp2_pclr_putdata(jp2_box_t *box, jas_stream_t *out) { /* This code from official Jasper must be part of unfinished work. It generates an unused variable warning. - jp2_pclr_t *pclr = &box->data.pclr; + jp2_pclr_t *pclr = &box->data.pclr; */ - return -1; + return -1; } static void jp2_pclr_dumpdata(jp2_box_t *box, FILE *out) { - jp2_pclr_t *pclr = &box->data.pclr; - int i; - int j; - fprintf(out, "numents=%d; numchans=%d\n", (int) pclr->numlutents, - (int) pclr->numchans); - for (i = 0; i < pclr->numlutents; ++i) { - for (j = 0; j < pclr->numchans; ++j) { - fprintf(out, "LUT[%d][%d]=%d\n", i, j, pclr->lutdata[i * pclr->numchans + j]); - } - } + jp2_pclr_t *pclr = &box->data.pclr; + int i; + int j; + fprintf(out, "numents=%d; numchans=%d\n", (int) pclr->numlutents, + (int) pclr->numchans); + for (i = 0; i < pclr->numlutents; ++i) { + for (j = 0; j < pclr->numchans; ++j) { + fprintf(out, "LUT[%d][%d]=%d\n", i, j, + (int)pclr->lutdata[i * pclr->numchans + j]); + } + } } static int jp2_getint(jas_stream_t *in, int s, int n, int_fast32_t *val) { - int c; - int i; - uint_fast32_t v; - int m; - - m = (n + 7) / 8; - - v = 0; - for (i = 0; i < m; ++i) { - if ((c = jas_stream_getc(in)) == EOF) { - return -1; - } - v = (v << 8) | c; - } - v &= ONES(n); - if (s) { - int sb; - sb = v & (1 << (8 * m - 1)); - *val = ((~v) + 1) & ONES(8 * m); - if (sb) { - *val = -*val; - } - } else { - *val = v; - } - - return 0; + int c; + int i; + uint_fast32_t v; + int m; + + m = (n + 7) / 8; + + v = 0; + for (i = 0; i < m; ++i) { + if ((c = jas_stream_getc(in)) == EOF) { + return -1; + } + v = (v << 8) | c; + } + v &= ONES(n); + if (s) { + int sb; + sb = v & (1 << (8 * m - 1)); + *val = ((~v) + 1) & ONES(8 * m); + if (sb) { + *val = -*val; + } + } else { + *val = v; + } + + return 0; } jp2_cdefchan_t *jp2_cdef_lookup(jp2_cdef_t *cdef, int channo) { - int i; - jp2_cdefchan_t *cdefent; - for (i = 0; i < cdef->numchans; ++i) { - cdefent = &cdef->ents[i]; - if (cdefent->channo == channo) { - return cdefent; - } - } - return 0; + int i; + jp2_cdefchan_t *cdefent; + for (i = 0; i < cdef->numchans; ++i) { + cdefent = &cdef->ents[i]; + if (cdefent->channo == channo) { + return cdefent; + } + } + return 0; } diff --git a/converter/other/jpeg2000/libjasper/jp2/jp2_dec.c b/converter/other/jpeg2000/libjasper/jp2/jp2_dec.c index 3cce9278..91ce6c51 100644 --- a/converter/other/jpeg2000/libjasper/jp2/jp2_dec.c +++ b/converter/other/jpeg2000/libjasper/jp2/jp2_dec.c @@ -297,9 +297,9 @@ jas_image_t *jp2_decode(jas_stream_t *in, char *optstr) jas_eprintf("warning: component data type mismatch\n"); } - /* Is the compression type supported? */ + /* Can we handle the compression type? */ if (dec->ihdr->data.ihdr.comptype != JP2_IHDR_COMPTYPE) { - jas_eprintf("error: unsupported compression type\n"); + jas_eprintf("error: not capable of this compression type\n"); goto error; } @@ -340,7 +340,8 @@ jas_image_t *jp2_decode(jas_stream_t *in, char *optstr) iccp = dec->colr->data.colr.iccp; cs = (iccp[16] << 24) | (iccp[17] << 16) | (iccp[18] << 8) | iccp[19]; - jas_eprintf("ICC Profile CS %08x\n", cs); + if (jas_getdbglevel() > 1) + jas_eprintf("ICC Profile CS %08x\n", cs); jas_image_setcolorspace(dec->image, fromiccpcs(cs)); break; } @@ -454,7 +455,6 @@ jas_image_t *jp2_decode(jas_stream_t *in, char *optstr) jas_eprintf("error: no components\n"); goto error; } -fprintf(stderr, "no of components is %d\n", jas_image_numcmpts(dec->image)); /* Prevent the image from being destroyed later. */ image = dec->image; diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_bs.c b/converter/other/jpeg2000/libjasper/jpc/jpc_bs.c index 54f0a819..c66fcd99 100644 --- a/converter/other/jpeg2000/libjasper/jpc/jpc_bs.c +++ b/converter/other/jpeg2000/libjasper/jpc/jpc_bs.c @@ -157,10 +157,6 @@ jpc_bitstream_t *jpc_bitstream_sopen(jas_stream_t *stream, const char *mode) { jpc_bitstream_t *bitstream; - /* Ensure that the open mode is valid. */ - assert(!strcmp(mode, "r") || !strcmp(mode, "w") || !strcmp(mode, "r+") - || !strcmp(mode, "w+")); - if (!(bitstream = jpc_bitstream_alloc())) { return 0; } diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_bs.h b/converter/other/jpeg2000/libjasper/jpc/jpc_bs.h index f515972b..edb0a2df 100644 --- a/converter/other/jpeg2000/libjasper/jpc/jpc_bs.h +++ b/converter/other/jpeg2000/libjasper/jpc/jpc_bs.h @@ -149,7 +149,7 @@ #define JPC_BITSTREAM_NOCLOSE 0x01 /* End of file has been reached while reading. */ #define JPC_BITSTREAM_EOF 0x02 -/* An I/O error has occured. */ +/* An I/O error has occurred. */ #define JPC_BITSTREAM_ERR 0x04 /******************************************************************************\ diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_cs.c b/converter/other/jpeg2000/libjasper/jpc/jpc_cs.c index 63cf8ba7..559f36cf 100644 --- a/converter/other/jpeg2000/libjasper/jpc/jpc_cs.c +++ b/converter/other/jpeg2000/libjasper/jpc/jpc_cs.c @@ -135,9 +135,9 @@ /* Marker segment table entry. */ typedef struct { - int id; - const char *name; - jpc_msops_t ops; + int id; + const char *name; + jpc_msops_t ops; } jpc_mstabent_t; /******************************************************************************\ @@ -220,40 +220,40 @@ static int jpc_cox_putcompparms(jpc_ms_t *ms, jpc_cstate_t *cstate, \******************************************************************************/ static jpc_mstabent_t jpc_mstab[] = { - {JPC_MS_SOC, "SOC", {0, 0, 0, 0}}, - {JPC_MS_SOT, "SOT", {0, jpc_sot_getparms, jpc_sot_putparms, - jpc_sot_dumpparms}}, - {JPC_MS_SOD, "SOD", {0, 0, 0, 0}}, - {JPC_MS_EOC, "EOC", {0, 0, 0, 0}}, - {JPC_MS_SIZ, "SIZ", {jpc_siz_destroyparms, jpc_siz_getparms, - jpc_siz_putparms, jpc_siz_dumpparms}}, - {JPC_MS_COD, "COD", {jpc_cod_destroyparms, jpc_cod_getparms, - jpc_cod_putparms, jpc_cod_dumpparms}}, - {JPC_MS_COC, "COC", {jpc_coc_destroyparms, jpc_coc_getparms, - jpc_coc_putparms, jpc_coc_dumpparms}}, - {JPC_MS_RGN, "RGN", {0, jpc_rgn_getparms, jpc_rgn_putparms, - jpc_rgn_dumpparms}}, - {JPC_MS_QCD, "QCD", {jpc_qcd_destroyparms, jpc_qcd_getparms, - jpc_qcd_putparms, jpc_qcd_dumpparms}}, - {JPC_MS_QCC, "QCC", {jpc_qcc_destroyparms, jpc_qcc_getparms, - jpc_qcc_putparms, jpc_qcc_dumpparms}}, - {JPC_MS_POC, "POC", {jpc_poc_destroyparms, jpc_poc_getparms, - jpc_poc_putparms, jpc_poc_dumpparms}}, - {JPC_MS_TLM, "TLM", {0, jpc_unk_getparms, jpc_unk_putparms, 0}}, - {JPC_MS_PLM, "PLM", {0, jpc_unk_getparms, jpc_unk_putparms, 0}}, - {JPC_MS_PPM, "PPM", {jpc_ppm_destroyparms, jpc_ppm_getparms, - jpc_ppm_putparms, jpc_ppm_dumpparms}}, - {JPC_MS_PPT, "PPT", {jpc_ppt_destroyparms, jpc_ppt_getparms, - jpc_ppt_putparms, jpc_ppt_dumpparms}}, - {JPC_MS_SOP, "SOP", {0, jpc_sop_getparms, jpc_sop_putparms, - jpc_sop_dumpparms}}, - {JPC_MS_EPH, "EPH", {0, 0, 0, 0}}, - {JPC_MS_CRG, "CRG", {0, jpc_crg_getparms, jpc_crg_putparms, - jpc_crg_dumpparms}}, - {JPC_MS_COM, "COM", {jpc_com_destroyparms, jpc_com_getparms, - jpc_com_putparms, jpc_com_dumpparms}}, - {-1, "UNKNOWN", {jpc_unk_destroyparms, jpc_unk_getparms, - jpc_unk_putparms, jpc_unk_dumpparms}} + {JPC_MS_SOC, "SOC", {0, 0, 0, 0}}, + {JPC_MS_SOT, "SOT", {0, jpc_sot_getparms, jpc_sot_putparms, + jpc_sot_dumpparms}}, + {JPC_MS_SOD, "SOD", {0, 0, 0, 0}}, + {JPC_MS_EOC, "EOC", {0, 0, 0, 0}}, + {JPC_MS_SIZ, "SIZ", {jpc_siz_destroyparms, jpc_siz_getparms, + jpc_siz_putparms, jpc_siz_dumpparms}}, + {JPC_MS_COD, "COD", {jpc_cod_destroyparms, jpc_cod_getparms, + jpc_cod_putparms, jpc_cod_dumpparms}}, + {JPC_MS_COC, "COC", {jpc_coc_destroyparms, jpc_coc_getparms, + jpc_coc_putparms, jpc_coc_dumpparms}}, + {JPC_MS_RGN, "RGN", {0, jpc_rgn_getparms, jpc_rgn_putparms, + jpc_rgn_dumpparms}}, + {JPC_MS_QCD, "QCD", {jpc_qcd_destroyparms, jpc_qcd_getparms, + jpc_qcd_putparms, jpc_qcd_dumpparms}}, + {JPC_MS_QCC, "QCC", {jpc_qcc_destroyparms, jpc_qcc_getparms, + jpc_qcc_putparms, jpc_qcc_dumpparms}}, + {JPC_MS_POC, "POC", {jpc_poc_destroyparms, jpc_poc_getparms, + jpc_poc_putparms, jpc_poc_dumpparms}}, + {JPC_MS_TLM, "TLM", {0, jpc_unk_getparms, jpc_unk_putparms, 0}}, + {JPC_MS_PLM, "PLM", {0, jpc_unk_getparms, jpc_unk_putparms, 0}}, + {JPC_MS_PPM, "PPM", {jpc_ppm_destroyparms, jpc_ppm_getparms, + jpc_ppm_putparms, jpc_ppm_dumpparms}}, + {JPC_MS_PPT, "PPT", {jpc_ppt_destroyparms, jpc_ppt_getparms, + jpc_ppt_putparms, jpc_ppt_dumpparms}}, + {JPC_MS_SOP, "SOP", {0, jpc_sop_getparms, jpc_sop_putparms, + jpc_sop_dumpparms}}, + {JPC_MS_EPH, "EPH", {0, 0, 0, 0}}, + {JPC_MS_CRG, "CRG", {0, jpc_crg_getparms, jpc_crg_putparms, + jpc_crg_dumpparms}}, + {JPC_MS_COM, "COM", {jpc_com_destroyparms, jpc_com_getparms, + jpc_com_putparms, jpc_com_dumpparms}}, + {-1, "UNKNOWN", {jpc_unk_destroyparms, jpc_unk_getparms, + jpc_unk_putparms, jpc_unk_dumpparms}} }; /******************************************************************************\ @@ -263,160 +263,160 @@ static jpc_mstabent_t jpc_mstab[] = { /* Create a code stream state object. */ jpc_cstate_t *jpc_cstate_create() { - jpc_cstate_t *cstate; - if (!(cstate = jas_malloc(sizeof(jpc_cstate_t)))) { - return 0; - } - cstate->numcomps = 0; - return cstate; + jpc_cstate_t *cstate; + if (!(cstate = jas_malloc(sizeof(jpc_cstate_t)))) { + return 0; + } + cstate->numcomps = 0; + return cstate; } /* Destroy a code stream state object. */ void jpc_cstate_destroy(jpc_cstate_t *cstate) { - jas_free(cstate); + jas_free(cstate); } /* Read a marker segment from a stream. */ jpc_ms_t *jpc_getms(jas_stream_t *in, jpc_cstate_t *cstate) { - jpc_ms_t *ms; - jpc_mstabent_t *mstabent; - jas_stream_t *tmpstream; - - if (!(ms = jpc_ms_create(0))) { - return 0; - } - - /* Get the marker type. */ - if (jpc_getuint16(in, &ms->id) || ms->id < JPC_MS_MIN || - ms->id > JPC_MS_MAX) { - jpc_ms_destroy(ms); - return 0; - } - - mstabent = jpc_mstab_lookup(ms->id); - ms->ops = &mstabent->ops; - - /* Get the marker segment length and parameters if present. */ - /* Note: It is tacitly assumed that a marker segment cannot have - parameters unless it has a length field. That is, there cannot - be a parameters field without a length field and vice versa. */ - if (JPC_MS_HASPARMS(ms->id)) { - /* Get the length of the marker segment. */ - if (jpc_getuint16(in, &ms->len) || ms->len < 3) { - jpc_ms_destroy(ms); - return 0; - } - /* Calculate the length of the marker segment parameters. */ - ms->len -= 2; - /* Create and prepare a temporary memory stream from which to - read the marker segment parameters. */ - /* Note: This approach provides a simple way of ensuring that - we never read beyond the end of the marker segment (even if - the marker segment length is errantly set too small). */ - if (!(tmpstream = jas_stream_memopen(0, 0))) { - jpc_ms_destroy(ms); - return 0; - } - if (jas_stream_copy(tmpstream, in, ms->len) || - jas_stream_seek(tmpstream, 0, SEEK_SET) < 0) { - jas_stream_close(tmpstream); - jpc_ms_destroy(ms); - return 0; - } - /* Get the marker segment parameters. */ - if ((*ms->ops->getparms)(ms, cstate, tmpstream)) { - ms->ops = 0; - jpc_ms_destroy(ms); - jas_stream_close(tmpstream); - return 0; - } - - if (jas_getdbglevel() > 0) { - jpc_ms_dump(ms, stderr); - } - - if (jas_stream_tell(tmpstream) != ms->len) { - fprintf(stderr, - "warning: trailing garbage in marker segment (%ld bytes)\n", - ms->len - jas_stream_tell(tmpstream)); - } - - /* Close the temporary stream. */ - jas_stream_close(tmpstream); - - } else { - /* There are no marker segment parameters. */ - ms->len = 0; - - if (jas_getdbglevel() > 0) { - jpc_ms_dump(ms, stderr); - } - } - - /* Update the code stream state information based on the type of - marker segment read. */ - /* Note: This is a bit of a hack, but I'm not going to define another - type of virtual function for this one special case. */ - if (ms->id == JPC_MS_SIZ) { - cstate->numcomps = ms->parms.siz.numcomps; - } - - return ms; + jpc_ms_t *ms; + jpc_mstabent_t *mstabent; + jas_stream_t *tmpstream; + + if (!(ms = jpc_ms_create(0))) { + return 0; + } + + /* Get the marker type. */ + if (jpc_getuint16(in, &ms->id) || ms->id < JPC_MS_MIN || + ms->id > JPC_MS_MAX) { + jpc_ms_destroy(ms); + return 0; + } + + mstabent = jpc_mstab_lookup(ms->id); + ms->ops = &mstabent->ops; + + /* Get the marker segment length and parameters if present. */ + /* Note: It is tacitly assumed that a marker segment cannot have + parameters unless it has a length field. That is, there cannot + be a parameters field without a length field and vice versa. */ + if (JPC_MS_HASPARMS(ms->id)) { + /* Get the length of the marker segment. */ + if (jpc_getuint16(in, &ms->len) || ms->len < 3) { + jpc_ms_destroy(ms); + return 0; + } + /* Calculate the length of the marker segment parameters. */ + ms->len -= 2; + /* Create and prepare a temporary memory stream from which to + read the marker segment parameters. */ + /* Note: This approach provides a simple way of ensuring that + we never read beyond the end of the marker segment (even if + the marker segment length is errantly set too small). */ + if (!(tmpstream = jas_stream_memopen(0, 0))) { + jpc_ms_destroy(ms); + return 0; + } + if (jas_stream_copy(tmpstream, in, ms->len) || + jas_stream_seek(tmpstream, 0, SEEK_SET) < 0) { + jas_stream_close(tmpstream); + jpc_ms_destroy(ms); + return 0; + } + /* Get the marker segment parameters. */ + if ((*ms->ops->getparms)(ms, cstate, tmpstream)) { + ms->ops = 0; + jpc_ms_destroy(ms); + jas_stream_close(tmpstream); + return 0; + } + + if (jas_getdbglevel() > 0) { + jpc_ms_dump(ms, stderr); + } + + if (jas_stream_tell(tmpstream) != ms->len) { + fprintf(stderr, + "warning: trailing garbage in marker segment (%ld bytes)\n", + ms->len - jas_stream_tell(tmpstream)); + } + + /* Close the temporary stream. */ + jas_stream_close(tmpstream); + + } else { + /* There are no marker segment parameters. */ + ms->len = 0; + + if (jas_getdbglevel() > 0) { + jpc_ms_dump(ms, stderr); + } + } + + /* Update the code stream state information based on the type of + marker segment read. */ + /* Note: This is a bit of a hack, but I'm not going to define another + type of virtual function for this one special case. */ + if (ms->id == JPC_MS_SIZ) { + cstate->numcomps = ms->parms.siz.numcomps; + } + + return ms; } /* Write a marker segment to a stream. */ int jpc_putms(jas_stream_t *out, jpc_cstate_t *cstate, jpc_ms_t *ms) { - jas_stream_t *tmpstream; - int len; - - /* Output the marker segment type. */ - if (jpc_putuint16(out, ms->id)) { - return -1; - } - - /* Output the marker segment length and parameters if necessary. */ - if (ms->ops->putparms) { - /* Create a temporary stream in which to buffer the - parameter data. */ - if (!(tmpstream = jas_stream_memopen(0, 0))) { - return -1; - } - if ((*ms->ops->putparms)(ms, cstate, tmpstream)) { - jas_stream_close(tmpstream); - return -1; - } - /* Get the number of bytes of parameter data written. */ - if ((len = jas_stream_tell(tmpstream)) < 0) { - jas_stream_close(tmpstream); - return -1; - } - ms->len = len; - /* Write the marker segment length and parameter data to - the output stream. */ - if (jas_stream_seek(tmpstream, 0, SEEK_SET) < 0 || - jpc_putuint16(out, ms->len + 2) || - jas_stream_copy(out, tmpstream, ms->len) < 0) { - jas_stream_close(tmpstream); - return -1; - } - /* Close the temporary stream. */ - jas_stream_close(tmpstream); - } - - /* This is a bit of a hack, but I'm not going to define another - type of virtual function for this one special case. */ - if (ms->id == JPC_MS_SIZ) { - cstate->numcomps = ms->parms.siz.numcomps; - } - - if (jas_getdbglevel() > 0) { - jpc_ms_dump(ms, stderr); - } - - return 0; + jas_stream_t *tmpstream; + int len; + + /* Output the marker segment type. */ + if (jpc_putuint16(out, ms->id)) { + return -1; + } + + /* Output the marker segment length and parameters if necessary. */ + if (ms->ops->putparms) { + /* Create a temporary stream in which to buffer the + parameter data. */ + if (!(tmpstream = jas_stream_memopen(0, 0))) { + return -1; + } + if ((*ms->ops->putparms)(ms, cstate, tmpstream)) { + jas_stream_close(tmpstream); + return -1; + } + /* Get the number of bytes of parameter data written. */ + if ((len = jas_stream_tell(tmpstream)) < 0) { + jas_stream_close(tmpstream); + return -1; + } + ms->len = len; + /* Write the marker segment length and parameter data to + the output stream. */ + if (jas_stream_seek(tmpstream, 0, SEEK_SET) < 0 || + jpc_putuint16(out, ms->len + 2) || + jas_stream_copy(out, tmpstream, ms->len) < 0) { + jas_stream_close(tmpstream); + return -1; + } + /* Close the temporary stream. */ + jas_stream_close(tmpstream); + } + + /* This is a bit of a hack, but I'm not going to define another + type of virtual function for this one special case. */ + if (ms->id == JPC_MS_SIZ) { + cstate->numcomps = ms->parms.siz.numcomps; + } + + if (jas_getdbglevel() > 0) { + jpc_ms_dump(ms, stderr); + } + + return 0; } /******************************************************************************\ @@ -426,45 +426,46 @@ int jpc_putms(jas_stream_t *out, jpc_cstate_t *cstate, jpc_ms_t *ms) /* Create a marker segment of the specified type. */ jpc_ms_t *jpc_ms_create(int type) { - jpc_ms_t *ms; - jpc_mstabent_t *mstabent; + jpc_ms_t *ms; + jpc_mstabent_t *mstabent; - if (!(ms = jas_malloc(sizeof(jpc_ms_t)))) { - return 0; - } - ms->id = type; - ms->len = 0; - mstabent = jpc_mstab_lookup(ms->id); - ms->ops = &mstabent->ops; - memset(&ms->parms, 0, sizeof(jpc_msparms_t)); - return ms; + if (!(ms = jas_malloc(sizeof(jpc_ms_t)))) { + return 0; + } + ms->id = type; + ms->len = 0; + mstabent = jpc_mstab_lookup(ms->id); + ms->ops = &mstabent->ops; + memset(&ms->parms, 0, sizeof(jpc_msparms_t)); + return ms; } /* Destroy a marker segment. */ void jpc_ms_destroy(jpc_ms_t *ms) { - if (ms->ops && ms->ops->destroyparms) { - (*ms->ops->destroyparms)(ms); - } - jas_free(ms); + if (ms->ops && ms->ops->destroyparms) { + (*ms->ops->destroyparms)(ms); + } + jas_free(ms); } /* Dump a marker segment to a stream for debugging. */ void jpc_ms_dump(jpc_ms_t *ms, FILE *out) { - jpc_mstabent_t *mstabent; - mstabent = jpc_mstab_lookup(ms->id); - fprintf(out, "type = 0x%04x (%s);", ms->id, mstabent->name); - if (JPC_MS_HASPARMS(ms->id)) { - fprintf(out, " len = %d;", ms->len + 2); - if (ms->ops->dumpparms) { - (*ms->ops->dumpparms)(ms, out); - } else { - fprintf(out, "\n"); - } - } else { - fprintf(out, "\n"); - } + jpc_mstabent_t *mstabent; + mstabent = jpc_mstab_lookup(ms->id); + fprintf(out, "type = 0x%04x (%s);", + (unsigned int)ms->id, mstabent->name); + if (JPC_MS_HASPARMS(ms->id)) { + fprintf(out, " len = %d;", (int)ms->len + 2); + if (ms->ops->dumpparms) { + (*ms->ops->dumpparms)(ms, out); + } else { + fprintf(out, "\n"); + } + } else { + fprintf(out, "\n"); + } } /******************************************************************************\ @@ -473,37 +474,37 @@ void jpc_ms_dump(jpc_ms_t *ms, FILE *out) static int jpc_sot_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in) { - jpc_sot_t *sot = &ms->parms.sot; - if (jpc_getuint16(in, &sot->tileno) || - jpc_getuint32(in, &sot->len) || - jpc_getuint8(in, &sot->partno) || - jpc_getuint8(in, &sot->numparts)) { - return -1; - } - if (jas_stream_eof(in)) { - return -1; - } - return 0; + jpc_sot_t *sot = &ms->parms.sot; + if (jpc_getuint16(in, &sot->tileno) || + jpc_getuint32(in, &sot->len) || + jpc_getuint8(in, &sot->partno) || + jpc_getuint8(in, &sot->numparts)) { + return -1; + } + if (jas_stream_eof(in)) { + return -1; + } + return 0; } static int jpc_sot_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out) { - jpc_sot_t *sot = &ms->parms.sot; - if (jpc_putuint16(out, sot->tileno) || - jpc_putuint32(out, sot->len) || - jpc_putuint8(out, sot->partno) || - jpc_putuint8(out, sot->numparts)) { - return -1; - } - return 0; + jpc_sot_t *sot = &ms->parms.sot; + if (jpc_putuint16(out, sot->tileno) || + jpc_putuint32(out, sot->len) || + jpc_putuint8(out, sot->partno) || + jpc_putuint8(out, sot->numparts)) { + return -1; + } + return 0; } static int jpc_sot_dumpparms(jpc_ms_t *ms, FILE *out) { - jpc_sot_t *sot = &ms->parms.sot; - fprintf(out, "tileno = %d; len = %d; partno = %d; numparts = %d\n", - sot->tileno, sot->len, sot->partno, sot->numparts); - return 0; + jpc_sot_t *sot = &ms->parms.sot; + fprintf(out, "tileno = %d; len = %d; partno = %d; numparts = %d\n", + (int)sot->tileno, (int)sot->len, sot->partno, sot->numparts); + return 0; } /******************************************************************************\ @@ -512,242 +513,244 @@ static int jpc_sot_dumpparms(jpc_ms_t *ms, FILE *out) static void jpc_siz_destroyparms(jpc_ms_t *ms) { - jpc_siz_t *siz = &ms->parms.siz; - if (siz->comps) { - jas_free(siz->comps); - } + jpc_siz_t *siz = &ms->parms.siz; + if (siz->comps) { + jas_free(siz->comps); + } } static int jpc_siz_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in) { - jpc_siz_t *siz = &ms->parms.siz; - int i; - uint_fast8_t tmp; - if (jpc_getuint16(in, &siz->caps) || - jpc_getuint32(in, &siz->width) || - jpc_getuint32(in, &siz->height) || - jpc_getuint32(in, &siz->xoff) || - jpc_getuint32(in, &siz->yoff) || - jpc_getuint32(in, &siz->tilewidth) || - jpc_getuint32(in, &siz->tileheight) || - jpc_getuint32(in, &siz->tilexoff) || - jpc_getuint32(in, &siz->tileyoff) || - jpc_getuint16(in, &siz->numcomps)) { - return -1; - } - if (!siz->width || !siz->height || !siz->tilewidth || - !siz->tileheight || !siz->numcomps) { - return -1; - } - if (!(siz->comps = jas_malloc(siz->numcomps * sizeof(jpc_sizcomp_t)))) { - return -1; - } - for (i = 0; i < siz->numcomps; ++i) { - if (jpc_getuint8(in, &tmp) || - jpc_getuint8(in, &siz->comps[i].hsamp) || - jpc_getuint8(in, &siz->comps[i].vsamp)) { - jas_free(siz->comps); - return -1; - } - siz->comps[i].sgnd = (tmp >> 7) & 1; - siz->comps[i].prec = (tmp & 0x7f) + 1; - } - if (jas_stream_eof(in)) { - jas_free(siz->comps); - return -1; - } - return 0; + jpc_siz_t *siz = &ms->parms.siz; + int i; + uint_fast8_t tmp; + if (jpc_getuint16(in, &siz->caps) || + jpc_getuint32(in, &siz->width) || + jpc_getuint32(in, &siz->height) || + jpc_getuint32(in, &siz->xoff) || + jpc_getuint32(in, &siz->yoff) || + jpc_getuint32(in, &siz->tilewidth) || + jpc_getuint32(in, &siz->tileheight) || + jpc_getuint32(in, &siz->tilexoff) || + jpc_getuint32(in, &siz->tileyoff) || + jpc_getuint16(in, &siz->numcomps)) { + return -1; + } + if (!siz->width || !siz->height || !siz->tilewidth || + !siz->tileheight || !siz->numcomps) { + return -1; + } + if (!(siz->comps = jas_malloc(siz->numcomps * sizeof(jpc_sizcomp_t)))) { + return -1; + } + for (i = 0; i < siz->numcomps; ++i) { + if (jpc_getuint8(in, &tmp) || + jpc_getuint8(in, &siz->comps[i].hsamp) || + jpc_getuint8(in, &siz->comps[i].vsamp)) { + jas_free(siz->comps); + return -1; + } + siz->comps[i].sgnd = (tmp >> 7) & 1; + siz->comps[i].prec = (tmp & 0x7f) + 1; + } + if (jas_stream_eof(in)) { + jas_free(siz->comps); + return -1; + } + return 0; } static int jpc_siz_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out) { - jpc_siz_t *siz = &ms->parms.siz; - int i; - assert(siz->width && siz->height && siz->tilewidth && - siz->tileheight && siz->numcomps); - if (jpc_putuint16(out, siz->caps) || - jpc_putuint32(out, siz->width) || - jpc_putuint32(out, siz->height) || - jpc_putuint32(out, siz->xoff) || - jpc_putuint32(out, siz->yoff) || - jpc_putuint32(out, siz->tilewidth) || - jpc_putuint32(out, siz->tileheight) || - jpc_putuint32(out, siz->tilexoff) || - jpc_putuint32(out, siz->tileyoff) || - jpc_putuint16(out, siz->numcomps)) { - return -1; - } - for (i = 0; i < siz->numcomps; ++i) { - if (jpc_putuint8(out, ((siz->comps[i].sgnd & 1) << 7) | - ((siz->comps[i].prec - 1) & 0x7f)) || - jpc_putuint8(out, siz->comps[i].hsamp) || - jpc_putuint8(out, siz->comps[i].vsamp)) { - return -1; - } - } - return 0; + jpc_siz_t *siz = &ms->parms.siz; + int i; + assert(siz->width && siz->height && siz->tilewidth && + siz->tileheight && siz->numcomps); + if (jpc_putuint16(out, siz->caps) || + jpc_putuint32(out, siz->width) || + jpc_putuint32(out, siz->height) || + jpc_putuint32(out, siz->xoff) || + jpc_putuint32(out, siz->yoff) || + jpc_putuint32(out, siz->tilewidth) || + jpc_putuint32(out, siz->tileheight) || + jpc_putuint32(out, siz->tilexoff) || + jpc_putuint32(out, siz->tileyoff) || + jpc_putuint16(out, siz->numcomps)) { + return -1; + } + for (i = 0; i < siz->numcomps; ++i) { + if (jpc_putuint8(out, ((siz->comps[i].sgnd & 1) << 7) | + ((siz->comps[i].prec - 1) & 0x7f)) || + jpc_putuint8(out, siz->comps[i].hsamp) || + jpc_putuint8(out, siz->comps[i].vsamp)) { + return -1; + } + } + return 0; } static int jpc_siz_dumpparms(jpc_ms_t *ms, FILE *out) { - jpc_siz_t *siz = &ms->parms.siz; - int i; - fprintf(out, "caps = 0x%02x;\n", siz->caps); - fprintf(out, "width = %d; height = %d; xoff = %d; yoff = %d;\n", - siz->width, siz->height, siz->xoff, siz->yoff); - fprintf(out, "tilewidth = %d; tileheight = %d; tilexoff = %d; " - "tileyoff = %d;\n", siz->tilewidth, siz->tileheight, siz->tilexoff, - siz->tileyoff); - for (i = 0; i < siz->numcomps; ++i) { - fprintf(out, "prec[%d] = %d; sgnd[%d] = %d; hsamp[%d] = %d; " - "vsamp[%d] = %d\n", i, siz->comps[i].prec, i, - siz->comps[i].sgnd, i, siz->comps[i].hsamp, i, - siz->comps[i].vsamp); - } - return 0; -} - -/******************************************************************************\ + jpc_siz_t *siz = &ms->parms.siz; + int i; + fprintf(out, "caps = 0x%02x;\n", (unsigned int)siz->caps); + fprintf(out, "width = %d; height = %d; xoff = %d; yoff = %d;\n", + (int)siz->width, (int)siz->height, (int)siz->xoff, (int)siz->yoff); + fprintf(out, "tilewidth = %d; tileheight = %d; tilexoff = %d; " + "tileyoff = %d;\n", + (int)siz->tilewidth, (int)siz->tileheight, + (int)siz->tilexoff, (int)siz->tileyoff); + for (i = 0; i < siz->numcomps; ++i) { + fprintf(out, "prec[%d] = %d; sgnd[%d] = %d; hsamp[%d] = %d; " + "vsamp[%d] = %d\n", i, siz->comps[i].prec, i, + siz->comps[i].sgnd, i, siz->comps[i].hsamp, i, + siz->comps[i].vsamp); + } + return 0; +} + +/*****************************************************************************\ * COD marker segment operations. -\******************************************************************************/ +\*****************************************************************************/ static void jpc_cod_destroyparms(jpc_ms_t *ms) { - jpc_cod_t *cod = &ms->parms.cod; - jpc_cox_destroycompparms(&cod->compparms); + jpc_cod_t *cod = &ms->parms.cod; + jpc_cox_destroycompparms(&cod->compparms); } static int jpc_cod_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in) { - jpc_cod_t *cod = &ms->parms.cod; - if (jpc_getuint8(in, &cod->csty)) { - return -1; - } - if (jpc_getuint8(in, &cod->prg) || - jpc_getuint16(in, &cod->numlyrs) || - jpc_getuint8(in, &cod->mctrans)) { - return -1; - } - if (jpc_cox_getcompparms(ms, cstate, in, - (cod->csty & JPC_COX_PRT) != 0, &cod->compparms)) { - return -1; - } - if (jas_stream_eof(in)) { - jpc_cod_destroyparms(ms); - return -1; - } - return 0; + jpc_cod_t *cod = &ms->parms.cod; + if (jpc_getuint8(in, &cod->csty)) { + return -1; + } + if (jpc_getuint8(in, &cod->prg) || + jpc_getuint16(in, &cod->numlyrs) || + jpc_getuint8(in, &cod->mctrans)) { + return -1; + } + if (jpc_cox_getcompparms(ms, cstate, in, + (cod->csty & JPC_COX_PRT) != 0, &cod->compparms)) { + return -1; + } + if (jas_stream_eof(in)) { + jpc_cod_destroyparms(ms); + return -1; + } + return 0; } static int jpc_cod_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out) { - jpc_cod_t *cod = &ms->parms.cod; - assert(cod->numlyrs > 0 && cod->compparms.numdlvls <= 32); - assert(cod->compparms.numdlvls == cod->compparms.numrlvls - 1); - if (jpc_putuint8(out, cod->compparms.csty) || - jpc_putuint8(out, cod->prg) || - jpc_putuint16(out, cod->numlyrs) || - jpc_putuint8(out, cod->mctrans)) { - return -1; - } - if (jpc_cox_putcompparms(ms, cstate, out, - (cod->csty & JPC_COX_PRT) != 0, &cod->compparms)) { - return -1; - } - return 0; + jpc_cod_t *cod = &ms->parms.cod; + assert(cod->numlyrs > 0 && cod->compparms.numdlvls <= 32); + assert(cod->compparms.numdlvls == cod->compparms.numrlvls - 1); + if (jpc_putuint8(out, cod->compparms.csty) || + jpc_putuint8(out, cod->prg) || + jpc_putuint16(out, cod->numlyrs) || + jpc_putuint8(out, cod->mctrans)) { + return -1; + } + if (jpc_cox_putcompparms(ms, cstate, out, + (cod->csty & JPC_COX_PRT) != 0, &cod->compparms)) { + return -1; + } + return 0; } static int jpc_cod_dumpparms(jpc_ms_t *ms, FILE *out) { - jpc_cod_t *cod = &ms->parms.cod; - int i; - fprintf(out, "csty = 0x%02x;\n", cod->compparms.csty); - fprintf(out, "numdlvls = %d; qmfbid = %d; mctrans = %d\n", - cod->compparms.numdlvls, cod->compparms.qmfbid, cod->mctrans); - fprintf(out, "prg = %d; numlyrs = %d;\n", - cod->prg, cod->numlyrs); - fprintf(out, "cblkwidthval = %d; cblkheightval = %d; " - "cblksty = 0x%02x;\n", cod->compparms.cblkwidthval, cod->compparms.cblkheightval, - cod->compparms.cblksty); - if (cod->csty & JPC_COX_PRT) { - for (i = 0; i < cod->compparms.numrlvls; ++i) { - fprintf(stderr, "prcwidth[%d] = %d, prcheight[%d] = %d\n", - i, cod->compparms.rlvls[i].parwidthval, - i, cod->compparms.rlvls[i].parheightval); - } - } - return 0; -} - -/******************************************************************************\ + jpc_cod_t *cod = &ms->parms.cod; + int i; + fprintf(out, "csty = 0x%02x;\n", cod->compparms.csty); + fprintf(out, "numdlvls = %d; qmfbid = %d; mctrans = %d\n", + cod->compparms.numdlvls, cod->compparms.qmfbid, cod->mctrans); + fprintf(out, "prg = %d; numlyrs = %d;\n", + cod->prg, (int)cod->numlyrs); + fprintf(out, "cblkwidthval = %d; cblkheightval = %d; " + "cblksty = 0x%02x;\n", cod->compparms.cblkwidthval, cod->compparms.cblkheightval, + cod->compparms.cblksty); + if (cod->csty & JPC_COX_PRT) { + for (i = 0; i < cod->compparms.numrlvls; ++i) { + fprintf(stderr, "prcwidth[%d] = %d, prcheight[%d] = %d\n", + i, cod->compparms.rlvls[i].parwidthval, + i, cod->compparms.rlvls[i].parheightval); + } + } + return 0; +} + +/*****************************************************************************\ * COC marker segment operations. -\******************************************************************************/ +\*****************************************************************************/ static void jpc_coc_destroyparms(jpc_ms_t *ms) { - jpc_coc_t *coc = &ms->parms.coc; - jpc_cox_destroycompparms(&coc->compparms); + jpc_coc_t *coc = &ms->parms.coc; + jpc_cox_destroycompparms(&coc->compparms); } static int jpc_coc_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in) { - jpc_coc_t *coc = &ms->parms.coc; - uint_fast8_t tmp; - if (cstate->numcomps <= 256) { - if (jpc_getuint8(in, &tmp)) { - return -1; - } - coc->compno = tmp; - } else { - if (jpc_getuint16(in, &coc->compno)) { - return -1; - } - } - if (jpc_getuint8(in, &coc->compparms.csty)) { - return -1; - } - if (jpc_cox_getcompparms(ms, cstate, in, - (coc->compparms.csty & JPC_COX_PRT) != 0, &coc->compparms)) { - return -1; - } - if (jas_stream_eof(in)) { - return -1; - } - return 0; + jpc_coc_t *coc = &ms->parms.coc; + uint_fast8_t tmp; + if (cstate->numcomps <= 256) { + if (jpc_getuint8(in, &tmp)) { + return -1; + } + coc->compno = tmp; + } else { + if (jpc_getuint16(in, &coc->compno)) { + return -1; + } + } + if (jpc_getuint8(in, &coc->compparms.csty)) { + return -1; + } + if (jpc_cox_getcompparms(ms, cstate, in, + (coc->compparms.csty & JPC_COX_PRT) != 0, &coc->compparms)) { + return -1; + } + if (jas_stream_eof(in)) { + return -1; + } + return 0; } static int jpc_coc_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out) { - jpc_coc_t *coc = &ms->parms.coc; - assert(coc->compparms.numdlvls <= 32); - if (cstate->numcomps <= 256) { - if (jpc_putuint8(out, coc->compno)) { - return -1; - } - } else { - if (jpc_putuint16(out, coc->compno)) { - return -1; - } - } - if (jpc_putuint8(out, coc->compparms.csty)) { - return -1; - } - if (jpc_cox_putcompparms(ms, cstate, out, - (coc->compparms.csty & JPC_COX_PRT) != 0, &coc->compparms)) { - return -1; - } - return 0; + jpc_coc_t *coc = &ms->parms.coc; + assert(coc->compparms.numdlvls <= 32); + if (cstate->numcomps <= 256) { + if (jpc_putuint8(out, coc->compno)) { + return -1; + } + } else { + if (jpc_putuint16(out, coc->compno)) { + return -1; + } + } + if (jpc_putuint8(out, coc->compparms.csty)) { + return -1; + } + if (jpc_cox_putcompparms(ms, cstate, out, + (coc->compparms.csty & JPC_COX_PRT) != 0, &coc->compparms)) { + return -1; + } + return 0; } static int jpc_coc_dumpparms(jpc_ms_t *ms, FILE *out) { - jpc_coc_t *coc = &ms->parms.coc; - fprintf(out, "compno = %d; csty = 0x%02x; numdlvls = %d;\n", - coc->compno, coc->compparms.csty, coc->compparms.numdlvls); - fprintf(out, "cblkwidthval = %d; cblkheightval = %d; " - "cblksty = 0x%02x; qmfbid = %d;\n", coc->compparms.cblkwidthval, - coc->compparms.cblkheightval, coc->compparms.cblksty, coc->compparms.qmfbid); - return 0; + jpc_coc_t *coc = &ms->parms.coc; + fprintf(out, "compno = %d; csty = 0x%02x; numdlvls = %d;\n", + (int)coc->compno, coc->compparms.csty, coc->compparms.numdlvls); + fprintf(out, "cblkwidthval = %d; cblkheightval = %d; " + "cblksty = 0x%02x; qmfbid = %d;\n", coc->compparms.cblkwidthval, + coc->compparms.cblkheightval, coc->compparms.cblksty, + coc->compparms.qmfbid); + return 0; } /******************************************************************************\ * COD/COC marker segment operation helper functions. @@ -760,58 +763,58 @@ static void jpc_cox_destroycompparms(jpc_coxcp_t *compparms) static int jpc_cox_getcompparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in, int prtflag, jpc_coxcp_t *compparms) { - uint_fast8_t tmp; - int i; - if (jpc_getuint8(in, &compparms->numdlvls) || - jpc_getuint8(in, &compparms->cblkwidthval) || - jpc_getuint8(in, &compparms->cblkheightval) || - jpc_getuint8(in, &compparms->cblksty) || - jpc_getuint8(in, &compparms->qmfbid)) { - return -1; - } - compparms->numrlvls = compparms->numdlvls + 1; - if (prtflag) { - for (i = 0; i < compparms->numrlvls; ++i) { - if (jpc_getuint8(in, &tmp)) { - jpc_cox_destroycompparms(compparms); - return -1; - } - compparms->rlvls[i].parwidthval = tmp & 0xf; - compparms->rlvls[i].parheightval = (tmp >> 4) & 0xf; - } + uint_fast8_t tmp; + int i; + if (jpc_getuint8(in, &compparms->numdlvls) || + jpc_getuint8(in, &compparms->cblkwidthval) || + jpc_getuint8(in, &compparms->cblkheightval) || + jpc_getuint8(in, &compparms->cblksty) || + jpc_getuint8(in, &compparms->qmfbid)) { + return -1; + } + compparms->numrlvls = compparms->numdlvls + 1; + if (prtflag) { + for (i = 0; i < compparms->numrlvls; ++i) { + if (jpc_getuint8(in, &tmp)) { + jpc_cox_destroycompparms(compparms); + return -1; + } + compparms->rlvls[i].parwidthval = tmp & 0xf; + compparms->rlvls[i].parheightval = (tmp >> 4) & 0xf; + } /* Sigh. This bit should be in the same field in both COC and COD mrk segs. */ compparms->csty |= JPC_COX_PRT; - } else { - } - if (jas_stream_eof(in)) { - jpc_cox_destroycompparms(compparms); - return -1; - } - return 0; + } else { + } + if (jas_stream_eof(in)) { + jpc_cox_destroycompparms(compparms); + return -1; + } + return 0; } static int jpc_cox_putcompparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out, int prtflag, jpc_coxcp_t *compparms) { - int i; - assert(compparms->numdlvls <= 32); - if (jpc_putuint8(out, compparms->numdlvls) || - jpc_putuint8(out, compparms->cblkwidthval) || - jpc_putuint8(out, compparms->cblkheightval) || - jpc_putuint8(out, compparms->cblksty) || - jpc_putuint8(out, compparms->qmfbid)) { - return -1; - } - if (prtflag) { - for (i = 0; i < compparms->numrlvls; ++i) { - if (jpc_putuint8(out, - ((compparms->rlvls[i].parheightval & 0xf) << 4) | - (compparms->rlvls[i].parwidthval & 0xf))) { - return -1; - } - } - } - return 0; + int i; + assert(compparms->numdlvls <= 32); + if (jpc_putuint8(out, compparms->numdlvls) || + jpc_putuint8(out, compparms->cblkwidthval) || + jpc_putuint8(out, compparms->cblkheightval) || + jpc_putuint8(out, compparms->cblksty) || + jpc_putuint8(out, compparms->qmfbid)) { + return -1; + } + if (prtflag) { + for (i = 0; i < compparms->numrlvls; ++i) { + if (jpc_putuint8(out, + ((compparms->rlvls[i].parheightval & 0xf) << 4) | + (compparms->rlvls[i].parwidthval & 0xf))) { + return -1; + } + } + } + return 0; } /******************************************************************************\ @@ -820,50 +823,50 @@ static int jpc_cox_putcompparms(jpc_ms_t *ms, jpc_cstate_t *cstate, static int jpc_rgn_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in) { - jpc_rgn_t *rgn = &ms->parms.rgn; - uint_fast8_t tmp; - if (cstate->numcomps <= 256) { - if (jpc_getuint8(in, &tmp)) { - return -1; - } - rgn->compno = tmp; - } else { - if (jpc_getuint16(in, &rgn->compno)) { - return -1; - } - } - if (jpc_getuint8(in, &rgn->roisty) || - jpc_getuint8(in, &rgn->roishift)) { - return -1; - } - return 0; + jpc_rgn_t *rgn = &ms->parms.rgn; + uint_fast8_t tmp; + if (cstate->numcomps <= 256) { + if (jpc_getuint8(in, &tmp)) { + return -1; + } + rgn->compno = tmp; + } else { + if (jpc_getuint16(in, &rgn->compno)) { + return -1; + } + } + if (jpc_getuint8(in, &rgn->roisty) || + jpc_getuint8(in, &rgn->roishift)) { + return -1; + } + return 0; } static int jpc_rgn_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out) { - jpc_rgn_t *rgn = &ms->parms.rgn; - if (cstate->numcomps <= 256) { - if (jpc_putuint8(out, rgn->compno)) { - return -1; - } - } else { - if (jpc_putuint16(out, rgn->compno)) { - return -1; - } - } - if (jpc_putuint8(out, rgn->roisty) || - jpc_putuint8(out, rgn->roishift)) { - return -1; - } - return 0; + jpc_rgn_t *rgn = &ms->parms.rgn; + if (cstate->numcomps <= 256) { + if (jpc_putuint8(out, rgn->compno)) { + return -1; + } + } else { + if (jpc_putuint16(out, rgn->compno)) { + return -1; + } + } + if (jpc_putuint8(out, rgn->roisty) || + jpc_putuint8(out, rgn->roishift)) { + return -1; + } + return 0; } static int jpc_rgn_dumpparms(jpc_ms_t *ms, FILE *out) { - jpc_rgn_t *rgn = &ms->parms.rgn; - fprintf(out, "compno = %d; roisty = %d; roishift = %d\n", - rgn->compno, rgn->roisty, rgn->roishift); - return 0; + jpc_rgn_t *rgn = &ms->parms.rgn; + fprintf(out, "compno = %d; roisty = %d; roishift = %d\n", + (int)rgn->compno, rgn->roisty, rgn->roishift); + return 0; } /******************************************************************************\ @@ -872,34 +875,34 @@ static int jpc_rgn_dumpparms(jpc_ms_t *ms, FILE *out) static void jpc_qcd_destroyparms(jpc_ms_t *ms) { - jpc_qcd_t *qcd = &ms->parms.qcd; - jpc_qcx_destroycompparms(&qcd->compparms); + jpc_qcd_t *qcd = &ms->parms.qcd; + jpc_qcx_destroycompparms(&qcd->compparms); } static int jpc_qcd_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in) { - jpc_qcxcp_t *compparms = &ms->parms.qcd.compparms; - return jpc_qcx_getcompparms(compparms, cstate, in, ms->len); + jpc_qcxcp_t *compparms = &ms->parms.qcd.compparms; + return jpc_qcx_getcompparms(compparms, cstate, in, ms->len); } static int jpc_qcd_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out) { - jpc_qcxcp_t *compparms = &ms->parms.qcd.compparms; - return jpc_qcx_putcompparms(compparms, cstate, out); + jpc_qcxcp_t *compparms = &ms->parms.qcd.compparms; + return jpc_qcx_putcompparms(compparms, cstate, out); } static int jpc_qcd_dumpparms(jpc_ms_t *ms, FILE *out) { - jpc_qcd_t *qcd = &ms->parms.qcd; - int i; - fprintf(out, "qntsty = %d; numguard = %d; numstepsizes = %d\n", - (int) qcd->compparms.qntsty, qcd->compparms.numguard, qcd->compparms.numstepsizes); - for (i = 0; i < qcd->compparms.numstepsizes; ++i) { - fprintf(out, "expn[%d] = 0x%04x; mant[%d] = 0x%04x;\n", - i, (unsigned) JPC_QCX_GETEXPN(qcd->compparms.stepsizes[i]), - i, (unsigned) JPC_QCX_GETMANT(qcd->compparms.stepsizes[i])); - } - return 0; + jpc_qcd_t *qcd = &ms->parms.qcd; + int i; + fprintf(out, "qntsty = %d; numguard = %d; numstepsizes = %d\n", + (int) qcd->compparms.qntsty, qcd->compparms.numguard, qcd->compparms.numstepsizes); + for (i = 0; i < qcd->compparms.numstepsizes; ++i) { + fprintf(out, "expn[%d] = 0x%04x; mant[%d] = 0x%04x;\n", + i, (unsigned) JPC_QCX_GETEXPN(qcd->compparms.stepsizes[i]), + i, (unsigned) JPC_QCX_GETMANT(qcd->compparms.stepsizes[i])); + } + return 0; } /******************************************************************************\ @@ -908,133 +911,134 @@ static int jpc_qcd_dumpparms(jpc_ms_t *ms, FILE *out) static void jpc_qcc_destroyparms(jpc_ms_t *ms) { - jpc_qcc_t *qcc = &ms->parms.qcc; - jpc_qcx_destroycompparms(&qcc->compparms); + jpc_qcc_t *qcc = &ms->parms.qcc; + jpc_qcx_destroycompparms(&qcc->compparms); } static int jpc_qcc_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in) { - jpc_qcc_t *qcc = &ms->parms.qcc; - uint_fast8_t tmp; - int len; - len = ms->len; - if (cstate->numcomps <= 256) { - jpc_getuint8(in, &tmp); - qcc->compno = tmp; - --len; - } else { - jpc_getuint16(in, &qcc->compno); - len -= 2; - } - if (jpc_qcx_getcompparms(&qcc->compparms, cstate, in, len)) { - return -1; - } - if (jas_stream_eof(in)) { - jpc_qcc_destroyparms(ms); - return -1; - } - return 0; + jpc_qcc_t *qcc = &ms->parms.qcc; + uint_fast8_t tmp; + int len; + len = ms->len; + if (cstate->numcomps <= 256) { + jpc_getuint8(in, &tmp); + qcc->compno = tmp; + --len; + } else { + jpc_getuint16(in, &qcc->compno); + len -= 2; + } + if (jpc_qcx_getcompparms(&qcc->compparms, cstate, in, len)) { + return -1; + } + if (jas_stream_eof(in)) { + jpc_qcc_destroyparms(ms); + return -1; + } + return 0; } static int jpc_qcc_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out) { - jpc_qcc_t *qcc = &ms->parms.qcc; - if (cstate->numcomps <= 256) { - jpc_putuint8(out, qcc->compno); - } else { - jpc_putuint16(out, qcc->compno); - } - if (jpc_qcx_putcompparms(&qcc->compparms, cstate, out)) { - return -1; - } - return 0; + jpc_qcc_t *qcc = &ms->parms.qcc; + if (cstate->numcomps <= 256) { + jpc_putuint8(out, qcc->compno); + } else { + jpc_putuint16(out, qcc->compno); + } + if (jpc_qcx_putcompparms(&qcc->compparms, cstate, out)) { + return -1; + } + return 0; } static int jpc_qcc_dumpparms(jpc_ms_t *ms, FILE *out) { - jpc_qcc_t *qcc = &ms->parms.qcc; - int i; - fprintf(out, "compno = %d; qntsty = %d; numguard = %d; " - "numstepsizes = %d\n", qcc->compno, qcc->compparms.qntsty, qcc->compparms.numguard, - qcc->compparms.numstepsizes); - for (i = 0; i < qcc->compparms.numstepsizes; ++i) { - fprintf(out, "expn[%d] = 0x%04x; mant[%d] = 0x%04x;\n", - i, (unsigned) JPC_QCX_GETEXPN(qcc->compparms.stepsizes[i]), - i, (unsigned) JPC_QCX_GETMANT(qcc->compparms.stepsizes[i])); - } - return 0; -} - -/******************************************************************************\ + jpc_qcc_t *qcc = &ms->parms.qcc; + int i; + fprintf(out, "compno = %d; qntsty = %d; numguard = %d; " + "numstepsizes = %d\n", + (int)qcc->compno, qcc->compparms.qntsty, qcc->compparms.numguard, + qcc->compparms.numstepsizes); + for (i = 0; i < qcc->compparms.numstepsizes; ++i) { + fprintf(out, "expn[%d] = 0x%04x; mant[%d] = 0x%04x;\n", + i, (unsigned) JPC_QCX_GETEXPN(qcc->compparms.stepsizes[i]), + i, (unsigned) JPC_QCX_GETMANT(qcc->compparms.stepsizes[i])); + } + return 0; +} + +/*****************************************************************************\ * QCD/QCC marker segment helper functions. -\******************************************************************************/ +\*****************************************************************************/ static void jpc_qcx_destroycompparms(jpc_qcxcp_t *compparms) { - if (compparms->stepsizes) { - jas_free(compparms->stepsizes); - } + if (compparms->stepsizes) { + jas_free(compparms->stepsizes); + } } static int jpc_qcx_getcompparms(jpc_qcxcp_t *compparms, jpc_cstate_t *cstate, jas_stream_t *in, uint_fast16_t len) { - uint_fast8_t tmp; - int n; - int i; - n = 0; - jpc_getuint8(in, &tmp); - ++n; - compparms->qntsty = tmp & 0x1f; - compparms->numguard = (tmp >> 5) & 7; - switch (compparms->qntsty) { - case JPC_QCX_SIQNT: - compparms->numstepsizes = 1; - break; - case JPC_QCX_NOQNT: - compparms->numstepsizes = (len - n); - break; - case JPC_QCX_SEQNT: - /* XXX - this is a hack */ - compparms->numstepsizes = (len - n) / 2; - break; - } + uint_fast8_t tmp; + int n; + int i; + n = 0; + jpc_getuint8(in, &tmp); + ++n; + compparms->qntsty = tmp & 0x1f; + compparms->numguard = (tmp >> 5) & 7; + switch (compparms->qntsty) { + case JPC_QCX_SIQNT: + compparms->numstepsizes = 1; + break; + case JPC_QCX_NOQNT: + compparms->numstepsizes = (len - n); + break; + case JPC_QCX_SEQNT: + /* XXX - this is a hack */ + compparms->numstepsizes = (len - n) / 2; + break; + } if (compparms->numstepsizes > 0) { - compparms->stepsizes = jas_malloc(compparms->numstepsizes * - sizeof(uint_fast32_t)); - assert(compparms->stepsizes); - for (i = 0; i < compparms->numstepsizes; ++i) { - if (compparms->qntsty == JPC_QCX_NOQNT) { - jpc_getuint8(in, &tmp); - compparms->stepsizes[i] = JPC_QCX_EXPN(tmp >> 3); - } else { - jpc_getuint16(in, &compparms->stepsizes[i]); - } - } + compparms->stepsizes = jas_malloc(compparms->numstepsizes * + sizeof(uint_fast32_t)); + assert(compparms->stepsizes); + for (i = 0; i < compparms->numstepsizes; ++i) { + if (compparms->qntsty == JPC_QCX_NOQNT) { + jpc_getuint8(in, &tmp); + compparms->stepsizes[i] = JPC_QCX_EXPN(tmp >> 3); + } else { + jpc_getuint16(in, &compparms->stepsizes[i]); + } + } } else { - compparms->stepsizes = 0; + compparms->stepsizes = 0; } - if (jas_stream_error(in) || jas_stream_eof(in)) { - jpc_qcx_destroycompparms(compparms); - return -1; - } - return 0; + if (jas_stream_error(in) || jas_stream_eof(in)) { + jpc_qcx_destroycompparms(compparms); + return -1; + } + return 0; } static int jpc_qcx_putcompparms(jpc_qcxcp_t *compparms, jpc_cstate_t *cstate, jas_stream_t *out) { - int i; - jpc_putuint8(out, ((compparms->numguard & 7) << 5) | compparms->qntsty); - for (i = 0; i < compparms->numstepsizes; ++i) { - if (compparms->qntsty == JPC_QCX_NOQNT) { - jpc_putuint8(out, JPC_QCX_GETEXPN( - compparms->stepsizes[i]) << 3); - } else { - jpc_putuint16(out, compparms->stepsizes[i]); - } - } - return 0; + int i; + jpc_putuint8(out, ((compparms->numguard & 7) << 5) | compparms->qntsty); + for (i = 0; i < compparms->numstepsizes; ++i) { + if (compparms->qntsty == JPC_QCX_NOQNT) { + jpc_putuint8(out, JPC_QCX_GETEXPN( + compparms->stepsizes[i]) << 3); + } else { + jpc_putuint16(out, compparms->stepsizes[i]); + } + } + return 0; } /******************************************************************************\ @@ -1043,27 +1047,27 @@ static int jpc_qcx_putcompparms(jpc_qcxcp_t *compparms, jpc_cstate_t *cstate, static int jpc_sop_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in) { - jpc_sop_t *sop = &ms->parms.sop; - if (jpc_getuint16(in, &sop->seqno)) { - return -1; - } - return 0; + jpc_sop_t *sop = &ms->parms.sop; + if (jpc_getuint16(in, &sop->seqno)) { + return -1; + } + return 0; } static int jpc_sop_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out) { - jpc_sop_t *sop = &ms->parms.sop; - if (jpc_putuint16(out, sop->seqno)) { - return -1; - } - return 0; + jpc_sop_t *sop = &ms->parms.sop; + if (jpc_putuint16(out, sop->seqno)) { + return -1; + } + return 0; } static int jpc_sop_dumpparms(jpc_ms_t *ms, FILE *out) { - jpc_sop_t *sop = &ms->parms.sop; - fprintf(out, "seqno = %d;\n", sop->seqno); - return 0; + jpc_sop_t *sop = &ms->parms.sop; + fprintf(out, "seqno = %d;\n", (int)sop->seqno); + return 0; } /******************************************************************************\ @@ -1072,61 +1076,61 @@ static int jpc_sop_dumpparms(jpc_ms_t *ms, FILE *out) static void jpc_ppm_destroyparms(jpc_ms_t *ms) { - jpc_ppm_t *ppm = &ms->parms.ppm; - if (ppm->data) { - jas_free(ppm->data); - } + jpc_ppm_t *ppm = &ms->parms.ppm; + if (ppm->data) { + jas_free(ppm->data); + } } static int jpc_ppm_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in) { - jpc_ppm_t *ppm = &ms->parms.ppm; - - ppm->data = 0; - - if (ms->len < 1) { - goto error; - } - if (jpc_getuint8(in, &ppm->ind)) { - goto error; - } - - ppm->len = ms->len - 1; - if (ppm->len > 0) { - if (!(ppm->data = jas_malloc(ppm->len * sizeof(unsigned char)))) { - goto error; - } - if (jas_stream_read(in, ppm->data, ppm->len) != ppm->len) { - goto error; - } - } else { - ppm->data = 0; - } - return 0; + jpc_ppm_t *ppm = &ms->parms.ppm; + + ppm->data = 0; + + if (ms->len < 1) { + goto error; + } + if (jpc_getuint8(in, &ppm->ind)) { + goto error; + } + + ppm->len = ms->len - 1; + if (ppm->len > 0) { + if (!(ppm->data = jas_malloc(ppm->len * sizeof(unsigned char)))) { + goto error; + } + if (jas_stream_read(in, ppm->data, ppm->len) != ppm->len) { + goto error; + } + } else { + ppm->data = 0; + } + return 0; error: - jpc_ppm_destroyparms(ms); - return -1; + jpc_ppm_destroyparms(ms); + return -1; } static int jpc_ppm_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out) { - jpc_ppm_t *ppm = &ms->parms.ppm; - if (jas_stream_write(out, (char *) ppm->data, ppm->len) != ppm->len) { - return -1; - } - return 0; + jpc_ppm_t *ppm = &ms->parms.ppm; + if (jas_stream_write(out, (char *) ppm->data, ppm->len) != ppm->len) { + return -1; + } + return 0; } static int jpc_ppm_dumpparms(jpc_ms_t *ms, FILE *out) { - jpc_ppm_t *ppm = &ms->parms.ppm; - fprintf(out, "ind=%d; len = %d;\n", ppm->ind, ppm->len); - if (ppm->len > 0) { - fprintf(out, "data =\n"); - jas_memdump(out, ppm->data, ppm->len); - } - return 0; + jpc_ppm_t *ppm = &ms->parms.ppm; + fprintf(out, "ind=%d; len = %d;\n", ppm->ind, (int)ppm->len); + if (ppm->len > 0) { + fprintf(out, "data =\n"); + jas_memdump(out, ppm->data, ppm->len); + } + return 0; } /******************************************************************************\ @@ -1135,169 +1139,169 @@ static int jpc_ppm_dumpparms(jpc_ms_t *ms, FILE *out) static void jpc_ppt_destroyparms(jpc_ms_t *ms) { - jpc_ppt_t *ppt = &ms->parms.ppt; - if (ppt->data) { - jas_free(ppt->data); - } + jpc_ppt_t *ppt = &ms->parms.ppt; + if (ppt->data) { + jas_free(ppt->data); + } } static int jpc_ppt_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in) { - jpc_ppt_t *ppt = &ms->parms.ppt; - ppt->data = 0; - - if (ms->len < 1) { - goto error; - } - if (jpc_getuint8(in, &ppt->ind)) { - goto error; - } - ppt->len = ms->len - 1; - if (ppt->len > 0) { - if (!(ppt->data = jas_malloc(ppt->len * sizeof(unsigned char)))) { - goto error; - } - if (jas_stream_read(in, (char *) ppt->data, ppt->len) != ppt->len) { - goto error; - } - } else { - ppt->data = 0; - } - return 0; + jpc_ppt_t *ppt = &ms->parms.ppt; + ppt->data = 0; + + if (ms->len < 1) { + goto error; + } + if (jpc_getuint8(in, &ppt->ind)) { + goto error; + } + ppt->len = ms->len - 1; + if (ppt->len > 0) { + if (!(ppt->data = jas_malloc(ppt->len * sizeof(unsigned char)))) { + goto error; + } + if (jas_stream_read(in, (char *) ppt->data, ppt->len) != ppt->len) { + goto error; + } + } else { + ppt->data = 0; + } + return 0; error: - jpc_ppt_destroyparms(ms); - return -1; + jpc_ppt_destroyparms(ms); + return -1; } static int jpc_ppt_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out) { - jpc_ppt_t *ppt = &ms->parms.ppt; - if (jpc_putuint8(out, ppt->ind)) { - return -1; - } - if (jas_stream_write(out, (char *) ppt->data, ppt->len) != ppt->len) { - return -1; - } - return 0; + jpc_ppt_t *ppt = &ms->parms.ppt; + if (jpc_putuint8(out, ppt->ind)) { + return -1; + } + if (jas_stream_write(out, (char *) ppt->data, ppt->len) != ppt->len) { + return -1; + } + return 0; } static int jpc_ppt_dumpparms(jpc_ms_t *ms, FILE *out) { - jpc_ppt_t *ppt = &ms->parms.ppt; - fprintf(out, "ind=%d; len = %d;\n", ppt->ind, ppt->len); - if (ppt->len > 0) { - fprintf(out, "data =\n"); - jas_memdump(out, ppt->data, ppt->len); - } - return 0; + jpc_ppt_t *ppt = &ms->parms.ppt; + fprintf(out, "ind=%d; len = %d;\n", ppt->ind, (int)ppt->len); + if (ppt->len > 0) { + fprintf(out, "data =\n"); + jas_memdump(out, ppt->data, ppt->len); + } + return 0; } -/******************************************************************************\ +/*****************************************************************************\ * POC marker segment operations. -\******************************************************************************/ +\*****************************************************************************/ static void jpc_poc_destroyparms(jpc_ms_t *ms) { - jpc_poc_t *poc = &ms->parms.poc; - if (poc->pchgs) { - jas_free(poc->pchgs); - } + jpc_poc_t *poc = &ms->parms.poc; + if (poc->pchgs) { + jas_free(poc->pchgs); + } } static int jpc_poc_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in) { - jpc_poc_t *poc = &ms->parms.poc; - jpc_pocpchg_t *pchg; - int pchgno; - uint_fast8_t tmp; - poc->numpchgs = (cstate->numcomps > 256) ? (ms->len / 9) : - (ms->len / 7); - if (!(poc->pchgs = jas_malloc(poc->numpchgs * sizeof(jpc_pocpchg_t)))) { - goto error; - } - for (pchgno = 0, pchg = poc->pchgs; pchgno < poc->numpchgs; ++pchgno, - ++pchg) { - if (jpc_getuint8(in, &pchg->rlvlnostart)) { - goto error; - } - if (cstate->numcomps > 256) { - if (jpc_getuint16(in, &pchg->compnostart)) { - goto error; - } - } else { - if (jpc_getuint8(in, &tmp)) { - goto error; - }; - pchg->compnostart = tmp; - } - if (jpc_getuint16(in, &pchg->lyrnoend) || - jpc_getuint8(in, &pchg->rlvlnoend)) { - goto error; - } - if (cstate->numcomps > 256) { - if (jpc_getuint16(in, &pchg->compnoend)) { - goto error; - } - } else { - if (jpc_getuint8(in, &tmp)) { - goto error; - } - pchg->compnoend = tmp; - } - if (jpc_getuint8(in, &pchg->prgord)) { - goto error; - } - if (pchg->rlvlnostart > pchg->rlvlnoend || - pchg->compnostart > pchg->compnoend) { - goto error; - } - } - return 0; + jpc_poc_t *poc = &ms->parms.poc; + jpc_pocpchg_t *pchg; + int pchgno; + uint_fast8_t tmp; + poc->numpchgs = (cstate->numcomps > 256) ? (ms->len / 9) : + (ms->len / 7); + if (!(poc->pchgs = jas_malloc(poc->numpchgs * sizeof(jpc_pocpchg_t)))) { + goto error; + } + for (pchgno = 0, pchg = poc->pchgs; pchgno < poc->numpchgs; ++pchgno, + ++pchg) { + if (jpc_getuint8(in, &pchg->rlvlnostart)) { + goto error; + } + if (cstate->numcomps > 256) { + if (jpc_getuint16(in, &pchg->compnostart)) { + goto error; + } + } else { + if (jpc_getuint8(in, &tmp)) { + goto error; + }; + pchg->compnostart = tmp; + } + if (jpc_getuint16(in, &pchg->lyrnoend) || + jpc_getuint8(in, &pchg->rlvlnoend)) { + goto error; + } + if (cstate->numcomps > 256) { + if (jpc_getuint16(in, &pchg->compnoend)) { + goto error; + } + } else { + if (jpc_getuint8(in, &tmp)) { + goto error; + } + pchg->compnoend = tmp; + } + if (jpc_getuint8(in, &pchg->prgord)) { + goto error; + } + if (pchg->rlvlnostart > pchg->rlvlnoend || + pchg->compnostart > pchg->compnoend) { + goto error; + } + } + return 0; error: - jpc_poc_destroyparms(ms); - return -1; + jpc_poc_destroyparms(ms); + return -1; } static int jpc_poc_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out) { - jpc_poc_t *poc = &ms->parms.poc; - jpc_pocpchg_t *pchg; - int pchgno; - for (pchgno = 0, pchg = poc->pchgs; pchgno < poc->numpchgs; ++pchgno, - ++pchg) { - if (jpc_putuint8(out, pchg->rlvlnostart) || - ((cstate->numcomps > 256) ? - jpc_putuint16(out, pchg->compnostart) : - jpc_putuint8(out, pchg->compnostart)) || - jpc_putuint16(out, pchg->lyrnoend) || - jpc_putuint8(out, pchg->rlvlnoend) || - ((cstate->numcomps > 256) ? - jpc_putuint16(out, pchg->compnoend) : - jpc_putuint8(out, pchg->compnoend)) || - jpc_putuint8(out, pchg->prgord)) { - return -1; - } - } - return 0; + jpc_poc_t *poc = &ms->parms.poc; + jpc_pocpchg_t *pchg; + int pchgno; + for (pchgno = 0, pchg = poc->pchgs; pchgno < poc->numpchgs; ++pchgno, + ++pchg) { + if (jpc_putuint8(out, pchg->rlvlnostart) || + ((cstate->numcomps > 256) ? + jpc_putuint16(out, pchg->compnostart) : + jpc_putuint8(out, pchg->compnostart)) || + jpc_putuint16(out, pchg->lyrnoend) || + jpc_putuint8(out, pchg->rlvlnoend) || + ((cstate->numcomps > 256) ? + jpc_putuint16(out, pchg->compnoend) : + jpc_putuint8(out, pchg->compnoend)) || + jpc_putuint8(out, pchg->prgord)) { + return -1; + } + } + return 0; } static int jpc_poc_dumpparms(jpc_ms_t *ms, FILE *out) { - jpc_poc_t *poc = &ms->parms.poc; - jpc_pocpchg_t *pchg; - int pchgno; - for (pchgno = 0, pchg = poc->pchgs; pchgno < poc->numpchgs; - ++pchgno, ++pchg) { - fprintf(out, "po[%d] = %d; ", pchgno, pchg->prgord); - fprintf(out, "cs[%d] = %d; ce[%d] = %d; ", - pchgno, pchg->compnostart, pchgno, pchg->compnoend); - fprintf(out, "rs[%d] = %d; re[%d] = %d; ", - pchgno, pchg->rlvlnostart, pchgno, pchg->rlvlnoend); - fprintf(out, "le[%d] = %d\n", pchgno, pchg->lyrnoend); - } - return 0; + jpc_poc_t *poc = &ms->parms.poc; + jpc_pocpchg_t *pchg; + int pchgno; + for (pchgno = 0, pchg = poc->pchgs; pchgno < poc->numpchgs; + ++pchgno, ++pchg) { + fprintf(out, "po[%d] = %d; ", pchgno, pchg->prgord); + fprintf(out, "cs[%d] = %d; ce[%d] = %d; ", + pchgno, (int)pchg->compnostart, pchgno, (int)pchg->compnoend); + fprintf(out, "rs[%d] = %d; re[%d] = %d; ", + pchgno, pchg->rlvlnostart, pchgno, pchg->rlvlnoend); + fprintf(out, "le[%d] = %d\n", pchgno, (int)pchg->lyrnoend); + } + return 0; } /******************************************************************************\ @@ -1306,58 +1310,58 @@ static int jpc_poc_dumpparms(jpc_ms_t *ms, FILE *out) static void jpc_crg_destroyparms(jpc_ms_t *ms) { - jpc_crg_t *crg = &ms->parms.crg; - if (crg->comps) { - jas_free(crg->comps); - } + jpc_crg_t *crg = &ms->parms.crg; + if (crg->comps) { + jas_free(crg->comps); + } } static int jpc_crg_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in) { - jpc_crg_t *crg = &ms->parms.crg; - jpc_crgcomp_t *comp; - uint_fast16_t compno; - crg->numcomps = cstate->numcomps; - if (!(crg->comps = jas_malloc(cstate->numcomps * sizeof(uint_fast16_t)))) { - return -1; - } - for (compno = 0, comp = crg->comps; compno < cstate->numcomps; - ++compno, ++comp) { - if (jpc_getuint16(in, &comp->hoff) || - jpc_getuint16(in, &comp->voff)) { - jpc_crg_destroyparms(ms); - return -1; - } - } - return 0; + jpc_crg_t *crg = &ms->parms.crg; + jpc_crgcomp_t *comp; + uint_fast16_t compno; + crg->numcomps = cstate->numcomps; + if (!(crg->comps = jas_malloc(cstate->numcomps * sizeof(uint_fast16_t)))) { + return -1; + } + for (compno = 0, comp = crg->comps; compno < cstate->numcomps; + ++compno, ++comp) { + if (jpc_getuint16(in, &comp->hoff) || + jpc_getuint16(in, &comp->voff)) { + jpc_crg_destroyparms(ms); + return -1; + } + } + return 0; } static int jpc_crg_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out) { - jpc_crg_t *crg = &ms->parms.crg; - int compno; - jpc_crgcomp_t *comp; - for (compno = 0, comp = crg->comps; compno < crg->numcomps; ++compno, - ++comp) { - if (jpc_putuint16(out, comp->hoff) || - jpc_putuint16(out, comp->voff)) { - return -1; - } - } - return 0; + jpc_crg_t *crg = &ms->parms.crg; + int compno; + jpc_crgcomp_t *comp; + for (compno = 0, comp = crg->comps; compno < crg->numcomps; ++compno, + ++comp) { + if (jpc_putuint16(out, comp->hoff) || + jpc_putuint16(out, comp->voff)) { + return -1; + } + } + return 0; } static int jpc_crg_dumpparms(jpc_ms_t *ms, FILE *out) { - jpc_crg_t *crg = &ms->parms.crg; - int compno; - jpc_crgcomp_t *comp; - for (compno = 0, comp = crg->comps; compno < crg->numcomps; ++compno, - ++comp) { - fprintf(out, "hoff[%d] = %d; voff[%d] = %d\n", compno, - comp->hoff, compno, comp->voff); - } - return 0; + jpc_crg_t *crg = &ms->parms.crg; + int compno; + jpc_crgcomp_t *comp; + for (compno = 0, comp = crg->comps; compno < crg->numcomps; ++compno, + ++comp) { + fprintf(out, "hoff[%d] = %d; voff[%d] = %d\n", + compno, (int)comp->hoff, compno, (int)comp->voff); + } + return 0; } /******************************************************************************\ @@ -1366,112 +1370,108 @@ static int jpc_crg_dumpparms(jpc_ms_t *ms, FILE *out) static void jpc_com_destroyparms(jpc_ms_t *ms) { - jpc_com_t *com = &ms->parms.com; - if (com->data) { - jas_free(com->data); - } + jpc_com_t *com = &ms->parms.com; + if (com->data) { + jas_free(com->data); + } } static int jpc_com_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in) { - jpc_com_t *com = &ms->parms.com; - if (jpc_getuint16(in, &com->regid)) { - return -1; - } - com->len = ms->len - 2; - if (com->len > 0) { - if (!(com->data = jas_malloc(com->len))) { - return -1; - } - if (jas_stream_read(in, com->data, com->len) != com->len) { - return -1; - } - } else { - com->data = 0; - } - return 0; + jpc_com_t *com = &ms->parms.com; + if (jpc_getuint16(in, &com->regid)) { + return -1; + } + com->len = ms->len - 2; + if (com->len > 0) { + if (!(com->data = jas_malloc(com->len))) { + return -1; + } + if (jas_stream_read(in, com->data, com->len) != com->len) { + return -1; + } + } else { + com->data = 0; + } + return 0; } static int jpc_com_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out) { - jpc_com_t *com = &ms->parms.com; - if (jpc_putuint16(out, com->regid)) { - return -1; - } - if (jas_stream_write(out, com->data, com->len) != com->len) { - return -1; - } - return 0; + jpc_com_t *com = &ms->parms.com; + if (jpc_putuint16(out, com->regid)) { + return -1; + } + if (jas_stream_write(out, com->data, com->len) != com->len) { + return -1; + } + return 0; } static int jpc_com_dumpparms(jpc_ms_t *ms, FILE *out) { - jpc_com_t *com = &ms->parms.com; - int i; - int printable; - fprintf(out, "regid = %d;\n", com->regid); - printable = 1; - for (i = 0; i < com->len; ++i) { - if (!isprint(com->data[i])) { - printable = 0; - break; - } - } - if (printable) { - fprintf(out, "data = "); - fwrite(com->data, sizeof(char), com->len, out); - fprintf(out, "\n"); - } - return 0; -} - -/******************************************************************************\ + jpc_com_t *com = &ms->parms.com; + int i; + int printable; + fprintf(out, "regid = %d;\n", (int)com->regid); + printable = 1; + for (i = 0, printable = 1; i < com->len && printable; ++i) { + if (!isprint(com->data[i])) + printable = 0; + } + if (printable) { + fprintf(out, "data = "); + fwrite(com->data, sizeof(char), com->len, out); + fprintf(out, "\n"); + } + return 0; +} + +/*****************************************************************************\ * Operations for unknown types of marker segments. -\******************************************************************************/ +\*****************************************************************************/ static void jpc_unk_destroyparms(jpc_ms_t *ms) { - jpc_unk_t *unk = &ms->parms.unk; - if (unk->data) { - jas_free(unk->data); - } + jpc_unk_t *unk = &ms->parms.unk; + if (unk->data) { + jas_free(unk->data); + } } static int jpc_unk_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in) { - jpc_unk_t *unk = &ms->parms.unk; + jpc_unk_t *unk = &ms->parms.unk; - if (ms->len > 0) { - if (!(unk->data = jas_malloc(ms->len * sizeof(unsigned char)))) { - return -1; - } - if (jas_stream_read(in, (char *) unk->data, ms->len) != ms->len) { - jas_free(unk->data); - return -1; - } - unk->len = ms->len; - } else { - unk->data = 0; - unk->len = 0; - } - return 0; + if (ms->len > 0) { + if (!(unk->data = jas_malloc(ms->len * sizeof(unsigned char)))) { + return -1; + } + if (jas_stream_read(in, (char *) unk->data, ms->len) != ms->len) { + jas_free(unk->data); + return -1; + } + unk->len = ms->len; + } else { + unk->data = 0; + unk->len = 0; + } + return 0; } static int jpc_unk_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out) { - /* If this function is called, we are trying to write an unsupported - type of marker segment. Return with an error indication. */ - return -1; + return -1; } static int jpc_unk_dumpparms(jpc_ms_t *ms, FILE *out) { - int i; - jpc_unk_t *unk = &ms->parms.unk; - for (i = 0; i < unk->len; ++i) { - fprintf(out, "%02x ", unk->data[i]); - } - return 0; + int i; + jpc_unk_t *unk = &ms->parms.unk; + for (i = 0; i < unk->len; ++i) { + fprintf(out, "%02x ", unk->data[i]); + } + return 0; } /******************************************************************************\ @@ -1480,86 +1480,86 @@ static int jpc_unk_dumpparms(jpc_ms_t *ms, FILE *out) int jpc_getuint8(jas_stream_t *in, uint_fast8_t *val) { - int c; - if ((c = jas_stream_getc(in)) == EOF) { - return -1; - } - if (val) { - *val = c; - } - return 0; + int c; + if ((c = jas_stream_getc(in)) == EOF) { + return -1; + } + if (val) { + *val = c; + } + return 0; } int jpc_putuint8(jas_stream_t *out, uint_fast8_t val) { - if (jas_stream_putc(out, val & 0xff) == EOF) { - return -1; - } - return 0; + if (jas_stream_putc(out, val & 0xff) == EOF) { + return -1; + } + return 0; } int jpc_getuint16(jas_stream_t *in, uint_fast16_t *val) { - uint_fast16_t v; - int c; - if ((c = jas_stream_getc(in)) == EOF) { - return -1; - } - v = c; - if ((c = jas_stream_getc(in)) == EOF) { - return -1; - } - v = (v << 8) | c; - if (val) { - *val = v; - } - return 0; + uint_fast16_t v; + int c; + if ((c = jas_stream_getc(in)) == EOF) { + return -1; + } + v = c; + if ((c = jas_stream_getc(in)) == EOF) { + return -1; + } + v = (v << 8) | c; + if (val) { + *val = v; + } + return 0; } int jpc_putuint16(jas_stream_t *out, uint_fast16_t val) { - if (jas_stream_putc(out, (val >> 8) & 0xff) == EOF || - jas_stream_putc(out, val & 0xff) == EOF) { - return -1; - } - return 0; + if (jas_stream_putc(out, (val >> 8) & 0xff) == EOF || + jas_stream_putc(out, val & 0xff) == EOF) { + return -1; + } + return 0; } int jpc_getuint32(jas_stream_t *in, uint_fast32_t *val) { - uint_fast32_t v; - int c; - if ((c = jas_stream_getc(in)) == EOF) { - return -1; - } - v = c; - if ((c = jas_stream_getc(in)) == EOF) { - return -1; - } - v = (v << 8) | c; - if ((c = jas_stream_getc(in)) == EOF) { - return -1; - } - v = (v << 8) | c; - if ((c = jas_stream_getc(in)) == EOF) { - return -1; - } - v = (v << 8) | c; - if (val) { - *val = v; - } - return 0; + uint_fast32_t v; + int c; + if ((c = jas_stream_getc(in)) == EOF) { + return -1; + } + v = c; + if ((c = jas_stream_getc(in)) == EOF) { + return -1; + } + v = (v << 8) | c; + if ((c = jas_stream_getc(in)) == EOF) { + return -1; + } + v = (v << 8) | c; + if ((c = jas_stream_getc(in)) == EOF) { + return -1; + } + v = (v << 8) | c; + if (val) { + *val = v; + } + return 0; } int jpc_putuint32(jas_stream_t *out, uint_fast32_t val) { - if (jas_stream_putc(out, (val >> 24) & 0xff) == EOF || - jas_stream_putc(out, (val >> 16) & 0xff) == EOF || - jas_stream_putc(out, (val >> 8) & 0xff) == EOF || - jas_stream_putc(out, val & 0xff) == EOF) { - return -1; - } - return 0; + if (jas_stream_putc(out, (val >> 24) & 0xff) == EOF || + jas_stream_putc(out, (val >> 16) & 0xff) == EOF || + jas_stream_putc(out, (val >> 8) & 0xff) == EOF || + jas_stream_putc(out, val & 0xff) == EOF) { + return -1; + } + return 0; } /******************************************************************************\ @@ -1568,47 +1568,47 @@ int jpc_putuint32(jas_stream_t *out, uint_fast32_t val) static jpc_mstabent_t *jpc_mstab_lookup(int id) { - jpc_mstabent_t *mstabent; - for (mstabent = jpc_mstab;; ++mstabent) { - if (mstabent->id == id || mstabent->id < 0) { - return mstabent; - } - } - assert(0); - return 0; + jpc_mstabent_t *mstabent; + for (mstabent = jpc_mstab;; ++mstabent) { + if (mstabent->id == id || mstabent->id < 0) { + return mstabent; + } + } + assert(0); + return 0; } int jpc_validate(jas_stream_t *in) { - int n; - int i; - unsigned char buf[2]; - - assert(JAS_STREAM_MAXPUTBACK >= 2); - - if ((n = jas_stream_read(in, (char *) buf, 2)) < 0) { - return -1; - } - for (i = n - 1; i >= 0; --i) { - if (jas_stream_ungetc(in, buf[i]) == EOF) { - return -1; - } - } - if (n < 2) { - return -1; - } - if (buf[0] == (JPC_MS_SOC >> 8) && buf[1] == (JPC_MS_SOC & 0xff)) { - return 0; - } - return -1; + int n; + int i; + unsigned char buf[2]; + + assert(JAS_STREAM_MAXPUTBACK >= 2); + + if ((n = jas_stream_read(in, (char *) buf, 2)) < 0) { + return -1; + } + for (i = n - 1; i >= 0; --i) { + if (jas_stream_ungetc(in, buf[i]) == EOF) { + return -1; + } + } + if (n < 2) { + return -1; + } + if (buf[0] == (JPC_MS_SOC >> 8) && buf[1] == (JPC_MS_SOC & 0xff)) { + return 0; + } + return -1; } int jpc_getdata(jas_stream_t *in, jas_stream_t *out, long len) { - return jas_stream_copy(out, in, len); + return jas_stream_copy(out, in, len); } int jpc_putdata(jas_stream_t *out, jas_stream_t *in, long len) { - return jas_stream_copy(out, in, len); + return jas_stream_copy(out, in, len); } diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_cs.h b/converter/other/jpeg2000/libjasper/jpc/jpc_cs.h index 07a046d1..4bff677c 100644 --- a/converter/other/jpeg2000/libjasper/jpc/jpc_cs.h +++ b/converter/other/jpeg2000/libjasper/jpc/jpc_cs.h @@ -188,7 +188,7 @@ typedef struct { /* The tile number. */ uint_fast16_t tileno; - /* The combined length of the marker segment and its auxilary data + /* The combined length of the marker segment and its auxiliary data (i.e., packet data). */ uint_fast32_t len; diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_dec.c b/converter/other/jpeg2000/libjasper/jpc/jpc_dec.c index 42980225..72bd0126 100644 --- a/converter/other/jpeg2000/libjasper/jpc/jpc_dec.c +++ b/converter/other/jpeg2000/libjasper/jpc/jpc_dec.c @@ -114,14 +114,16 @@ * $Id$ */ -/******************************************************************************\ +/*****************************************************************************\ * Includes. -\******************************************************************************/ +\*****************************************************************************/ #include #include #include +#include "pm.h" + #include "jasper/jas_types.h" #include "jasper/jas_math.h" #include "jasper/jas_tvp.h" @@ -136,34 +138,34 @@ #include "jpc_t1dec.h" #include "jpc_math.h" -/******************************************************************************\ +/*****************************************************************************\ * -\******************************************************************************/ +\*****************************************************************************/ -#define JPC_MHSOC 0x0001 +#define JPC_MHSOC 0x0001 /* In the main header, expecting a SOC marker segment. */ -#define JPC_MHSIZ 0x0002 +#define JPC_MHSIZ 0x0002 /* In the main header, expecting a SIZ marker segment. */ -#define JPC_MH 0x0004 +#define JPC_MH 0x0004 /* In the main header, expecting "other" marker segments. */ -#define JPC_TPHSOT 0x0008 +#define JPC_TPHSOT 0x0008 /* In a tile-part header, expecting a SOT marker segment. */ -#define JPC_TPH 0x0010 +#define JPC_TPH 0x0010 /* In a tile-part header, expecting "other" marker segments. */ -#define JPC_MT 0x0020 +#define JPC_MT 0x0020 /* In the main trailer. */ typedef struct { - uint_fast16_t id; - /* The marker segment type. */ + uint_fast16_t id; + /* The marker segment type. */ - int validstates; - /* The states in which this type of marker segment can be - validly encountered. */ + int validstates; + /* The states in which this type of marker segment can be + validly encountered. */ - int (*action)(jpc_dec_t *dec, jpc_ms_t *ms); - /* The action to take upon encountering this type of marker segment. */ + int (*action)(jpc_dec_t *dec, jpc_ms_t *ms); + /* The action to take upon encountering this type of marker segment. */ } jpc_dec_mstabent_t; @@ -172,13 +174,13 @@ typedef struct { \******************************************************************************/ /* COD/COC parameters have been specified. */ -#define JPC_CSET 0x0001 +#define JPC_CSET 0x0001 /* QCD/QCC parameters have been specified. */ -#define JPC_QSET 0x0002 +#define JPC_QSET 0x0002 /* COD/COC parameters set from a COC marker segment. */ -#define JPC_COC 0x0004 +#define JPC_COC 0x0004 /* QCD/QCC parameters set from a QCC marker segment. */ -#define JPC_QCC 0x0008 +#define JPC_QCC 0x0008 /******************************************************************************\ * Local function prototypes. @@ -253,134 +255,134 @@ static int jpc_dec_parseopts(char *optstr, jpc_dec_importopts_t *opts); \******************************************************************************/ jpc_dec_mstabent_t jpc_dec_mstab[] = { - {JPC_MS_SOC, JPC_MHSOC, jpc_dec_process_soc}, - {JPC_MS_SOT, JPC_MH | JPC_TPHSOT, jpc_dec_process_sot}, - {JPC_MS_SOD, JPC_TPH, jpc_dec_process_sod}, - {JPC_MS_EOC, JPC_TPHSOT, jpc_dec_process_eoc}, - {JPC_MS_SIZ, JPC_MHSIZ, jpc_dec_process_siz}, - {JPC_MS_COD, JPC_MH | JPC_TPH, jpc_dec_process_cod}, - {JPC_MS_COC, JPC_MH | JPC_TPH, jpc_dec_process_coc}, - {JPC_MS_RGN, JPC_MH | JPC_TPH, jpc_dec_process_rgn}, - {JPC_MS_QCD, JPC_MH | JPC_TPH, jpc_dec_process_qcd}, - {JPC_MS_QCC, JPC_MH | JPC_TPH, jpc_dec_process_qcc}, - {JPC_MS_POC, JPC_MH | JPC_TPH, jpc_dec_process_poc}, - {JPC_MS_TLM, JPC_MH, 0}, - {JPC_MS_PLM, JPC_MH, 0}, - {JPC_MS_PLT, JPC_TPH, 0}, - {JPC_MS_PPM, JPC_MH, jpc_dec_process_ppm}, - {JPC_MS_PPT, JPC_TPH, jpc_dec_process_ppt}, - {JPC_MS_SOP, 0, 0}, - {JPC_MS_CRG, JPC_MH, jpc_dec_process_crg}, - {JPC_MS_COM, JPC_MH | JPC_TPH, jpc_dec_process_com}, - {0, JPC_MH | JPC_TPH, jpc_dec_process_unk} + {JPC_MS_SOC, JPC_MHSOC, jpc_dec_process_soc}, + {JPC_MS_SOT, JPC_MH | JPC_TPHSOT, jpc_dec_process_sot}, + {JPC_MS_SOD, JPC_TPH, jpc_dec_process_sod}, + {JPC_MS_EOC, JPC_TPHSOT, jpc_dec_process_eoc}, + {JPC_MS_SIZ, JPC_MHSIZ, jpc_dec_process_siz}, + {JPC_MS_COD, JPC_MH | JPC_TPH, jpc_dec_process_cod}, + {JPC_MS_COC, JPC_MH | JPC_TPH, jpc_dec_process_coc}, + {JPC_MS_RGN, JPC_MH | JPC_TPH, jpc_dec_process_rgn}, + {JPC_MS_QCD, JPC_MH | JPC_TPH, jpc_dec_process_qcd}, + {JPC_MS_QCC, JPC_MH | JPC_TPH, jpc_dec_process_qcc}, + {JPC_MS_POC, JPC_MH | JPC_TPH, jpc_dec_process_poc}, + {JPC_MS_TLM, JPC_MH, 0}, + {JPC_MS_PLM, JPC_MH, 0}, + {JPC_MS_PLT, JPC_TPH, 0}, + {JPC_MS_PPM, JPC_MH, jpc_dec_process_ppm}, + {JPC_MS_PPT, JPC_TPH, jpc_dec_process_ppt}, + {JPC_MS_SOP, 0, 0}, + {JPC_MS_CRG, JPC_MH, jpc_dec_process_crg}, + {JPC_MS_COM, JPC_MH | JPC_TPH, jpc_dec_process_com}, + {0, JPC_MH | JPC_TPH, jpc_dec_process_unk} }; -/******************************************************************************\ +/*****************************************************************************\ * The main entry point for the JPEG-2000 decoder. -\******************************************************************************/ +\*****************************************************************************/ jas_image_t *jpc_decode(jas_stream_t *in, char *optstr) { - jpc_dec_importopts_t opts; - jpc_dec_t *dec; - jas_image_t *image; + jpc_dec_importopts_t opts; + jpc_dec_t *dec; + jas_image_t *image; - dec = 0; + dec = 0; - if (jpc_dec_parseopts(optstr, &opts)) { - goto error; - } + if (jpc_dec_parseopts(optstr, &opts)) { + goto error; + } - jpc_initluts(); + jpc_initluts(); - if (!(dec = jpc_dec_create(&opts, in))) { - goto error; - } + if (!(dec = jpc_dec_create(&opts, in))) { + goto error; + } - /* Do most of the work. */ - if (jpc_dec_decode(dec)) { - goto error; - } + /* Do most of the work. */ + if (jpc_dec_decode(dec)) { + goto error; + } - if (jas_image_numcmpts(dec->image) >= 3) { - jas_image_setcolorspace(dec->image, JAS_IMAGE_CS_RGB); - jas_image_setcmpttype(dec->image, 0, - JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_R)); - jas_image_setcmpttype(dec->image, 1, - JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_G)); - jas_image_setcmpttype(dec->image, 2, - JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_B)); - } else { - jas_image_setcolorspace(dec->image, JAS_IMAGE_CS_GRAY); - jas_image_setcmpttype(dec->image, 0, - JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_GRAY_Y)); - } + if (jas_image_numcmpts(dec->image) >= 3) { + jas_image_setcolorspace(dec->image, JAS_IMAGE_CS_RGB); + jas_image_setcmpttype(dec->image, 0, + JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_R)); + jas_image_setcmpttype(dec->image, 1, + JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_G)); + jas_image_setcmpttype(dec->image, 2, + JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_B)); + } else { + jas_image_setcolorspace(dec->image, JAS_IMAGE_CS_GRAY); + jas_image_setcmpttype(dec->image, 0, + JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_GRAY_Y)); + } - /* Save the return value. */ - image = dec->image; + /* Save the return value. */ + image = dec->image; - /* Stop the image from being discarded. */ - dec->image = 0; + /* Stop the image from being discarded. */ + dec->image = 0; - /* Destroy decoder. */ - jpc_dec_destroy(dec); + /* Destroy decoder. */ + jpc_dec_destroy(dec); - return image; + return image; error: - if (dec) { - jpc_dec_destroy(dec); - } - return 0; + if (dec) { + jpc_dec_destroy(dec); + } + return 0; } typedef enum { - OPT_MAXLYRS, - OPT_MAXPKTS, - OPT_DEBUG + OPT_MAXLYRS, + OPT_MAXPKTS, + OPT_DEBUG } optid_t; jas_taginfo_t decopts[] = { - {OPT_MAXLYRS, "maxlyrs"}, - {OPT_MAXPKTS, "maxpkts"}, - {OPT_DEBUG, "debug"}, - {-1, 0} + {OPT_MAXLYRS, "maxlyrs"}, + {OPT_MAXPKTS, "maxpkts"}, + {OPT_DEBUG, "debug"}, + {-1, 0} }; static int jpc_dec_parseopts(char *optstr, jpc_dec_importopts_t *opts) { - jas_tvparser_t *tvp; + jas_tvparser_t *tvp; - opts->debug = 0; - opts->maxlyrs = JPC_MAXLYRS; - opts->maxpkts = -1; + opts->debug = 0; + opts->maxlyrs = JPC_MAXLYRS; + opts->maxpkts = -1; - if (!(tvp = jas_tvparser_create(optstr ? optstr : ""))) { - return -1; - } + if (!(tvp = jas_tvparser_create(optstr ? optstr : ""))) { + return -1; + } - while (!jas_tvparser_next(tvp)) { - switch (jas_taginfo_nonull(jas_taginfos_lookup(decopts, - jas_tvparser_gettag(tvp)))->id) { - case OPT_MAXLYRS: - opts->maxlyrs = atoi(jas_tvparser_getval(tvp)); - break; - case OPT_DEBUG: - opts->debug = atoi(jas_tvparser_getval(tvp)); - break; - case OPT_MAXPKTS: - opts->maxpkts = atoi(jas_tvparser_getval(tvp)); - break; - default: - fprintf(stderr, "warning: ignoring invalid option %s\n", - jas_tvparser_gettag(tvp)); - break; - } - } + while (!jas_tvparser_next(tvp)) { + switch (jas_taginfo_nonull(jas_taginfos_lookup(decopts, + jas_tvparser_gettag(tvp)))->id) { + case OPT_MAXLYRS: + opts->maxlyrs = atoi(jas_tvparser_getval(tvp)); + break; + case OPT_DEBUG: + opts->debug = atoi(jas_tvparser_getval(tvp)); + break; + case OPT_MAXPKTS: + opts->maxpkts = atoi(jas_tvparser_getval(tvp)); + break; + default: + fprintf(stderr, "warning: ignoring invalid option %s\n", + jas_tvparser_gettag(tvp)); + break; + } + } - jas_tvparser_destroy(tvp); + jas_tvparser_destroy(tvp); - return 0; + return 0; } /******************************************************************************\ @@ -389,1121 +391,1121 @@ static int jpc_dec_parseopts(char *optstr, jpc_dec_importopts_t *opts) static jpc_dec_mstabent_t *jpc_dec_mstab_lookup(uint_fast16_t id) { - jpc_dec_mstabent_t *mstabent; - for (mstabent = jpc_dec_mstab; mstabent->id != 0; ++mstabent) { - if (mstabent->id == id) { - break; - } - } - return mstabent; + jpc_dec_mstabent_t *mstabent; + for (mstabent = jpc_dec_mstab; mstabent->id != 0; ++mstabent) { + if (mstabent->id == id) { + break; + } + } + return mstabent; } static int jpc_dec_decode(jpc_dec_t *dec) { - jpc_ms_t *ms; - jpc_dec_mstabent_t *mstabent; - int ret; - jpc_cstate_t *cstate; + jpc_ms_t *ms; + jpc_dec_mstabent_t *mstabent; + int ret; + jpc_cstate_t *cstate; - if (!(cstate = jpc_cstate_create())) { - return -1; - } - dec->cstate = cstate; + if (!(cstate = jpc_cstate_create())) { + return -1; + } + dec->cstate = cstate; - /* Initially, we should expect to encounter a SOC marker segment. */ - dec->state = JPC_MHSOC; + /* Initially, we should expect to encounter a SOC marker segment. */ + dec->state = JPC_MHSOC; - for (;;) { + for (;;) { - /* Get the next marker segment in the code stream. */ - if (!(ms = jpc_getms(dec->in, cstate))) { - fprintf(stderr, "cannot get marker segment\n"); - return -1; - } + /* Get the next marker segment in the code stream. */ + if (!(ms = jpc_getms(dec->in, cstate))) { + fprintf(stderr, "cannot get marker segment\n"); + return -1; + } - mstabent = jpc_dec_mstab_lookup(ms->id); - assert(mstabent); + mstabent = jpc_dec_mstab_lookup(ms->id); + assert(mstabent); - /* Ensure that this type of marker segment is permitted - at this point in the code stream. */ - if (!(dec->state & mstabent->validstates)) { - fprintf(stderr, "unexpected marker segment type\n"); - jpc_ms_destroy(ms); - return -1; - } + /* Ensure that this type of marker segment is permitted + at this point in the code stream. */ + if (!(dec->state & mstabent->validstates)) { + fprintf(stderr, "unexpected marker segment type\n"); + jpc_ms_destroy(ms); + return -1; + } - /* Process the marker segment. */ - if (mstabent->action) { - ret = (*mstabent->action)(dec, ms); - } else { - /* No explicit action is required. */ - ret = 0; - } + /* Process the marker segment. */ + if (mstabent->action) { + ret = (*mstabent->action)(dec, ms); + } else { + /* No explicit action is required. */ + ret = 0; + } - /* Destroy the marker segment. */ - jpc_ms_destroy(ms); + /* Destroy the marker segment. */ + jpc_ms_destroy(ms); - if (ret < 0) { - return -1; - } else if (ret > 0) { - break; - } + if (ret < 0) { + return -1; + } else if (ret > 0) { + break; + } - } + } - return 0; + return 0; } static int jpc_dec_process_crg(jpc_dec_t *dec, jpc_ms_t *ms) { - uint_fast16_t cmptno; - jpc_dec_cmpt_t *cmpt; - jpc_crg_t *crg; + uint_fast16_t cmptno; + jpc_dec_cmpt_t *cmpt; + jpc_crg_t *crg; - crg = &ms->parms.crg; - for (cmptno = 0, cmpt = dec->cmpts; cmptno < dec->numcomps; ++cmptno, - ++cmpt) { - /* Ignore the information in the CRG marker segment for now. - This information serves no useful purpose for decoding anyhow. - Some other parts of the code need to be changed if these lines - are uncommented. - cmpt->hsubstep = crg->comps[cmptno].hoff; - cmpt->vsubstep = crg->comps[cmptno].voff; - */ - } - return 0; + crg = &ms->parms.crg; + for (cmptno = 0, cmpt = dec->cmpts; cmptno < dec->numcomps; ++cmptno, + ++cmpt) { + /* Ignore the information in the CRG marker segment for now. + This information serves no useful purpose for decoding anyhow. + Some other parts of the code need to be changed if these lines + are uncommented. + cmpt->hsubstep = crg->comps[cmptno].hoff; + cmpt->vsubstep = crg->comps[cmptno].voff; + */ + } + return 0; } static int jpc_dec_process_soc(jpc_dec_t *dec, jpc_ms_t *ms) { - /* We should expect to encounter a SIZ marker segment next. */ - dec->state = JPC_MHSIZ; + /* We should expect to encounter a SIZ marker segment next. */ + dec->state = JPC_MHSIZ; - return 0; + return 0; } static int jpc_dec_process_sot(jpc_dec_t *dec, jpc_ms_t *ms) { - jpc_dec_tile_t *tile; - jpc_sot_t *sot = &ms->parms.sot; - jas_image_cmptparm_t *compinfos; - jas_image_cmptparm_t *compinfo; - jpc_dec_cmpt_t *cmpt; - uint_fast16_t cmptno; - - if (dec->state == JPC_MH) { - - compinfos = jas_malloc(dec->numcomps * sizeof(jas_image_cmptparm_t)); - assert(compinfos); - for (cmptno = 0, cmpt = dec->cmpts, compinfo = compinfos; - cmptno < dec->numcomps; ++cmptno, ++cmpt, ++compinfo) { - compinfo->tlx = 0; - compinfo->tly = 0; - compinfo->prec = cmpt->prec; - compinfo->sgnd = cmpt->sgnd; - compinfo->width = cmpt->width; - compinfo->height = cmpt->height; - compinfo->hstep = cmpt->hstep; - compinfo->vstep = cmpt->vstep; - } - - if (!(dec->image = jas_image_create(dec->numcomps, compinfos, - JAS_IMAGE_CS_UNKNOWN))) { - return -1; - } - jas_free(compinfos); - - /* Is the packet header information stored in PPM marker segments in - the main header? */ - if (dec->ppmstab) { - /* Convert the PPM marker segment data into a collection of streams - (one stream per tile-part). */ - if (!(dec->pkthdrstreams = jpc_ppmstabtostreams(dec->ppmstab))) { - abort(); - } - jpc_ppxstab_destroy(dec->ppmstab); - dec->ppmstab = 0; - } - } - - if (sot->len > 0) { - dec->curtileendoff = jas_stream_getrwcount(dec->in) - ms->len - - 4 + sot->len; - } else { - dec->curtileendoff = 0; - } - - if (sot->tileno > dec->numtiles) { - fprintf(stderr, "invalid tile number in SOT marker segment\n"); - return -1; - } - /* Set the current tile. */ - dec->curtile = &dec->tiles[sot->tileno]; - tile = dec->curtile; - /* Ensure that this is the expected part number. */ - if (sot->partno != tile->partno) { - return -1; - } - if (tile->numparts > 0 && sot->partno >= tile->numparts) { - return -1; - } - if (!tile->numparts && sot->numparts > 0) { - tile->numparts = sot->numparts; - } - - tile->pptstab = 0; - - switch (tile->state) { - case JPC_TILE_INIT: - /* This is the first tile-part for this tile. */ - tile->state = JPC_TILE_ACTIVE; - assert(!tile->cp); - if (!(tile->cp = jpc_dec_cp_copy(dec->cp))) { - return -1; - } - jpc_dec_cp_resetflags(dec->cp); - break; - default: - if (sot->numparts == sot->partno - 1) { - tile->state = JPC_TILE_ACTIVELAST; - } - break; - } - - /* Note: We do not increment the expected tile-part number until - all processing for this tile-part is complete. */ - - /* We should expect to encounter other tile-part header marker - segments next. */ - dec->state = JPC_TPH; - - return 0; + jpc_dec_tile_t *tile; + jpc_sot_t *sot = &ms->parms.sot; + jas_image_cmptparm_t *compinfos; + jas_image_cmptparm_t *compinfo; + jpc_dec_cmpt_t *cmpt; + uint_fast16_t cmptno; + + if (dec->state == JPC_MH) { + + compinfos = jas_malloc(dec->numcomps * sizeof(jas_image_cmptparm_t)); + assert(compinfos); + for (cmptno = 0, cmpt = dec->cmpts, compinfo = compinfos; + cmptno < dec->numcomps; ++cmptno, ++cmpt, ++compinfo) { + compinfo->tlx = 0; + compinfo->tly = 0; + compinfo->prec = cmpt->prec; + compinfo->sgnd = cmpt->sgnd; + compinfo->width = cmpt->width; + compinfo->height = cmpt->height; + compinfo->hstep = cmpt->hstep; + compinfo->vstep = cmpt->vstep; + } + + if (!(dec->image = jas_image_create(dec->numcomps, compinfos, + JAS_IMAGE_CS_UNKNOWN))) { + return -1; + } + jas_free(compinfos); + + /* Is the packet header information stored in PPM marker segments in + the main header? */ + if (dec->ppmstab) { + /* Convert the PPM marker segment data into a collection of streams + (one stream per tile-part). */ + if (!(dec->pkthdrstreams = jpc_ppmstabtostreams(dec->ppmstab))) { + abort(); + } + jpc_ppxstab_destroy(dec->ppmstab); + dec->ppmstab = 0; + } + } + + if (sot->len > 0) { + dec->curtileendoff = jas_stream_getrwcount(dec->in) - ms->len - + 4 + sot->len; + } else { + dec->curtileendoff = 0; + } + + if (sot->tileno > dec->numtiles) { + fprintf(stderr, "invalid tile number in SOT marker segment\n"); + return -1; + } + /* Set the current tile. */ + dec->curtile = &dec->tiles[sot->tileno]; + tile = dec->curtile; + /* Ensure that this is the expected part number. */ + if (sot->partno != tile->partno) { + return -1; + } + if (tile->numparts > 0 && sot->partno >= tile->numparts) { + return -1; + } + if (!tile->numparts && sot->numparts > 0) { + tile->numparts = sot->numparts; + } + + tile->pptstab = 0; + + switch (tile->state) { + case JPC_TILE_INIT: + /* This is the first tile-part for this tile. */ + tile->state = JPC_TILE_ACTIVE; + assert(!tile->cp); + if (!(tile->cp = jpc_dec_cp_copy(dec->cp))) { + return -1; + } + jpc_dec_cp_resetflags(dec->cp); + break; + default: + if (sot->numparts == sot->partno - 1) { + tile->state = JPC_TILE_ACTIVELAST; + } + break; + } + + /* Note: We do not increment the expected tile-part number until + all processing for this tile-part is complete. */ + + /* We should expect to encounter other tile-part header marker + segments next. */ + dec->state = JPC_TPH; + + return 0; } static int jpc_dec_process_sod(jpc_dec_t *dec, jpc_ms_t *ms) { - jpc_dec_tile_t *tile; - int pos; - - if (!(tile = dec->curtile)) { - return -1; - } - - if (!tile->partno) { - if (!jpc_dec_cp_isvalid(tile->cp)) { - return -1; - } - jpc_dec_cp_prepare(tile->cp); - if (jpc_dec_tileinit(dec, tile)) { - return -1; - } - } - - /* Are packet headers stored in the main header or tile-part header? */ - if (dec->pkthdrstreams) { - /* Get the stream containing the packet header data for this - tile-part. */ - if (!(tile->pkthdrstream = jpc_streamlist_remove(dec->pkthdrstreams, 0))) { - return -1; - } - } - - if (tile->pptstab) { - if (!tile->pkthdrstream) { - if (!(tile->pkthdrstream = jas_stream_memopen(0, 0))) { - return -1; - } - } - pos = jas_stream_tell(tile->pkthdrstream); - jas_stream_seek(tile->pkthdrstream, 0, SEEK_END); - if (jpc_pptstabwrite(tile->pkthdrstream, tile->pptstab)) { - return -1; - } - jas_stream_seek(tile->pkthdrstream, pos, SEEK_SET); - jpc_ppxstab_destroy(tile->pptstab); - tile->pptstab = 0; - } - - if (jas_getdbglevel() >= 10) { - jpc_dec_dump(dec, stderr); - } - - if (jpc_dec_decodepkts(dec, (tile->pkthdrstream) ? tile->pkthdrstream : - dec->in, dec->in)) { - fprintf(stderr, "jpc_dec_decodepkts failed\n"); - return -1; - } - - /* Gobble any unconsumed tile data. */ - if (dec->curtileendoff > 0) { - uint_fast32_t curoff; - uint_fast32_t n; - curoff = jas_stream_getrwcount(dec->in); - if (curoff < dec->curtileendoff) { - n = dec->curtileendoff - curoff; - fprintf(stderr, - "warning: ignoring trailing garbage (%lu bytes)\n", - (unsigned long) n); - - while (n-- > 0) { - if (jas_stream_getc(dec->in) == EOF) { - fprintf(stderr, "read error\n"); - return -1; - } - } - } else if (curoff > dec->curtileendoff) { - fprintf(stderr, - "warning: not enough tile data (%lu bytes)\n", - (unsigned long) curoff - dec->curtileendoff); - } - - } - - if (tile->numparts > 0 && tile->partno == tile->numparts - 1) { - if (jpc_dec_tiledecode(dec, tile)) { - return -1; - } - jpc_dec_tilefini(dec, tile); - } - - dec->curtile = 0; - - /* Increment the expected tile-part number. */ - ++tile->partno; - - /* We should expect to encounter a SOT marker segment next. */ - dec->state = JPC_TPHSOT; - - return 0; + jpc_dec_tile_t *tile; + int pos; + + if (!(tile = dec->curtile)) { + return -1; + } + + if (!tile->partno) { + if (!jpc_dec_cp_isvalid(tile->cp)) { + return -1; + } + jpc_dec_cp_prepare(tile->cp); + if (jpc_dec_tileinit(dec, tile)) { + return -1; + } + } + + /* Are packet headers stored in the main header or tile-part header? */ + if (dec->pkthdrstreams) { + /* Get the stream containing the packet header data for this + tile-part. */ + if (!(tile->pkthdrstream = jpc_streamlist_remove(dec->pkthdrstreams, 0))) { + return -1; + } + } + + if (tile->pptstab) { + if (!tile->pkthdrstream) { + if (!(tile->pkthdrstream = jas_stream_memopen(0, 0))) { + return -1; + } + } + pos = jas_stream_tell(tile->pkthdrstream); + jas_stream_seek(tile->pkthdrstream, 0, SEEK_END); + if (jpc_pptstabwrite(tile->pkthdrstream, tile->pptstab)) { + return -1; + } + jas_stream_seek(tile->pkthdrstream, pos, SEEK_SET); + jpc_ppxstab_destroy(tile->pptstab); + tile->pptstab = 0; + } + + if (jas_getdbglevel() >= 10) { + jpc_dec_dump(dec, stderr); + } + + if (jpc_dec_decodepkts(dec, (tile->pkthdrstream) ? tile->pkthdrstream : + dec->in, dec->in)) { + fprintf(stderr, "jpc_dec_decodepkts failed\n"); + return -1; + } + + /* Gobble any unconsumed tile data. */ + if (dec->curtileendoff > 0) { + uint_fast32_t curoff; + uint_fast32_t n; + curoff = jas_stream_getrwcount(dec->in); + if (curoff < dec->curtileendoff) { + n = dec->curtileendoff - curoff; + fprintf(stderr, + "warning: ignoring trailing garbage (%lu bytes)\n", + (unsigned long) n); + + while (n-- > 0) { + if (jas_stream_getc(dec->in) == EOF) { + fprintf(stderr, "read error\n"); + return -1; + } + } + } else if (curoff > dec->curtileendoff) { + fprintf(stderr, + "warning: not enough tile data (%lu bytes)\n", + (unsigned long) curoff - dec->curtileendoff); + } + + } + + if (tile->numparts > 0 && tile->partno == tile->numparts - 1) { + if (jpc_dec_tiledecode(dec, tile)) { + return -1; + } + jpc_dec_tilefini(dec, tile); + } + + dec->curtile = 0; + + /* Increment the expected tile-part number. */ + ++tile->partno; + + /* We should expect to encounter a SOT marker segment next. */ + dec->state = JPC_TPHSOT; + + return 0; } static int jpc_dec_tileinit(jpc_dec_t *dec, jpc_dec_tile_t *tile) { - jpc_dec_tcomp_t *tcomp; - uint_fast16_t compno; - int rlvlno; - jpc_dec_rlvl_t *rlvl; - jpc_dec_band_t *band; - jpc_dec_prc_t *prc; - int bndno; - jpc_tsfb_band_t *bnd; - int bandno; - jpc_dec_ccp_t *ccp; - int prccnt; - jpc_dec_cblk_t *cblk; - int cblkcnt; - uint_fast32_t tlprcxstart; - uint_fast32_t tlprcystart; - uint_fast32_t brprcxend; - uint_fast32_t brprcyend; - uint_fast32_t tlcbgxstart; - uint_fast32_t tlcbgystart; - uint_fast32_t brcbgxend; - uint_fast32_t brcbgyend; - uint_fast32_t cbgxstart; - uint_fast32_t cbgystart; - uint_fast32_t cbgxend; - uint_fast32_t cbgyend; - uint_fast32_t tlcblkxstart; - uint_fast32_t tlcblkystart; - uint_fast32_t brcblkxend; - uint_fast32_t brcblkyend; - uint_fast32_t cblkxstart; - uint_fast32_t cblkystart; - uint_fast32_t cblkxend; - uint_fast32_t cblkyend; - uint_fast32_t tmpxstart; - uint_fast32_t tmpystart; - uint_fast32_t tmpxend; - uint_fast32_t tmpyend; - jpc_dec_cp_t *cp; - jpc_tsfb_band_t bnds[64]; - jpc_pchg_t *pchg; - int pchgno; - jpc_dec_cmpt_t *cmpt; - - cp = tile->cp; - tile->realmode = 0; - if (cp->mctid == JPC_MCT_ICT) { - tile->realmode = 1; - } - - for (compno = 0, tcomp = tile->tcomps, cmpt = dec->cmpts; compno < - dec->numcomps; ++compno, ++tcomp, ++cmpt) { - ccp = &tile->cp->ccps[compno]; - if (ccp->qmfbid == JPC_COX_INS) { - tile->realmode = 1; - } - tcomp->numrlvls = ccp->numrlvls; - if (!(tcomp->rlvls = jas_malloc(tcomp->numrlvls * - sizeof(jpc_dec_rlvl_t)))) { - return -1; - } - if (!(tcomp->data = jas_seq2d_create(JPC_CEILDIV(tile->xstart, - cmpt->hstep), JPC_CEILDIV(tile->ystart, cmpt->vstep), - JPC_CEILDIV(tile->xend, cmpt->hstep), JPC_CEILDIV(tile->yend, - cmpt->vstep)))) { - return -1; - } - if (!(tcomp->tsfb = jpc_cod_gettsfb(ccp->qmfbid, - tcomp->numrlvls - 1))) { - return -1; - } -{ - jpc_tsfb_getbands(tcomp->tsfb, jas_seq2d_xstart(tcomp->data), jas_seq2d_ystart(tcomp->data), jas_seq2d_xend(tcomp->data), jas_seq2d_yend(tcomp->data), bnds); -} - for (rlvlno = 0, rlvl = tcomp->rlvls; rlvlno < tcomp->numrlvls; - ++rlvlno, ++rlvl) { + jpc_dec_tcomp_t *tcomp; + uint_fast16_t compno; + int rlvlno; + jpc_dec_rlvl_t *rlvl; + jpc_dec_band_t *band; + jpc_dec_prc_t *prc; + int bndno; + jpc_tsfb_band_t *bnd; + int bandno; + jpc_dec_ccp_t *ccp; + int prccnt; + jpc_dec_cblk_t *cblk; + int cblkcnt; + uint_fast32_t tlprcxstart; + uint_fast32_t tlprcystart; + uint_fast32_t brprcxend; + uint_fast32_t brprcyend; + uint_fast32_t tlcbgxstart; + uint_fast32_t tlcbgystart; + uint_fast32_t brcbgxend; + uint_fast32_t brcbgyend; + uint_fast32_t cbgxstart; + uint_fast32_t cbgystart; + uint_fast32_t cbgxend; + uint_fast32_t cbgyend; + uint_fast32_t tlcblkxstart; + uint_fast32_t tlcblkystart; + uint_fast32_t brcblkxend; + uint_fast32_t brcblkyend; + uint_fast32_t cblkxstart; + uint_fast32_t cblkystart; + uint_fast32_t cblkxend; + uint_fast32_t cblkyend; + uint_fast32_t tmpxstart; + uint_fast32_t tmpystart; + uint_fast32_t tmpxend; + uint_fast32_t tmpyend; + jpc_dec_cp_t *cp; + jpc_tsfb_band_t bnds[64]; + jpc_pchg_t *pchg; + int pchgno; + jpc_dec_cmpt_t *cmpt; + + cp = tile->cp; + tile->realmode = 0; + if (cp->mctid == JPC_MCT_ICT) { + tile->realmode = 1; + } + + for (compno = 0, tcomp = tile->tcomps, cmpt = dec->cmpts; compno < + dec->numcomps; ++compno, ++tcomp, ++cmpt) { + ccp = &tile->cp->ccps[compno]; + if (ccp->qmfbid == JPC_COX_INS) { + tile->realmode = 1; + } + tcomp->numrlvls = ccp->numrlvls; + if (!(tcomp->rlvls = jas_malloc(tcomp->numrlvls * + sizeof(jpc_dec_rlvl_t)))) { + return -1; + } + if (!(tcomp->data = jas_seq2d_create(JPC_CEILDIV(tile->xstart, + cmpt->hstep), JPC_CEILDIV(tile->ystart, cmpt->vstep), + JPC_CEILDIV(tile->xend, cmpt->hstep), JPC_CEILDIV(tile->yend, + cmpt->vstep)))) { + return -1; + } + if (!(tcomp->tsfb = jpc_cod_gettsfb(ccp->qmfbid, + tcomp->numrlvls - 1))) { + return -1; + } +{ + jpc_tsfb_getbands(tcomp->tsfb, jas_seq2d_xstart(tcomp->data), jas_seq2d_ystart(tcomp->data), jas_seq2d_xend(tcomp->data), jas_seq2d_yend(tcomp->data), bnds); +} + for (rlvlno = 0, rlvl = tcomp->rlvls; rlvlno < tcomp->numrlvls; + ++rlvlno, ++rlvl) { rlvl->bands = 0; - rlvl->xstart = JPC_CEILDIVPOW2(tcomp->xstart, - tcomp->numrlvls - 1 - rlvlno); - rlvl->ystart = JPC_CEILDIVPOW2(tcomp->ystart, - tcomp->numrlvls - 1 - rlvlno); - rlvl->xend = JPC_CEILDIVPOW2(tcomp->xend, - tcomp->numrlvls - 1 - rlvlno); - rlvl->yend = JPC_CEILDIVPOW2(tcomp->yend, - tcomp->numrlvls - 1 - rlvlno); - rlvl->prcwidthexpn = ccp->prcwidthexpns[rlvlno]; - rlvl->prcheightexpn = ccp->prcheightexpns[rlvlno]; - tlprcxstart = JPC_FLOORDIVPOW2(rlvl->xstart, - rlvl->prcwidthexpn) << rlvl->prcwidthexpn; - tlprcystart = JPC_FLOORDIVPOW2(rlvl->ystart, - rlvl->prcheightexpn) << rlvl->prcheightexpn; - brprcxend = JPC_CEILDIVPOW2(rlvl->xend, - rlvl->prcwidthexpn) << rlvl->prcwidthexpn; - brprcyend = JPC_CEILDIVPOW2(rlvl->yend, - rlvl->prcheightexpn) << rlvl->prcheightexpn; - rlvl->numhprcs = (brprcxend - tlprcxstart) >> - rlvl->prcwidthexpn; - rlvl->numvprcs = (brprcyend - tlprcystart) >> - rlvl->prcheightexpn; - rlvl->numprcs = rlvl->numhprcs * rlvl->numvprcs; - - if (rlvl->xstart >= rlvl->xend || rlvl->ystart >= rlvl->yend) { - rlvl->bands = 0; - rlvl->numprcs = 0; - rlvl->numhprcs = 0; - rlvl->numvprcs = 0; - continue; - } - if (!rlvlno) { - tlcbgxstart = tlprcxstart; - tlcbgystart = tlprcystart; - brcbgxend = brprcxend; - brcbgyend = brprcyend; - rlvl->cbgwidthexpn = rlvl->prcwidthexpn; - rlvl->cbgheightexpn = rlvl->prcheightexpn; - } else { - tlcbgxstart = JPC_CEILDIVPOW2(tlprcxstart, 1); - tlcbgystart = JPC_CEILDIVPOW2(tlprcystart, 1); - brcbgxend = JPC_CEILDIVPOW2(brprcxend, 1); - brcbgyend = JPC_CEILDIVPOW2(brprcyend, 1); - rlvl->cbgwidthexpn = rlvl->prcwidthexpn - 1; - rlvl->cbgheightexpn = rlvl->prcheightexpn - 1; - } - rlvl->cblkwidthexpn = JAS_MIN(ccp->cblkwidthexpn, - rlvl->cbgwidthexpn); - rlvl->cblkheightexpn = JAS_MIN(ccp->cblkheightexpn, - rlvl->cbgheightexpn); - - rlvl->numbands = (!rlvlno) ? 1 : 3; - if (!(rlvl->bands = jas_malloc(rlvl->numbands * - sizeof(jpc_dec_band_t)))) { - return -1; - } - for (bandno = 0, band = rlvl->bands; - bandno < rlvl->numbands; ++bandno, ++band) { - bndno = (!rlvlno) ? 0 : (3 * (rlvlno - 1) + - bandno + 1); - bnd = &bnds[bndno]; - - band->orient = bnd->orient; - band->stepsize = ccp->stepsizes[bndno]; - band->analgain = JPC_NOMINALGAIN(ccp->qmfbid, - tcomp->numrlvls - 1, rlvlno, band->orient); - band->absstepsize = jpc_calcabsstepsize(band->stepsize, - cmpt->prec + band->analgain); - band->numbps = ccp->numguardbits + - JPC_QCX_GETEXPN(band->stepsize) - 1; - band->roishift = (ccp->roishift + band->numbps >= JPC_PREC) ? - (JPC_PREC - 1 - band->numbps) : ccp->roishift; - band->data = 0; - band->prcs = 0; - if (bnd->xstart == bnd->xend || bnd->ystart == bnd->yend) { - continue; - } - if (!(band->data = jas_seq2d_create(0, 0, 0, 0))) { - return -1; - } - jas_seq2d_bindsub(band->data, tcomp->data, bnd->locxstart, bnd->locystart, bnd->locxend, bnd->locyend); - jas_seq2d_setshift(band->data, bnd->xstart, bnd->ystart); - - assert(rlvl->numprcs); - - if (!(band->prcs = jas_malloc(rlvl->numprcs * sizeof(jpc_dec_prc_t)))) { - return -1; - } + rlvl->xstart = JPC_CEILDIVPOW2(tcomp->xstart, + tcomp->numrlvls - 1 - rlvlno); + rlvl->ystart = JPC_CEILDIVPOW2(tcomp->ystart, + tcomp->numrlvls - 1 - rlvlno); + rlvl->xend = JPC_CEILDIVPOW2(tcomp->xend, + tcomp->numrlvls - 1 - rlvlno); + rlvl->yend = JPC_CEILDIVPOW2(tcomp->yend, + tcomp->numrlvls - 1 - rlvlno); + rlvl->prcwidthexpn = ccp->prcwidthexpns[rlvlno]; + rlvl->prcheightexpn = ccp->prcheightexpns[rlvlno]; + tlprcxstart = JPC_FLOORDIVPOW2(rlvl->xstart, + rlvl->prcwidthexpn) << rlvl->prcwidthexpn; + tlprcystart = JPC_FLOORDIVPOW2(rlvl->ystart, + rlvl->prcheightexpn) << rlvl->prcheightexpn; + brprcxend = JPC_CEILDIVPOW2(rlvl->xend, + rlvl->prcwidthexpn) << rlvl->prcwidthexpn; + brprcyend = JPC_CEILDIVPOW2(rlvl->yend, + rlvl->prcheightexpn) << rlvl->prcheightexpn; + rlvl->numhprcs = (brprcxend - tlprcxstart) >> + rlvl->prcwidthexpn; + rlvl->numvprcs = (brprcyend - tlprcystart) >> + rlvl->prcheightexpn; + rlvl->numprcs = rlvl->numhprcs * rlvl->numvprcs; + + if (rlvl->xstart >= rlvl->xend || rlvl->ystart >= rlvl->yend) { + rlvl->bands = 0; + rlvl->numprcs = 0; + rlvl->numhprcs = 0; + rlvl->numvprcs = 0; + continue; + } + if (!rlvlno) { + tlcbgxstart = tlprcxstart; + tlcbgystart = tlprcystart; + brcbgxend = brprcxend; + brcbgyend = brprcyend; + rlvl->cbgwidthexpn = rlvl->prcwidthexpn; + rlvl->cbgheightexpn = rlvl->prcheightexpn; + } else { + tlcbgxstart = JPC_CEILDIVPOW2(tlprcxstart, 1); + tlcbgystart = JPC_CEILDIVPOW2(tlprcystart, 1); + brcbgxend = JPC_CEILDIVPOW2(brprcxend, 1); + brcbgyend = JPC_CEILDIVPOW2(brprcyend, 1); + rlvl->cbgwidthexpn = rlvl->prcwidthexpn - 1; + rlvl->cbgheightexpn = rlvl->prcheightexpn - 1; + } + rlvl->cblkwidthexpn = JAS_MIN(ccp->cblkwidthexpn, + rlvl->cbgwidthexpn); + rlvl->cblkheightexpn = JAS_MIN(ccp->cblkheightexpn, + rlvl->cbgheightexpn); + + rlvl->numbands = (!rlvlno) ? 1 : 3; + if (!(rlvl->bands = jas_malloc(rlvl->numbands * + sizeof(jpc_dec_band_t)))) { + return -1; + } + for (bandno = 0, band = rlvl->bands; + bandno < rlvl->numbands; ++bandno, ++band) { + bndno = (!rlvlno) ? 0 : (3 * (rlvlno - 1) + + bandno + 1); + bnd = &bnds[bndno]; + + band->orient = bnd->orient; + band->stepsize = ccp->stepsizes[bndno]; + band->analgain = JPC_NOMINALGAIN(ccp->qmfbid, + tcomp->numrlvls - 1, rlvlno, band->orient); + band->absstepsize = jpc_calcabsstepsize(band->stepsize, + cmpt->prec + band->analgain); + band->numbps = ccp->numguardbits + + JPC_QCX_GETEXPN(band->stepsize) - 1; + band->roishift = (ccp->roishift + band->numbps >= JPC_PREC) ? + (JPC_PREC - 1 - band->numbps) : ccp->roishift; + band->data = 0; + band->prcs = 0; + if (bnd->xstart == bnd->xend || bnd->ystart == bnd->yend) { + continue; + } + if (!(band->data = jas_seq2d_create(0, 0, 0, 0))) { + return -1; + } + jas_seq2d_bindsub(band->data, tcomp->data, bnd->locxstart, bnd->locystart, bnd->locxend, bnd->locyend); + jas_seq2d_setshift(band->data, bnd->xstart, bnd->ystart); + + assert(rlvl->numprcs); + + if (!(band->prcs = jas_malloc(rlvl->numprcs * sizeof(jpc_dec_prc_t)))) { + return -1; + } /************************************************/ - cbgxstart = tlcbgxstart; - cbgystart = tlcbgystart; - for (prccnt = rlvl->numprcs, prc = band->prcs; - prccnt > 0; --prccnt, ++prc) { - cbgxend = cbgxstart + (1 << rlvl->cbgwidthexpn); - cbgyend = cbgystart + (1 << rlvl->cbgheightexpn); - prc->xstart = JAS_MAX(cbgxstart, jas_seq2d_xstart(band->data)); - prc->ystart = JAS_MAX(cbgystart, jas_seq2d_ystart(band->data)); - prc->xend = JAS_MIN(cbgxend, jas_seq2d_xend(band->data)); - prc->yend = JAS_MIN(cbgyend, jas_seq2d_yend(band->data)); - if (prc->xend > prc->xstart && prc->yend > prc->ystart) { - tlcblkxstart = JPC_FLOORDIVPOW2(prc->xstart, - rlvl->cblkwidthexpn) << rlvl->cblkwidthexpn; - tlcblkystart = JPC_FLOORDIVPOW2(prc->ystart, - rlvl->cblkheightexpn) << rlvl->cblkheightexpn; - brcblkxend = JPC_CEILDIVPOW2U(prc->xend, - rlvl->cblkwidthexpn) << rlvl->cblkwidthexpn; - brcblkyend = JPC_CEILDIVPOW2U(prc->yend, - rlvl->cblkheightexpn) << rlvl->cblkheightexpn; - prc->numhcblks = (brcblkxend - tlcblkxstart) >> - rlvl->cblkwidthexpn; - prc->numvcblks = (brcblkyend - tlcblkystart) >> - rlvl->cblkheightexpn; - prc->numcblks = prc->numhcblks * prc->numvcblks; - assert(prc->numcblks > 0); - - if (!(prc->incltagtree = jpc_tagtree_create(prc->numhcblks, prc->numvcblks))) { - return -1; - } - if (!(prc->numimsbstagtree = jpc_tagtree_create(prc->numhcblks, prc->numvcblks))) { - return -1; - } - if (!(prc->cblks = jas_malloc(prc->numcblks * sizeof(jpc_dec_cblk_t)))) { - return -1; - } - - cblkxstart = cbgxstart; - cblkystart = cbgystart; - for (cblkcnt = prc->numcblks, cblk = prc->cblks; cblkcnt > 0;) { - cblkxend = cblkxstart + (1 << rlvl->cblkwidthexpn); - cblkyend = cblkystart + (1 << rlvl->cblkheightexpn); - tmpxstart = JAS_MAX(cblkxstart, prc->xstart); - tmpystart = JAS_MAX(cblkystart, prc->ystart); - tmpxend = JAS_MIN(cblkxend, prc->xend); - tmpyend = JAS_MIN(cblkyend, prc->yend); - if (tmpxend > tmpxstart && tmpyend > tmpystart) { - cblk->firstpassno = -1; - cblk->mqdec = 0; - cblk->nulldec = 0; - cblk->flags = 0; - cblk->numpasses = 0; - cblk->segs.head = 0; - cblk->segs.tail = 0; - cblk->curseg = 0; - cblk->numimsbs = 0; - cblk->numlenbits = 3; - cblk->flags = 0; - if (!(cblk->data = jas_seq2d_create(0, 0, 0, 0))) { - return -1; - } - jas_seq2d_bindsub(cblk->data, band->data, tmpxstart, tmpystart, tmpxend, tmpyend); - ++cblk; - --cblkcnt; - } - cblkxstart += 1 << rlvl->cblkwidthexpn; - if (cblkxstart >= cbgxend) { - cblkxstart = cbgxstart; - cblkystart += 1 << rlvl->cblkheightexpn; - } - } - - } else { - prc->cblks = 0; - prc->incltagtree = 0; - prc->numimsbstagtree = 0; - } - cbgxstart += 1 << rlvl->cbgwidthexpn; - if (cbgxstart >= brcbgxend) { - cbgxstart = tlcbgxstart; - cbgystart += 1 << rlvl->cbgheightexpn; - } - - } + cbgxstart = tlcbgxstart; + cbgystart = tlcbgystart; + for (prccnt = rlvl->numprcs, prc = band->prcs; + prccnt > 0; --prccnt, ++prc) { + cbgxend = cbgxstart + (1 << rlvl->cbgwidthexpn); + cbgyend = cbgystart + (1 << rlvl->cbgheightexpn); + prc->xstart = JAS_MAX(cbgxstart, jas_seq2d_xstart(band->data)); + prc->ystart = JAS_MAX(cbgystart, jas_seq2d_ystart(band->data)); + prc->xend = JAS_MIN(cbgxend, jas_seq2d_xend(band->data)); + prc->yend = JAS_MIN(cbgyend, jas_seq2d_yend(band->data)); + if (prc->xend > prc->xstart && prc->yend > prc->ystart) { + tlcblkxstart = JPC_FLOORDIVPOW2(prc->xstart, + rlvl->cblkwidthexpn) << rlvl->cblkwidthexpn; + tlcblkystart = JPC_FLOORDIVPOW2(prc->ystart, + rlvl->cblkheightexpn) << rlvl->cblkheightexpn; + brcblkxend = JPC_CEILDIVPOW2U(prc->xend, + rlvl->cblkwidthexpn) << rlvl->cblkwidthexpn; + brcblkyend = JPC_CEILDIVPOW2U(prc->yend, + rlvl->cblkheightexpn) << rlvl->cblkheightexpn; + prc->numhcblks = (brcblkxend - tlcblkxstart) >> + rlvl->cblkwidthexpn; + prc->numvcblks = (brcblkyend - tlcblkystart) >> + rlvl->cblkheightexpn; + prc->numcblks = prc->numhcblks * prc->numvcblks; + assert(prc->numcblks > 0); + + if (!(prc->incltagtree = jpc_tagtree_create(prc->numhcblks, prc->numvcblks))) { + return -1; + } + if (!(prc->numimsbstagtree = jpc_tagtree_create(prc->numhcblks, prc->numvcblks))) { + return -1; + } + if (!(prc->cblks = jas_malloc(prc->numcblks * sizeof(jpc_dec_cblk_t)))) { + return -1; + } + + cblkxstart = cbgxstart; + cblkystart = cbgystart; + for (cblkcnt = prc->numcblks, cblk = prc->cblks; cblkcnt > 0;) { + cblkxend = cblkxstart + (1 << rlvl->cblkwidthexpn); + cblkyend = cblkystart + (1 << rlvl->cblkheightexpn); + tmpxstart = JAS_MAX(cblkxstart, prc->xstart); + tmpystart = JAS_MAX(cblkystart, prc->ystart); + tmpxend = JAS_MIN(cblkxend, prc->xend); + tmpyend = JAS_MIN(cblkyend, prc->yend); + if (tmpxend > tmpxstart && tmpyend > tmpystart) { + cblk->firstpassno = -1; + cblk->mqdec = 0; + cblk->nulldec = 0; + cblk->flags = 0; + cblk->numpasses = 0; + cblk->segs.head = 0; + cblk->segs.tail = 0; + cblk->curseg = 0; + cblk->numimsbs = 0; + cblk->numlenbits = 3; + cblk->flags = 0; + if (!(cblk->data = jas_seq2d_create(0, 0, 0, 0))) { + return -1; + } + jas_seq2d_bindsub(cblk->data, band->data, tmpxstart, tmpystart, tmpxend, tmpyend); + ++cblk; + --cblkcnt; + } + cblkxstart += 1 << rlvl->cblkwidthexpn; + if (cblkxstart >= cbgxend) { + cblkxstart = cbgxstart; + cblkystart += 1 << rlvl->cblkheightexpn; + } + } + + } else { + prc->cblks = 0; + prc->incltagtree = 0; + prc->numimsbstagtree = 0; + } + cbgxstart += 1 << rlvl->cbgwidthexpn; + if (cbgxstart >= brcbgxend) { + cbgxstart = tlcbgxstart; + cbgystart += 1 << rlvl->cbgheightexpn; + } + + } /********************************************/ - } - } - } + } + } + } if (!(tile->pi = jpc_dec_pi_create(dec, tile))) { - return -1; + return -1; } - for (pchgno = 0; pchgno < jpc_pchglist_numpchgs(tile->cp->pchglist); - ++pchgno) { - pchg = jpc_pchg_copy(jpc_pchglist_get(tile->cp->pchglist, pchgno)); - assert(pchg); - jpc_pi_addpchg(tile->pi, pchg); - } - jpc_pi_init(tile->pi); + for (pchgno = 0; pchgno < jpc_pchglist_numpchgs(tile->cp->pchglist); + ++pchgno) { + pchg = jpc_pchg_copy(jpc_pchglist_get(tile->cp->pchglist, pchgno)); + assert(pchg); + jpc_pi_addpchg(tile->pi, pchg); + } + jpc_pi_init(tile->pi); - return 0; + return 0; } static int jpc_dec_tilefini(jpc_dec_t *dec, jpc_dec_tile_t *tile) { - jpc_dec_tcomp_t *tcomp; - int compno; - int bandno; - int rlvlno; - jpc_dec_band_t *band; - jpc_dec_rlvl_t *rlvl; - int prcno; - jpc_dec_prc_t *prc; - jpc_dec_seg_t *seg; - jpc_dec_cblk_t *cblk; - int cblkno; + jpc_dec_tcomp_t *tcomp; + int compno; + int bandno; + int rlvlno; + jpc_dec_band_t *band; + jpc_dec_rlvl_t *rlvl; + int prcno; + jpc_dec_prc_t *prc; + jpc_dec_seg_t *seg; + jpc_dec_cblk_t *cblk; + int cblkno; if (tile->tcomps) { - for (compno = 0, tcomp = tile->tcomps; compno < dec->numcomps; - ++compno, ++tcomp) { - for (rlvlno = 0, rlvl = tcomp->rlvls; rlvlno < tcomp->numrlvls; - ++rlvlno, ++rlvl) { + for (compno = 0, tcomp = tile->tcomps; compno < dec->numcomps; + ++compno, ++tcomp) { + for (rlvlno = 0, rlvl = tcomp->rlvls; rlvlno < tcomp->numrlvls; + ++rlvlno, ++rlvl) { if (!rlvl->bands) { - continue; + continue; } - for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands; ++bandno, ++band) { + for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands; ++bandno, ++band) { if (band->prcs) { - for (prcno = 0, prc = band->prcs; prcno < - rlvl->numprcs; ++prcno, ++prc) { + for (prcno = 0, prc = band->prcs; prcno < + rlvl->numprcs; ++prcno, ++prc) { if (!prc->cblks) { - continue; -} - for (cblkno = 0, cblk = prc->cblks; cblkno < prc->numcblks; ++cblkno, ++cblk) { - - while (cblk->segs.head) { - seg = cblk->segs.head; - jpc_seglist_remove(&cblk->segs, seg); - jpc_seg_destroy(seg); - } - jas_matrix_destroy(cblk->data); - if (cblk->mqdec) { - jpc_mqdec_destroy(cblk->mqdec); - } - if (cblk->nulldec) { - jpc_bitstream_close(cblk->nulldec); - } - if (cblk->flags) { - jas_matrix_destroy(cblk->flags); - } - } - if (prc->incltagtree) { - jpc_tagtree_destroy(prc->incltagtree); - } - if (prc->numimsbstagtree) { - jpc_tagtree_destroy(prc->numimsbstagtree); - } - if (prc->cblks) { - jas_free(prc->cblks); - } - } -} - if (band->data) { - jas_matrix_destroy(band->data); - } - if (band->prcs) { - jas_free(band->prcs); - } - } - if (rlvl->bands) { - jas_free(rlvl->bands); - } - } - if (tcomp->rlvls) { - jas_free(tcomp->rlvls); - } - if (tcomp->data) { - jas_matrix_destroy(tcomp->data); - } - if (tcomp->tsfb) { - jpc_tsfb_destroy(tcomp->tsfb); - } - } -} - if (tile->cp) { - jpc_dec_cp_destroy(tile->cp); - tile->cp = 0; - } - if (tile->tcomps) { - jas_free(tile->tcomps); - tile->tcomps = 0; - } - if (tile->pi) { - jpc_pi_destroy(tile->pi); - tile->pi = 0; - } - if (tile->pkthdrstream) { - jas_stream_close(tile->pkthdrstream); - tile->pkthdrstream = 0; - } - if (tile->pptstab) { - jpc_ppxstab_destroy(tile->pptstab); - tile->pptstab = 0; - } - - tile->state = JPC_TILE_DONE; - - return 0; + continue; +} + for (cblkno = 0, cblk = prc->cblks; cblkno < prc->numcblks; ++cblkno, ++cblk) { + + while (cblk->segs.head) { + seg = cblk->segs.head; + jpc_seglist_remove(&cblk->segs, seg); + jpc_seg_destroy(seg); + } + jas_matrix_destroy(cblk->data); + if (cblk->mqdec) { + jpc_mqdec_destroy(cblk->mqdec); + } + if (cblk->nulldec) { + jpc_bitstream_close(cblk->nulldec); + } + if (cblk->flags) { + jas_matrix_destroy(cblk->flags); + } + } + if (prc->incltagtree) { + jpc_tagtree_destroy(prc->incltagtree); + } + if (prc->numimsbstagtree) { + jpc_tagtree_destroy(prc->numimsbstagtree); + } + if (prc->cblks) { + jas_free(prc->cblks); + } + } +} + if (band->data) { + jas_matrix_destroy(band->data); + } + if (band->prcs) { + jas_free(band->prcs); + } + } + if (rlvl->bands) { + jas_free(rlvl->bands); + } + } + if (tcomp->rlvls) { + jas_free(tcomp->rlvls); + } + if (tcomp->data) { + jas_matrix_destroy(tcomp->data); + } + if (tcomp->tsfb) { + jpc_tsfb_destroy(tcomp->tsfb); + } + } +} + if (tile->cp) { + jpc_dec_cp_destroy(tile->cp); + tile->cp = 0; + } + if (tile->tcomps) { + jas_free(tile->tcomps); + tile->tcomps = 0; + } + if (tile->pi) { + jpc_pi_destroy(tile->pi); + tile->pi = 0; + } + if (tile->pkthdrstream) { + jas_stream_close(tile->pkthdrstream); + tile->pkthdrstream = 0; + } + if (tile->pptstab) { + jpc_ppxstab_destroy(tile->pptstab); + tile->pptstab = 0; + } + + tile->state = JPC_TILE_DONE; + + return 0; } static int jpc_dec_tiledecode(jpc_dec_t *dec, jpc_dec_tile_t *tile) { - int i; - int j; - jpc_dec_tcomp_t *tcomp; - jpc_dec_rlvl_t *rlvl; - jpc_dec_band_t *band; - int compno; - int rlvlno; - int bandno; - int adjust; - int v; - jpc_dec_ccp_t *ccp; - jpc_dec_cmpt_t *cmpt; - - if (jpc_dec_decodecblks(dec, tile)) { - fprintf(stderr, "jpc_dec_decodecblks failed\n"); - return -1; - } - - /* Perform dequantization. */ - for (compno = 0, tcomp = tile->tcomps; compno < dec->numcomps; - ++compno, ++tcomp) { - ccp = &tile->cp->ccps[compno]; - for (rlvlno = 0, rlvl = tcomp->rlvls; rlvlno < tcomp->numrlvls; - ++rlvlno, ++rlvl) { - if (!rlvl->bands) { - continue; - } - for (bandno = 0, band = rlvl->bands; - bandno < rlvl->numbands; ++bandno, ++band) { - if (!band->data) { - continue; - } - jpc_undo_roi(band->data, band->roishift, ccp->roishift - - band->roishift, band->numbps); - if (tile->realmode) { - jas_matrix_asl(band->data, JPC_FIX_FRACBITS); - jpc_dequantize(band->data, band->absstepsize); - } - - } - } - } - - /* Apply an inverse wavelet transform if necessary. */ - for (compno = 0, tcomp = tile->tcomps; compno < dec->numcomps; - ++compno, ++tcomp) { - ccp = &tile->cp->ccps[compno]; - jpc_tsfb_synthesize(tcomp->tsfb, ((ccp->qmfbid == - JPC_COX_RFT) ? JPC_TSFB_RITIMODE : 0), tcomp->data); - } - - - /* Apply an inverse intercomponent transform if necessary. */ - switch (tile->cp->mctid) { - case JPC_MCT_RCT: - assert(dec->numcomps == 3); - jpc_irct(tile->tcomps[0].data, tile->tcomps[1].data, - tile->tcomps[2].data); - break; - case JPC_MCT_ICT: - assert(dec->numcomps == 3); - jpc_iict(tile->tcomps[0].data, tile->tcomps[1].data, - tile->tcomps[2].data); - break; - } - - /* Perform rounding and convert to integer values. */ - if (tile->realmode) { - for (compno = 0, tcomp = tile->tcomps; compno < dec->numcomps; - ++compno, ++tcomp) { - for (i = 0; i < jas_matrix_numrows(tcomp->data); ++i) { - for (j = 0; j < jas_matrix_numcols(tcomp->data); ++j) { - v = jas_matrix_get(tcomp->data, i, j); - v = jpc_fix_round(v); - jas_matrix_set(tcomp->data, i, j, jpc_fixtoint(v)); - } - } - } - } - - /* Perform level shift. */ - for (compno = 0, tcomp = tile->tcomps, cmpt = dec->cmpts; compno < - dec->numcomps; ++compno, ++tcomp, ++cmpt) { - adjust = cmpt->sgnd ? 0 : (1 << (cmpt->prec - 1)); - for (i = 0; i < jas_matrix_numrows(tcomp->data); ++i) { - for (j = 0; j < jas_matrix_numcols(tcomp->data); ++j) { - *jas_matrix_getref(tcomp->data, i, j) += adjust; - } - } - } - - /* Perform clipping. */ - for (compno = 0, tcomp = tile->tcomps, cmpt = dec->cmpts; compno < - dec->numcomps; ++compno, ++tcomp, ++cmpt) { - jpc_fix_t mn; - jpc_fix_t mx; - mn = cmpt->sgnd ? (-(1 << (cmpt->prec - 1))) : (0); - mx = cmpt->sgnd ? ((1 << (cmpt->prec - 1)) - 1) : ((1 << - cmpt->prec) - 1); - jas_matrix_clip(tcomp->data, mn, mx); - } - - /* XXX need to free tsfb struct */ - - /* Write the data for each component of the image. */ - for (compno = 0, tcomp = tile->tcomps, cmpt = dec->cmpts; compno < - dec->numcomps; ++compno, ++tcomp, ++cmpt) { - if (jas_image_writecmpt(dec->image, compno, tcomp->xstart - - JPC_CEILDIV(dec->xstart, cmpt->hstep), tcomp->ystart - - JPC_CEILDIV(dec->ystart, cmpt->vstep), jas_matrix_numcols( - tcomp->data), jas_matrix_numrows(tcomp->data), tcomp->data)) { - fprintf(stderr, "write component failed\n"); - return -4; - } - } - - return 0; + int i; + int j; + jpc_dec_tcomp_t *tcomp; + jpc_dec_rlvl_t *rlvl; + jpc_dec_band_t *band; + int compno; + int rlvlno; + int bandno; + int adjust; + int v; + jpc_dec_ccp_t *ccp; + jpc_dec_cmpt_t *cmpt; + + if (jpc_dec_decodecblks(dec, tile)) { + fprintf(stderr, "jpc_dec_decodecblks failed\n"); + return -1; + } + + /* Perform dequantization. */ + for (compno = 0, tcomp = tile->tcomps; compno < dec->numcomps; + ++compno, ++tcomp) { + ccp = &tile->cp->ccps[compno]; + for (rlvlno = 0, rlvl = tcomp->rlvls; rlvlno < tcomp->numrlvls; + ++rlvlno, ++rlvl) { + if (!rlvl->bands) { + continue; + } + for (bandno = 0, band = rlvl->bands; + bandno < rlvl->numbands; ++bandno, ++band) { + if (!band->data) { + continue; + } + jpc_undo_roi(band->data, band->roishift, ccp->roishift - + band->roishift, band->numbps); + if (tile->realmode) { + jas_matrix_asl(band->data, JPC_FIX_FRACBITS); + jpc_dequantize(band->data, band->absstepsize); + } + + } + } + } + + /* Apply an inverse wavelet transform if necessary. */ + for (compno = 0, tcomp = tile->tcomps; compno < dec->numcomps; + ++compno, ++tcomp) { + ccp = &tile->cp->ccps[compno]; + jpc_tsfb_synthesize(tcomp->tsfb, ((ccp->qmfbid == + JPC_COX_RFT) ? JPC_TSFB_RITIMODE : 0), tcomp->data); + } + + + /* Apply an inverse intercomponent transform if necessary. */ + switch (tile->cp->mctid) { + case JPC_MCT_RCT: + assert(dec->numcomps == 3); + jpc_irct(tile->tcomps[0].data, tile->tcomps[1].data, + tile->tcomps[2].data); + break; + case JPC_MCT_ICT: + assert(dec->numcomps == 3); + jpc_iict(tile->tcomps[0].data, tile->tcomps[1].data, + tile->tcomps[2].data); + break; + } + + /* Perform rounding and convert to integer values. */ + if (tile->realmode) { + for (compno = 0, tcomp = tile->tcomps; compno < dec->numcomps; + ++compno, ++tcomp) { + for (i = 0; i < jas_matrix_numrows(tcomp->data); ++i) { + for (j = 0; j < jas_matrix_numcols(tcomp->data); ++j) { + v = jas_matrix_get(tcomp->data, i, j); + v = jpc_fix_round(v); + jas_matrix_set(tcomp->data, i, j, jpc_fixtoint(v)); + } + } + } + } + + /* Perform level shift. */ + for (compno = 0, tcomp = tile->tcomps, cmpt = dec->cmpts; compno < + dec->numcomps; ++compno, ++tcomp, ++cmpt) { + adjust = cmpt->sgnd ? 0 : (1 << (cmpt->prec - 1)); + for (i = 0; i < jas_matrix_numrows(tcomp->data); ++i) { + for (j = 0; j < jas_matrix_numcols(tcomp->data); ++j) { + *jas_matrix_getref(tcomp->data, i, j) += adjust; + } + } + } + + /* Perform clipping. */ + for (compno = 0, tcomp = tile->tcomps, cmpt = dec->cmpts; compno < + dec->numcomps; ++compno, ++tcomp, ++cmpt) { + jpc_fix_t mn; + jpc_fix_t mx; + mn = cmpt->sgnd ? (-(1 << (cmpt->prec - 1))) : (0); + mx = cmpt->sgnd ? ((1 << (cmpt->prec - 1)) - 1) : ((1 << + cmpt->prec) - 1); + jas_matrix_clip(tcomp->data, mn, mx); + } + + /* XXX need to free tsfb struct */ + + /* Write the data for each component of the image. */ + for (compno = 0, tcomp = tile->tcomps, cmpt = dec->cmpts; compno < + dec->numcomps; ++compno, ++tcomp, ++cmpt) { + if (jas_image_writecmpt(dec->image, compno, tcomp->xstart - + JPC_CEILDIV(dec->xstart, cmpt->hstep), tcomp->ystart - + JPC_CEILDIV(dec->ystart, cmpt->vstep), jas_matrix_numcols( + tcomp->data), jas_matrix_numrows(tcomp->data), tcomp->data)) { + fprintf(stderr, "write component failed\n"); + return -4; + } + } + + return 0; } static int jpc_dec_process_eoc(jpc_dec_t *dec, jpc_ms_t *ms) { - int tileno; - jpc_dec_tile_t *tile; - for (tileno = 0, tile = dec->tiles; tileno < dec->numtiles; ++tileno, - ++tile) { - if (tile->state == JPC_TILE_ACTIVE) { - if (jpc_dec_tiledecode(dec, tile)) { - return -1; - } - } - jpc_dec_tilefini(dec, tile); - } + int tileno; + jpc_dec_tile_t *tile; + for (tileno = 0, tile = dec->tiles; tileno < dec->numtiles; ++tileno, + ++tile) { + if (tile->state == JPC_TILE_ACTIVE) { + if (jpc_dec_tiledecode(dec, tile)) { + return -1; + } + } + jpc_dec_tilefini(dec, tile); + } - /* We are done processing the code stream. */ - dec->state = JPC_MT; + /* We are done processing the code stream. */ + dec->state = JPC_MT; - return 1; + return 1; } static int jpc_dec_process_siz(jpc_dec_t *dec, jpc_ms_t *ms) { - jpc_siz_t *siz = &ms->parms.siz; - uint_fast16_t compno; - uint_fast32_t tileno; - jpc_dec_tile_t *tile; - jpc_dec_tcomp_t *tcomp; - uint_fast32_t htileno; - uint_fast32_t vtileno; - jpc_dec_cmpt_t *cmpt; - - dec->xstart = siz->xoff; - dec->ystart = siz->yoff; - dec->xend = siz->width; - dec->yend = siz->height; - dec->tilewidth = siz->tilewidth; - dec->tileheight = siz->tileheight; - dec->tilexoff = siz->tilexoff; - dec->tileyoff = siz->tileyoff; - dec->numcomps = siz->numcomps; - if (!(dec->cp = jpc_dec_cp_create(dec->numcomps))) { - return -1; - } - - if (!(dec->cmpts = jas_malloc(dec->numcomps * sizeof(jpc_dec_cmpt_t)))) { - return -1; - } - - for (compno = 0, cmpt = dec->cmpts; compno < dec->numcomps; ++compno, - ++cmpt) { - cmpt->prec = siz->comps[compno].prec; - cmpt->sgnd = siz->comps[compno].sgnd; - cmpt->hstep = siz->comps[compno].hsamp; - cmpt->vstep = siz->comps[compno].vsamp; - cmpt->width = JPC_CEILDIV(dec->xend, cmpt->hstep) - - JPC_CEILDIV(dec->xstart, cmpt->hstep); - cmpt->height = JPC_CEILDIV(dec->yend, cmpt->vstep) - - JPC_CEILDIV(dec->ystart, cmpt->vstep); - cmpt->hsubstep = 0; - cmpt->vsubstep = 0; - } - - dec->image = 0; - - dec->numhtiles = JPC_CEILDIV(dec->xend - dec->tilexoff, dec->tilewidth); - dec->numvtiles = JPC_CEILDIV(dec->yend - dec->tileyoff, dec->tileheight); - dec->numtiles = dec->numhtiles * dec->numvtiles; - if (!(dec->tiles = jas_malloc(dec->numtiles * sizeof(jpc_dec_tile_t)))) { - return -1; - } - - for (tileno = 0, tile = dec->tiles; tileno < dec->numtiles; ++tileno, - ++tile) { - htileno = tileno % dec->numhtiles; - vtileno = tileno / dec->numhtiles; - tile->realmode = 0; - tile->state = JPC_TILE_INIT; - tile->xstart = JAS_MAX(dec->tilexoff + htileno * dec->tilewidth, - dec->xstart); - tile->ystart = JAS_MAX(dec->tileyoff + vtileno * dec->tileheight, - dec->ystart); - tile->xend = JAS_MIN(dec->tilexoff + (htileno + 1) * - dec->tilewidth, dec->xend); - tile->yend = JAS_MIN(dec->tileyoff + (vtileno + 1) * - dec->tileheight, dec->yend); - tile->numparts = 0; - tile->partno = 0; - tile->pkthdrstream = 0; - tile->pkthdrstreampos = 0; - tile->pptstab = 0; - tile->cp = 0; - if (!(tile->tcomps = jas_malloc(dec->numcomps * - sizeof(jpc_dec_tcomp_t)))) { - return -1; - } - for (compno = 0, cmpt = dec->cmpts, tcomp = tile->tcomps; - compno < dec->numcomps; ++compno, ++cmpt, ++tcomp) { - tcomp->rlvls = 0; - tcomp->data = 0; - tcomp->xstart = JPC_CEILDIV(tile->xstart, cmpt->hstep); - tcomp->ystart = JPC_CEILDIV(tile->ystart, cmpt->vstep); - tcomp->xend = JPC_CEILDIV(tile->xend, cmpt->hstep); - tcomp->yend = JPC_CEILDIV(tile->yend, cmpt->vstep); - tcomp->tsfb = 0; - } - } - - dec->pkthdrstreams = 0; - - /* We should expect to encounter other main header marker segments - or an SOT marker segment next. */ - dec->state = JPC_MH; - - return 0; + jpc_siz_t *siz = &ms->parms.siz; + uint_fast16_t compno; + uint_fast32_t tileno; + jpc_dec_tile_t *tile; + jpc_dec_tcomp_t *tcomp; + uint_fast32_t htileno; + uint_fast32_t vtileno; + jpc_dec_cmpt_t *cmpt; + + dec->xstart = siz->xoff; + dec->ystart = siz->yoff; + dec->xend = siz->width; + dec->yend = siz->height; + dec->tilewidth = siz->tilewidth; + dec->tileheight = siz->tileheight; + dec->tilexoff = siz->tilexoff; + dec->tileyoff = siz->tileyoff; + dec->numcomps = siz->numcomps; + if (!(dec->cp = jpc_dec_cp_create(dec->numcomps))) { + return -1; + } + + if (!(dec->cmpts = jas_malloc(dec->numcomps * sizeof(jpc_dec_cmpt_t)))) { + return -1; + } + + for (compno = 0, cmpt = dec->cmpts; compno < dec->numcomps; ++compno, + ++cmpt) { + cmpt->prec = siz->comps[compno].prec; + cmpt->sgnd = siz->comps[compno].sgnd; + cmpt->hstep = siz->comps[compno].hsamp; + cmpt->vstep = siz->comps[compno].vsamp; + cmpt->width = JPC_CEILDIV(dec->xend, cmpt->hstep) - + JPC_CEILDIV(dec->xstart, cmpt->hstep); + cmpt->height = JPC_CEILDIV(dec->yend, cmpt->vstep) - + JPC_CEILDIV(dec->ystart, cmpt->vstep); + cmpt->hsubstep = 0; + cmpt->vsubstep = 0; + } + + dec->image = 0; + + dec->numhtiles = JPC_CEILDIV(dec->xend - dec->tilexoff, dec->tilewidth); + dec->numvtiles = JPC_CEILDIV(dec->yend - dec->tileyoff, dec->tileheight); + dec->numtiles = dec->numhtiles * dec->numvtiles; + if (!(dec->tiles = jas_malloc(dec->numtiles * sizeof(jpc_dec_tile_t)))) { + return -1; + } + + for (tileno = 0, tile = dec->tiles; tileno < dec->numtiles; ++tileno, + ++tile) { + htileno = tileno % dec->numhtiles; + vtileno = tileno / dec->numhtiles; + tile->realmode = 0; + tile->state = JPC_TILE_INIT; + tile->xstart = JAS_MAX(dec->tilexoff + htileno * dec->tilewidth, + dec->xstart); + tile->ystart = JAS_MAX(dec->tileyoff + vtileno * dec->tileheight, + dec->ystart); + tile->xend = JAS_MIN(dec->tilexoff + (htileno + 1) * + dec->tilewidth, dec->xend); + tile->yend = JAS_MIN(dec->tileyoff + (vtileno + 1) * + dec->tileheight, dec->yend); + tile->numparts = 0; + tile->partno = 0; + tile->pkthdrstream = 0; + tile->pkthdrstreampos = 0; + tile->pptstab = 0; + tile->cp = 0; + if (!(tile->tcomps = jas_malloc(dec->numcomps * + sizeof(jpc_dec_tcomp_t)))) { + return -1; + } + for (compno = 0, cmpt = dec->cmpts, tcomp = tile->tcomps; + compno < dec->numcomps; ++compno, ++cmpt, ++tcomp) { + tcomp->rlvls = 0; + tcomp->data = 0; + tcomp->xstart = JPC_CEILDIV(tile->xstart, cmpt->hstep); + tcomp->ystart = JPC_CEILDIV(tile->ystart, cmpt->vstep); + tcomp->xend = JPC_CEILDIV(tile->xend, cmpt->hstep); + tcomp->yend = JPC_CEILDIV(tile->yend, cmpt->vstep); + tcomp->tsfb = 0; + } + } + + dec->pkthdrstreams = 0; + + /* We should expect to encounter other main header marker segments + or an SOT marker segment next. */ + dec->state = JPC_MH; + + return 0; } static int jpc_dec_process_cod(jpc_dec_t *dec, jpc_ms_t *ms) { - jpc_cod_t *cod = &ms->parms.cod; - jpc_dec_tile_t *tile; - - switch (dec->state) { - case JPC_MH: - jpc_dec_cp_setfromcod(dec->cp, cod); - break; - case JPC_TPH: - if (!(tile = dec->curtile)) { - return -1; - } - if (tile->partno != 0) { - return -1; - } - jpc_dec_cp_setfromcod(tile->cp, cod); - break; - } - return 0; + jpc_cod_t *cod = &ms->parms.cod; + jpc_dec_tile_t *tile; + + switch (dec->state) { + case JPC_MH: + jpc_dec_cp_setfromcod(dec->cp, cod); + break; + case JPC_TPH: + if (!(tile = dec->curtile)) { + return -1; + } + if (tile->partno != 0) { + return -1; + } + jpc_dec_cp_setfromcod(tile->cp, cod); + break; + } + return 0; } static int jpc_dec_process_coc(jpc_dec_t *dec, jpc_ms_t *ms) { - jpc_coc_t *coc = &ms->parms.coc; - jpc_dec_tile_t *tile; - - if (coc->compno > dec->numcomps) { - fprintf(stderr, - "invalid component number in COC marker segment\n"); - return -1; - } - switch (dec->state) { - case JPC_MH: - jpc_dec_cp_setfromcoc(dec->cp, coc); - break; - case JPC_TPH: - if (!(tile = dec->curtile)) { - return -1; - } - if (tile->partno > 0) { - return -1; - } - jpc_dec_cp_setfromcoc(tile->cp, coc); - break; - } - return 0; + jpc_coc_t *coc = &ms->parms.coc; + jpc_dec_tile_t *tile; + + if (coc->compno > dec->numcomps) { + fprintf(stderr, + "invalid component number in COC marker segment\n"); + return -1; + } + switch (dec->state) { + case JPC_MH: + jpc_dec_cp_setfromcoc(dec->cp, coc); + break; + case JPC_TPH: + if (!(tile = dec->curtile)) { + return -1; + } + if (tile->partno > 0) { + return -1; + } + jpc_dec_cp_setfromcoc(tile->cp, coc); + break; + } + return 0; } static int jpc_dec_process_rgn(jpc_dec_t *dec, jpc_ms_t *ms) { - jpc_rgn_t *rgn = &ms->parms.rgn; - jpc_dec_tile_t *tile; - - if (rgn->compno > dec->numcomps) { - fprintf(stderr, - "invalid component number in RGN marker segment\n"); - return -1; - } - switch (dec->state) { - case JPC_MH: - jpc_dec_cp_setfromrgn(dec->cp, rgn); - break; - case JPC_TPH: - if (!(tile = dec->curtile)) { - return -1; - } - if (tile->partno > 0) { - return -1; - } - jpc_dec_cp_setfromrgn(tile->cp, rgn); - break; - } - - return 0; + jpc_rgn_t *rgn = &ms->parms.rgn; + jpc_dec_tile_t *tile; + + if (rgn->compno > dec->numcomps) { + fprintf(stderr, + "invalid component number in RGN marker segment\n"); + return -1; + } + switch (dec->state) { + case JPC_MH: + jpc_dec_cp_setfromrgn(dec->cp, rgn); + break; + case JPC_TPH: + if (!(tile = dec->curtile)) { + return -1; + } + if (tile->partno > 0) { + return -1; + } + jpc_dec_cp_setfromrgn(tile->cp, rgn); + break; + } + + return 0; } static int jpc_dec_process_qcd(jpc_dec_t *dec, jpc_ms_t *ms) { - jpc_qcd_t *qcd = &ms->parms.qcd; - jpc_dec_tile_t *tile; - - switch (dec->state) { - case JPC_MH: - jpc_dec_cp_setfromqcd(dec->cp, qcd); - break; - case JPC_TPH: - if (!(tile = dec->curtile)) { - return -1; - } - if (tile->partno > 0) { - return -1; - } - jpc_dec_cp_setfromqcd(tile->cp, qcd); - break; - } - return 0; + jpc_qcd_t *qcd = &ms->parms.qcd; + jpc_dec_tile_t *tile; + + switch (dec->state) { + case JPC_MH: + jpc_dec_cp_setfromqcd(dec->cp, qcd); + break; + case JPC_TPH: + if (!(tile = dec->curtile)) { + return -1; + } + if (tile->partno > 0) { + return -1; + } + jpc_dec_cp_setfromqcd(tile->cp, qcd); + break; + } + return 0; } static int jpc_dec_process_qcc(jpc_dec_t *dec, jpc_ms_t *ms) { - jpc_qcc_t *qcc = &ms->parms.qcc; - jpc_dec_tile_t *tile; - - if (qcc->compno > dec->numcomps) { - fprintf(stderr, - "invalid component number in QCC marker segment\n"); - return -1; - } - switch (dec->state) { - case JPC_MH: - jpc_dec_cp_setfromqcc(dec->cp, qcc); - break; - case JPC_TPH: - if (!(tile = dec->curtile)) { - return -1; - } - if (tile->partno > 0) { - return -1; - } - jpc_dec_cp_setfromqcc(tile->cp, qcc); - break; - } - return 0; + jpc_qcc_t *qcc = &ms->parms.qcc; + jpc_dec_tile_t *tile; + + if (qcc->compno > dec->numcomps) { + fprintf(stderr, + "invalid component number in QCC marker segment\n"); + return -1; + } + switch (dec->state) { + case JPC_MH: + jpc_dec_cp_setfromqcc(dec->cp, qcc); + break; + case JPC_TPH: + if (!(tile = dec->curtile)) { + return -1; + } + if (tile->partno > 0) { + return -1; + } + jpc_dec_cp_setfromqcc(tile->cp, qcc); + break; + } + return 0; } static int jpc_dec_process_poc(jpc_dec_t *dec, jpc_ms_t *ms) { - jpc_poc_t *poc = &ms->parms.poc; - jpc_dec_tile_t *tile; - switch (dec->state) { - case JPC_MH: - if (jpc_dec_cp_setfrompoc(dec->cp, poc, 1)) { - return -1; - } - break; - case JPC_TPH: - if (!(tile = dec->curtile)) { - return -1; - } - if (!tile->partno) { - if (jpc_dec_cp_setfrompoc(tile->cp, poc, (!tile->partno))) { - return -1; - } - } else { - jpc_pi_addpchgfrompoc(tile->pi, poc); - } - break; - } - return 0; + jpc_poc_t *poc = &ms->parms.poc; + jpc_dec_tile_t *tile; + switch (dec->state) { + case JPC_MH: + if (jpc_dec_cp_setfrompoc(dec->cp, poc, 1)) { + return -1; + } + break; + case JPC_TPH: + if (!(tile = dec->curtile)) { + return -1; + } + if (!tile->partno) { + if (jpc_dec_cp_setfrompoc(tile->cp, poc, (!tile->partno))) { + return -1; + } + } else { + jpc_pi_addpchgfrompoc(tile->pi, poc); + } + break; + } + return 0; } static int jpc_dec_process_ppm(jpc_dec_t *dec, jpc_ms_t *ms) { - jpc_ppm_t *ppm = &ms->parms.ppm; - jpc_ppxstabent_t *ppmstabent; + jpc_ppm_t *ppm = &ms->parms.ppm; + jpc_ppxstabent_t *ppmstabent; - if (!dec->ppmstab) { - if (!(dec->ppmstab = jpc_ppxstab_create())) { - return -1; - } - } + if (!dec->ppmstab) { + if (!(dec->ppmstab = jpc_ppxstab_create())) { + return -1; + } + } - if (!(ppmstabent = jpc_ppxstabent_create())) { - return -1; - } - ppmstabent->ind = ppm->ind; - ppmstabent->data = ppm->data; - ppm->data = 0; - ppmstabent->len = ppm->len; - if (jpc_ppxstab_insert(dec->ppmstab, ppmstabent)) { - return -1; - } - return 0; + if (!(ppmstabent = jpc_ppxstabent_create())) { + return -1; + } + ppmstabent->ind = ppm->ind; + ppmstabent->data = ppm->data; + ppm->data = 0; + ppmstabent->len = ppm->len; + if (jpc_ppxstab_insert(dec->ppmstab, ppmstabent)) { + return -1; + } + return 0; } static int jpc_dec_process_ppt(jpc_dec_t *dec, jpc_ms_t *ms) { - jpc_ppt_t *ppt = &ms->parms.ppt; - jpc_dec_tile_t *tile; - jpc_ppxstabent_t *pptstabent; - - tile = dec->curtile; - if (!tile->pptstab) { - if (!(tile->pptstab = jpc_ppxstab_create())) { - return -1; - } - } - if (!(pptstabent = jpc_ppxstabent_create())) { - return -1; - } - pptstabent->ind = ppt->ind; - pptstabent->data = ppt->data; - ppt->data = 0; - pptstabent->len = ppt->len; - if (jpc_ppxstab_insert(tile->pptstab, pptstabent)) { - return -1; - } - return 0; + jpc_ppt_t *ppt = &ms->parms.ppt; + jpc_dec_tile_t *tile; + jpc_ppxstabent_t *pptstabent; + + tile = dec->curtile; + if (!tile->pptstab) { + if (!(tile->pptstab = jpc_ppxstab_create())) { + return -1; + } + } + if (!(pptstabent = jpc_ppxstabent_create())) { + return -1; + } + pptstabent->ind = ppt->ind; + pptstabent->data = ppt->data; + ppt->data = 0; + pptstabent->len = ppt->len; + if (jpc_ppxstab_insert(tile->pptstab, pptstabent)) { + return -1; + } + return 0; } static int jpc_dec_process_com(jpc_dec_t *dec, jpc_ms_t *ms) { - return 0; + return 0; } static int jpc_dec_process_unk(jpc_dec_t *dec, jpc_ms_t *ms) { - fprintf(stderr, "warning: ignoring unknown marker segment\n"); - jpc_ms_dump(ms, stderr); - return 0; + fprintf(stderr, "warning: ignoring unknown marker segment\n"); + jpc_ms_dump(ms, stderr); + return 0; } /******************************************************************************\ @@ -1512,426 +1514,426 @@ static int jpc_dec_process_unk(jpc_dec_t *dec, jpc_ms_t *ms) static jpc_dec_cp_t *jpc_dec_cp_create(uint_fast16_t numcomps) { - jpc_dec_cp_t *cp; - jpc_dec_ccp_t *ccp; - int compno; - - if (!(cp = jas_malloc(sizeof(jpc_dec_cp_t)))) { - return 0; - } - cp->flags = 0; - cp->numcomps = numcomps; - cp->prgord = 0; - cp->numlyrs = 0; - cp->mctid = 0; - cp->csty = 0; - if (!(cp->ccps = jas_malloc(cp->numcomps * sizeof(jpc_dec_ccp_t)))) { - return 0; - } - if (!(cp->pchglist = jpc_pchglist_create())) { - jas_free(cp->ccps); - return 0; - } - for (compno = 0, ccp = cp->ccps; compno < cp->numcomps; - ++compno, ++ccp) { - ccp->flags = 0; - ccp->numrlvls = 0; - ccp->cblkwidthexpn = 0; - ccp->cblkheightexpn = 0; - ccp->qmfbid = 0; - ccp->numstepsizes = 0; - ccp->numguardbits = 0; - ccp->roishift = 0; - ccp->cblkctx = 0; - } - return cp; + jpc_dec_cp_t *cp; + jpc_dec_ccp_t *ccp; + int compno; + + if (!(cp = jas_malloc(sizeof(jpc_dec_cp_t)))) { + return 0; + } + cp->flags = 0; + cp->numcomps = numcomps; + cp->prgord = 0; + cp->numlyrs = 0; + cp->mctid = 0; + cp->csty = 0; + if (!(cp->ccps = jas_malloc(cp->numcomps * sizeof(jpc_dec_ccp_t)))) { + return 0; + } + if (!(cp->pchglist = jpc_pchglist_create())) { + jas_free(cp->ccps); + return 0; + } + for (compno = 0, ccp = cp->ccps; compno < cp->numcomps; + ++compno, ++ccp) { + ccp->flags = 0; + ccp->numrlvls = 0; + ccp->cblkwidthexpn = 0; + ccp->cblkheightexpn = 0; + ccp->qmfbid = 0; + ccp->numstepsizes = 0; + ccp->numguardbits = 0; + ccp->roishift = 0; + ccp->cblkctx = 0; + } + return cp; } static jpc_dec_cp_t *jpc_dec_cp_copy(jpc_dec_cp_t *cp) { - jpc_dec_cp_t *newcp; - jpc_dec_ccp_t *newccp; - jpc_dec_ccp_t *ccp; - int compno; - - if (!(newcp = jpc_dec_cp_create(cp->numcomps))) { - return 0; - } - newcp->flags = cp->flags; - newcp->prgord = cp->prgord; - newcp->numlyrs = cp->numlyrs; - newcp->mctid = cp->mctid; - newcp->csty = cp->csty; - jpc_pchglist_destroy(newcp->pchglist); - newcp->pchglist = 0; - if (!(newcp->pchglist = jpc_pchglist_copy(cp->pchglist))) { - jas_free(newcp); - return 0; - } - for (compno = 0, newccp = newcp->ccps, ccp = cp->ccps; - compno < cp->numcomps; - ++compno, ++newccp, ++ccp) { - *newccp = *ccp; - } - return newcp; + jpc_dec_cp_t *newcp; + jpc_dec_ccp_t *newccp; + jpc_dec_ccp_t *ccp; + int compno; + + if (!(newcp = jpc_dec_cp_create(cp->numcomps))) { + return 0; + } + newcp->flags = cp->flags; + newcp->prgord = cp->prgord; + newcp->numlyrs = cp->numlyrs; + newcp->mctid = cp->mctid; + newcp->csty = cp->csty; + jpc_pchglist_destroy(newcp->pchglist); + newcp->pchglist = 0; + if (!(newcp->pchglist = jpc_pchglist_copy(cp->pchglist))) { + jas_free(newcp); + return 0; + } + for (compno = 0, newccp = newcp->ccps, ccp = cp->ccps; + compno < cp->numcomps; + ++compno, ++newccp, ++ccp) { + *newccp = *ccp; + } + return newcp; } static void jpc_dec_cp_resetflags(jpc_dec_cp_t *cp) { - int compno; - jpc_dec_ccp_t *ccp; - cp->flags &= (JPC_CSET | JPC_QSET); - for (compno = 0, ccp = cp->ccps; compno < cp->numcomps; - ++compno, ++ccp) { - ccp->flags = 0; - } + int compno; + jpc_dec_ccp_t *ccp; + cp->flags &= (JPC_CSET | JPC_QSET); + for (compno = 0, ccp = cp->ccps; compno < cp->numcomps; + ++compno, ++ccp) { + ccp->flags = 0; + } } static void jpc_dec_cp_destroy(jpc_dec_cp_t *cp) { - if (cp->ccps) { - jas_free(cp->ccps); - } - if (cp->pchglist) { - jpc_pchglist_destroy(cp->pchglist); - } - jas_free(cp); + if (cp->ccps) { + jas_free(cp->ccps); + } + if (cp->pchglist) { + jpc_pchglist_destroy(cp->pchglist); + } + jas_free(cp); } static int jpc_dec_cp_isvalid(jpc_dec_cp_t *cp) { - uint_fast16_t compcnt; - jpc_dec_ccp_t *ccp; + uint_fast16_t compcnt; + jpc_dec_ccp_t *ccp; - if (!(cp->flags & JPC_CSET) || !(cp->flags & JPC_QSET)) { - return 0; - } - for (compcnt = cp->numcomps, ccp = cp->ccps; compcnt > 0; --compcnt, - ++ccp) { - /* Is there enough step sizes for the number of bands? */ - if ((ccp->qsty != JPC_QCX_SIQNT && ccp->numstepsizes < 3 * - ccp->numrlvls - 2) || (ccp->qsty == JPC_QCX_SIQNT && - ccp->numstepsizes != 1)) { - return 0; - } - } - return 1; + if (!(cp->flags & JPC_CSET) || !(cp->flags & JPC_QSET)) { + return 0; + } + for (compcnt = cp->numcomps, ccp = cp->ccps; compcnt > 0; --compcnt, + ++ccp) { + /* Is there enough step sizes for the number of bands? */ + if ((ccp->qsty != JPC_QCX_SIQNT && ccp->numstepsizes < 3 * + ccp->numrlvls - 2) || (ccp->qsty == JPC_QCX_SIQNT && + ccp->numstepsizes != 1)) { + return 0; + } + } + return 1; } static void calcstepsizes(uint_fast16_t refstepsize, int numrlvls, uint_fast16_t *stepsizes) { - int bandno; - int numbands; - uint_fast16_t expn; - uint_fast16_t mant; - expn = JPC_QCX_GETEXPN(refstepsize); - mant = JPC_QCX_GETMANT(refstepsize); - numbands = 3 * numrlvls - 2; - for (bandno = 0; bandno < numbands; ++bandno) { - stepsizes[bandno] = JPC_QCX_MANT(mant) | JPC_QCX_EXPN(expn + - (numrlvls - 1) - (numrlvls - 1 - ((bandno > 0) ? ((bandno + 2) / 3) : (0)))); - } + int bandno; + int numbands; + uint_fast16_t expn; + uint_fast16_t mant; + expn = JPC_QCX_GETEXPN(refstepsize); + mant = JPC_QCX_GETMANT(refstepsize); + numbands = 3 * numrlvls - 2; + for (bandno = 0; bandno < numbands; ++bandno) { + stepsizes[bandno] = JPC_QCX_MANT(mant) | JPC_QCX_EXPN(expn + + (numrlvls - 1) - (numrlvls - 1 - ((bandno > 0) ? ((bandno + 2) / 3) : (0)))); + } } static int jpc_dec_cp_prepare(jpc_dec_cp_t *cp) { - jpc_dec_ccp_t *ccp; - int compno; - int i; - for (compno = 0, ccp = cp->ccps; compno < cp->numcomps; - ++compno, ++ccp) { - if (!(ccp->csty & JPC_COX_PRT)) { - for (i = 0; i < JPC_MAXRLVLS; ++i) { - ccp->prcwidthexpns[i] = 15; - ccp->prcheightexpns[i] = 15; - } - } - if (ccp->qsty == JPC_QCX_SIQNT) { - calcstepsizes(ccp->stepsizes[0], ccp->numrlvls, ccp->stepsizes); - } - } - return 0; + jpc_dec_ccp_t *ccp; + int compno; + int i; + for (compno = 0, ccp = cp->ccps; compno < cp->numcomps; + ++compno, ++ccp) { + if (!(ccp->csty & JPC_COX_PRT)) { + for (i = 0; i < JPC_MAXRLVLS; ++i) { + ccp->prcwidthexpns[i] = 15; + ccp->prcheightexpns[i] = 15; + } + } + if (ccp->qsty == JPC_QCX_SIQNT) { + calcstepsizes(ccp->stepsizes[0], ccp->numrlvls, ccp->stepsizes); + } + } + return 0; } static int jpc_dec_cp_setfromcod(jpc_dec_cp_t *cp, jpc_cod_t *cod) { - jpc_dec_ccp_t *ccp; - int compno; - cp->flags |= JPC_CSET; - cp->prgord = cod->prg; - if (cod->mctrans) { - cp->mctid = (cod->compparms.qmfbid == JPC_COX_INS) ? (JPC_MCT_ICT) : (JPC_MCT_RCT); - } else { - cp->mctid = JPC_MCT_NONE; - } - cp->numlyrs = cod->numlyrs; - cp->csty = cod->csty & (JPC_COD_SOP | JPC_COD_EPH); - for (compno = 0, ccp = cp->ccps; compno < cp->numcomps; - ++compno, ++ccp) { - jpc_dec_cp_setfromcox(cp, ccp, &cod->compparms, 0); - } - cp->flags |= JPC_CSET; - return 0; + jpc_dec_ccp_t *ccp; + int compno; + cp->flags |= JPC_CSET; + cp->prgord = cod->prg; + if (cod->mctrans) { + cp->mctid = (cod->compparms.qmfbid == JPC_COX_INS) ? (JPC_MCT_ICT) : (JPC_MCT_RCT); + } else { + cp->mctid = JPC_MCT_NONE; + } + cp->numlyrs = cod->numlyrs; + cp->csty = cod->csty & (JPC_COD_SOP | JPC_COD_EPH); + for (compno = 0, ccp = cp->ccps; compno < cp->numcomps; + ++compno, ++ccp) { + jpc_dec_cp_setfromcox(cp, ccp, &cod->compparms, 0); + } + cp->flags |= JPC_CSET; + return 0; } static int jpc_dec_cp_setfromcoc(jpc_dec_cp_t *cp, jpc_coc_t *coc) { - jpc_dec_cp_setfromcox(cp, &cp->ccps[coc->compno], &coc->compparms, JPC_COC); - return 0; + jpc_dec_cp_setfromcox(cp, &cp->ccps[coc->compno], &coc->compparms, JPC_COC); + return 0; } static int jpc_dec_cp_setfromcox(jpc_dec_cp_t *cp, jpc_dec_ccp_t *ccp, jpc_coxcp_t *compparms, int flags) { - int rlvlno; - if ((flags & JPC_COC) || !(ccp->flags & JPC_COC)) { - ccp->numrlvls = compparms->numdlvls + 1; - ccp->cblkwidthexpn = JPC_COX_GETCBLKSIZEEXPN( - compparms->cblkwidthval); - ccp->cblkheightexpn = JPC_COX_GETCBLKSIZEEXPN( - compparms->cblkheightval); - ccp->qmfbid = compparms->qmfbid; - ccp->cblkctx = compparms->cblksty; - ccp->csty = compparms->csty & JPC_COX_PRT; - for (rlvlno = 0; rlvlno < compparms->numrlvls; ++rlvlno) { - ccp->prcwidthexpns[rlvlno] = - compparms->rlvls[rlvlno].parwidthval; - ccp->prcheightexpns[rlvlno] = - compparms->rlvls[rlvlno].parheightval; - } - ccp->flags |= flags | JPC_CSET; - } - return 0; + int rlvlno; + if ((flags & JPC_COC) || !(ccp->flags & JPC_COC)) { + ccp->numrlvls = compparms->numdlvls + 1; + ccp->cblkwidthexpn = JPC_COX_GETCBLKSIZEEXPN( + compparms->cblkwidthval); + ccp->cblkheightexpn = JPC_COX_GETCBLKSIZEEXPN( + compparms->cblkheightval); + ccp->qmfbid = compparms->qmfbid; + ccp->cblkctx = compparms->cblksty; + ccp->csty = compparms->csty & JPC_COX_PRT; + for (rlvlno = 0; rlvlno < compparms->numrlvls; ++rlvlno) { + ccp->prcwidthexpns[rlvlno] = + compparms->rlvls[rlvlno].parwidthval; + ccp->prcheightexpns[rlvlno] = + compparms->rlvls[rlvlno].parheightval; + } + ccp->flags |= flags | JPC_CSET; + } + return 0; } static int jpc_dec_cp_setfromqcd(jpc_dec_cp_t *cp, jpc_qcd_t *qcd) { - int compno; - jpc_dec_ccp_t *ccp; - for (compno = 0, ccp = cp->ccps; compno < cp->numcomps; - ++compno, ++ccp) { - jpc_dec_cp_setfromqcx(cp, ccp, &qcd->compparms, 0); - } - cp->flags |= JPC_QSET; - return 0; + int compno; + jpc_dec_ccp_t *ccp; + for (compno = 0, ccp = cp->ccps; compno < cp->numcomps; + ++compno, ++ccp) { + jpc_dec_cp_setfromqcx(cp, ccp, &qcd->compparms, 0); + } + cp->flags |= JPC_QSET; + return 0; } static int jpc_dec_cp_setfromqcc(jpc_dec_cp_t *cp, jpc_qcc_t *qcc) { - return jpc_dec_cp_setfromqcx(cp, &cp->ccps[qcc->compno], &qcc->compparms, JPC_QCC); + return jpc_dec_cp_setfromqcx(cp, &cp->ccps[qcc->compno], &qcc->compparms, JPC_QCC); } static int jpc_dec_cp_setfromqcx(jpc_dec_cp_t *cp, jpc_dec_ccp_t *ccp, jpc_qcxcp_t *compparms, int flags) { - int bandno; - if ((flags & JPC_QCC) || !(ccp->flags & JPC_QCC)) { - ccp->flags |= flags | JPC_QSET; - for (bandno = 0; bandno < compparms->numstepsizes; ++bandno) { - ccp->stepsizes[bandno] = compparms->stepsizes[bandno]; - } - ccp->numstepsizes = compparms->numstepsizes; - ccp->numguardbits = compparms->numguard; - ccp->qsty = compparms->qntsty; - } - return 0; + int bandno; + if ((flags & JPC_QCC) || !(ccp->flags & JPC_QCC)) { + ccp->flags |= flags | JPC_QSET; + for (bandno = 0; bandno < compparms->numstepsizes; ++bandno) { + ccp->stepsizes[bandno] = compparms->stepsizes[bandno]; + } + ccp->numstepsizes = compparms->numstepsizes; + ccp->numguardbits = compparms->numguard; + ccp->qsty = compparms->qntsty; + } + return 0; } static int jpc_dec_cp_setfromrgn(jpc_dec_cp_t *cp, jpc_rgn_t *rgn) { - jpc_dec_ccp_t *ccp; - ccp = &cp->ccps[rgn->compno]; - ccp->roishift = rgn->roishift; - return 0; + jpc_dec_ccp_t *ccp; + ccp = &cp->ccps[rgn->compno]; + ccp->roishift = rgn->roishift; + return 0; } static int jpc_pi_addpchgfrompoc(jpc_pi_t *pi, jpc_poc_t *poc) { - int pchgno; - jpc_pchg_t *pchg; - for (pchgno = 0; pchgno < poc->numpchgs; ++pchgno) { - if (!(pchg = jpc_pchg_copy(&poc->pchgs[pchgno]))) { - return -1; - } - if (jpc_pchglist_insert(pi->pchglist, -1, pchg)) { - return -1; - } - } - return 0; + int pchgno; + jpc_pchg_t *pchg; + for (pchgno = 0; pchgno < poc->numpchgs; ++pchgno) { + if (!(pchg = jpc_pchg_copy(&poc->pchgs[pchgno]))) { + return -1; + } + if (jpc_pchglist_insert(pi->pchglist, -1, pchg)) { + return -1; + } + } + return 0; } static int jpc_dec_cp_setfrompoc(jpc_dec_cp_t *cp, jpc_poc_t *poc, int reset) { - int pchgno; - jpc_pchg_t *pchg; - if (reset) { - while (jpc_pchglist_numpchgs(cp->pchglist) > 0) { - pchg = jpc_pchglist_remove(cp->pchglist, 0); - jpc_pchg_destroy(pchg); - } - } - for (pchgno = 0; pchgno < poc->numpchgs; ++pchgno) { - if (!(pchg = jpc_pchg_copy(&poc->pchgs[pchgno]))) { - return -1; - } - if (jpc_pchglist_insert(cp->pchglist, -1, pchg)) { - return -1; - } - } - return 0; + int pchgno; + jpc_pchg_t *pchg; + if (reset) { + while (jpc_pchglist_numpchgs(cp->pchglist) > 0) { + pchg = jpc_pchglist_remove(cp->pchglist, 0); + jpc_pchg_destroy(pchg); + } + } + for (pchgno = 0; pchgno < poc->numpchgs; ++pchgno) { + if (!(pchg = jpc_pchg_copy(&poc->pchgs[pchgno]))) { + return -1; + } + if (jpc_pchglist_insert(cp->pchglist, -1, pchg)) { + return -1; + } + } + return 0; } static jpc_fix_t jpc_calcabsstepsize(int stepsize, int numbits) { - jpc_fix_t absstepsize; - int n; + jpc_fix_t absstepsize; + int n; - absstepsize = jpc_inttofix(1); - n = JPC_FIX_FRACBITS - 11; - absstepsize |= (n >= 0) ? (JPC_QCX_GETMANT(stepsize) << n) : - (JPC_QCX_GETMANT(stepsize) >> (-n)); - n = numbits - JPC_QCX_GETEXPN(stepsize); - absstepsize = (n >= 0) ? (absstepsize << n) : (absstepsize >> (-n)); - return absstepsize; + absstepsize = jpc_inttofix(1); + n = JPC_FIX_FRACBITS - 11; + absstepsize |= (n >= 0) ? (JPC_QCX_GETMANT(stepsize) << n) : + (JPC_QCX_GETMANT(stepsize) >> (-n)); + n = numbits - JPC_QCX_GETEXPN(stepsize); + absstepsize = (n >= 0) ? (absstepsize << n) : (absstepsize >> (-n)); + return absstepsize; } static void jpc_dequantize(jas_matrix_t *x, jpc_fix_t absstepsize) { - int i; - int j; - int t; + int i; + int j; + int t; - assert(absstepsize >= 0); - if (absstepsize == jpc_inttofix(1)) { - return; - } + assert(absstepsize >= 0); + if (absstepsize == jpc_inttofix(1)) { + return; + } - for (i = 0; i < jas_matrix_numrows(x); ++i) { - for (j = 0; j < jas_matrix_numcols(x); ++j) { - t = jas_matrix_get(x, i, j); - if (t) { - t = jpc_fix_mul(t, absstepsize); - } else { - t = 0; - } - jas_matrix_set(x, i, j, t); - } - } + for (i = 0; i < jas_matrix_numrows(x); ++i) { + for (j = 0; j < jas_matrix_numcols(x); ++j) { + t = jas_matrix_get(x, i, j); + if (t) { + t = jpc_fix_mul(t, absstepsize); + } else { + t = 0; + } + jas_matrix_set(x, i, j, t); + } + } } static void jpc_undo_roi(jas_matrix_t *x, int roishift, int bgshift, int numbps) { - int i; - int j; - int thresh; - jpc_fix_t val; - jpc_fix_t mag; - bool warn; - uint_fast32_t mask; - - if (roishift == 0 && bgshift == 0) { - return; - } - thresh = 1 << roishift; - - warn = false; - for (i = 0; i < jas_matrix_numrows(x); ++i) { - for (j = 0; j < jas_matrix_numcols(x); ++j) { - val = jas_matrix_get(x, i, j); - mag = JAS_ABS(val); - if (mag >= thresh) { - /* We are dealing with ROI data. */ - mag >>= roishift; - val = (val < 0) ? (-mag) : mag; - jas_matrix_set(x, i, j, val); - } else { - /* We are dealing with non-ROI (i.e., background) data. */ - mag <<= bgshift; - mask = (1 << numbps) - 1; - /* Perform a basic sanity check on the sample value. */ - /* Some implementations write garbage in the unused - most-significant bit planes introduced by ROI shifting. - Here we ensure that any such bits are masked off. */ - if (mag & (~mask)) { - if (!warn) { - fprintf(stderr, - "warning: possibly corrupt code stream\n"); - warn = true; - } - mag &= mask; - } - val = (val < 0) ? (-mag) : mag; - jas_matrix_set(x, i, j, val); - } - } - } + int i; + int j; + int thresh; + jpc_fix_t val; + jpc_fix_t mag; + bool warn; + uint_fast32_t mask; + + if (roishift == 0 && bgshift == 0) { + return; + } + thresh = 1 << roishift; + + warn = false; + for (i = 0; i < jas_matrix_numrows(x); ++i) { + for (j = 0; j < jas_matrix_numcols(x); ++j) { + val = jas_matrix_get(x, i, j); + mag = JAS_ABS(val); + if (mag >= thresh) { + /* We are dealing with ROI data. */ + mag >>= roishift; + val = (val < 0) ? (-mag) : mag; + jas_matrix_set(x, i, j, val); + } else { + /* We are dealing with non-ROI (i.e., background) data. */ + mag <<= bgshift; + mask = (1 << numbps) - 1; + /* Perform a basic sanity check on the sample value. */ + /* Some implementations write garbage in the unused + most-significant bit planes introduced by ROI shifting. + Here we ensure that any such bits are masked off. */ + if (mag & (~mask)) { + if (!warn) { + fprintf(stderr, + "warning: possibly corrupt code stream\n"); + warn = true; + } + mag &= mask; + } + val = (val < 0) ? (-mag) : mag; + jas_matrix_set(x, i, j, val); + } + } + } } static jpc_dec_t *jpc_dec_create(jpc_dec_importopts_t *impopts, jas_stream_t *in) { - jpc_dec_t *dec; - - if (!(dec = jas_malloc(sizeof(jpc_dec_t)))) { - return 0; - } - - dec->image = 0; - dec->xstart = 0; - dec->ystart = 0; - dec->xend = 0; - dec->yend = 0; - dec->tilewidth = 0; - dec->tileheight = 0; - dec->tilexoff = 0; - dec->tileyoff = 0; - dec->numhtiles = 0; - dec->numvtiles = 0; - dec->numtiles = 0; - dec->tiles = 0; - dec->curtile = 0; - dec->numcomps = 0; - dec->in = in; - dec->cp = 0; - dec->maxlyrs = impopts->maxlyrs; - dec->maxpkts = impopts->maxpkts; + jpc_dec_t *dec; + + if (!(dec = jas_malloc(sizeof(jpc_dec_t)))) { + return 0; + } + + dec->image = 0; + dec->xstart = 0; + dec->ystart = 0; + dec->xend = 0; + dec->yend = 0; + dec->tilewidth = 0; + dec->tileheight = 0; + dec->tilexoff = 0; + dec->tileyoff = 0; + dec->numhtiles = 0; + dec->numvtiles = 0; + dec->numtiles = 0; + dec->tiles = 0; + dec->curtile = 0; + dec->numcomps = 0; + dec->in = in; + dec->cp = 0; + dec->maxlyrs = impopts->maxlyrs; + dec->maxpkts = impopts->maxpkts; dec->numpkts = 0; - dec->ppmseqno = 0; - dec->state = 0; - dec->cmpts = 0; - dec->pkthdrstreams = 0; - dec->ppmstab = 0; - dec->curtileendoff = 0; + dec->ppmseqno = 0; + dec->state = 0; + dec->cmpts = 0; + dec->pkthdrstreams = 0; + dec->ppmstab = 0; + dec->curtileendoff = 0; - return dec; + return dec; } static void jpc_dec_destroy(jpc_dec_t *dec) { - if (dec->cstate) { - jpc_cstate_destroy(dec->cstate); - } - if (dec->pkthdrstreams) { - jpc_streamlist_destroy(dec->pkthdrstreams); - } - if (dec->image) { - jas_image_destroy(dec->image); - } + if (dec->cstate) { + jpc_cstate_destroy(dec->cstate); + } + if (dec->pkthdrstreams) { + jpc_streamlist_destroy(dec->pkthdrstreams); + } + if (dec->image) { + jas_image_destroy(dec->image); + } - if (dec->cp) { - jpc_dec_cp_destroy(dec->cp); - } + if (dec->cp) { + jpc_dec_cp_destroy(dec->cp); + } - if (dec->cmpts) { - jas_free(dec->cmpts); - } + if (dec->cmpts) { + jas_free(dec->cmpts); + } - if (dec->tiles) { - jas_free(dec->tiles); - } + if (dec->tiles) { + jas_free(dec->tiles); + } - jas_free(dec); + jas_free(dec); } /******************************************************************************\ @@ -1940,395 +1942,411 @@ static void jpc_dec_destroy(jpc_dec_t *dec) void jpc_seglist_insert(jpc_dec_seglist_t *list, jpc_dec_seg_t *ins, jpc_dec_seg_t *node) { - jpc_dec_seg_t *prev; - jpc_dec_seg_t *next; - - prev = ins; - node->prev = prev; - next = prev ? (prev->next) : 0; - node->prev = prev; - node->next = next; - if (prev) { - prev->next = node; - } else { - list->head = node; - } - if (next) { - next->prev = node; - } else { - list->tail = node; - } + jpc_dec_seg_t *prev; + jpc_dec_seg_t *next; + + prev = ins; + node->prev = prev; + next = prev ? (prev->next) : 0; + node->prev = prev; + node->next = next; + if (prev) { + prev->next = node; + } else { + list->head = node; + } + if (next) { + next->prev = node; + } else { + list->tail = node; + } } void jpc_seglist_remove(jpc_dec_seglist_t *list, jpc_dec_seg_t *seg) { - jpc_dec_seg_t *prev; - jpc_dec_seg_t *next; - - prev = seg->prev; - next = seg->next; - if (prev) { - prev->next = next; - } else { - list->head = next; - } - if (next) { - next->prev = prev; - } else { - list->tail = prev; - } - seg->prev = 0; - seg->next = 0; + jpc_dec_seg_t *prev; + jpc_dec_seg_t *next; + + prev = seg->prev; + next = seg->next; + if (prev) { + prev->next = next; + } else { + list->head = next; + } + if (next) { + next->prev = prev; + } else { + list->tail = prev; + } + seg->prev = 0; + seg->next = 0; } jpc_dec_seg_t *jpc_seg_alloc(void) { - jpc_dec_seg_t *seg; + jpc_dec_seg_t *seg; - if (!(seg = jas_malloc(sizeof(jpc_dec_seg_t)))) { - return 0; - } - seg->prev = 0; - seg->next = 0; - seg->passno = -1; - seg->numpasses = 0; - seg->maxpasses = 0; - seg->type = JPC_SEG_INVALID; - seg->stream = 0; - seg->cnt = 0; - seg->complete = 0; - seg->lyrno = -1; - return seg; + if (!(seg = jas_malloc(sizeof(jpc_dec_seg_t)))) { + return 0; + } + seg->prev = 0; + seg->next = 0; + seg->passno = -1; + seg->numpasses = 0; + seg->maxpasses = 0; + seg->type = JPC_SEG_INVALID; + seg->stream = 0; + seg->cnt = 0; + seg->complete = 0; + seg->lyrno = -1; + return seg; } void jpc_seg_destroy(jpc_dec_seg_t *seg) { - if (seg->stream) { - jas_stream_close(seg->stream); - } - jas_free(seg); + if (seg->stream) { + jas_stream_close(seg->stream); + } + jas_free(seg); } static int jpc_dec_dump(jpc_dec_t *dec, FILE *out) { - jpc_dec_tile_t *tile; - int tileno; - jpc_dec_tcomp_t *tcomp; - uint_fast16_t compno; - jpc_dec_rlvl_t *rlvl; - int rlvlno; - jpc_dec_band_t *band; - int bandno; - jpc_dec_prc_t *prc; - int prcno; - jpc_dec_cblk_t *cblk; - int cblkno; - - for (tileno = 0, tile = dec->tiles; tileno < dec->numtiles; - ++tileno, ++tile) { - for (compno = 0, tcomp = tile->tcomps; compno < dec->numcomps; - ++compno, ++tcomp) { - for (rlvlno = 0, rlvl = tcomp->rlvls; rlvlno < - tcomp->numrlvls; ++rlvlno, ++rlvl) { -fprintf(out, "RESOLUTION LEVEL %d\n", rlvlno); -fprintf(out, "xs =%d, ys = %d, xe = %d, ye = %d, w = %d, h = %d\n", - rlvl->xstart, rlvl->ystart, rlvl->xend, rlvl->yend, rlvl->xend - - rlvl->xstart, rlvl->yend - rlvl->ystart); - for (bandno = 0, band = rlvl->bands; - bandno < rlvl->numbands; ++bandno, ++band) { -fprintf(out, "BAND %d\n", bandno); -fprintf(out, "xs =%d, ys = %d, xe = %d, ye = %d, w = %d, h = %d\n", - jas_seq2d_xstart(band->data), jas_seq2d_ystart(band->data), jas_seq2d_xend(band->data), - jas_seq2d_yend(band->data), jas_seq2d_xend(band->data) - jas_seq2d_xstart(band->data), - jas_seq2d_yend(band->data) - jas_seq2d_ystart(band->data)); - for (prcno = 0, prc = band->prcs; - prcno < rlvl->numprcs; ++prcno, - ++prc) { -fprintf(out, "CODE BLOCK GROUP %d\n", prcno); -fprintf(out, "xs =%d, ys = %d, xe = %d, ye = %d, w = %d, h = %d\n", - prc->xstart, prc->ystart, prc->xend, prc->yend, prc->xend - - prc->xstart, prc->yend - prc->ystart); - for (cblkno = 0, cblk = - prc->cblks; cblkno < - prc->numcblks; ++cblkno, - ++cblk) { -fprintf(out, "CODE BLOCK %d\n", cblkno); -fprintf(out, "xs =%d, ys = %d, xe = %d, ye = %d, w = %d, h = %d\n", - jas_seq2d_xstart(cblk->data), jas_seq2d_ystart(cblk->data), jas_seq2d_xend(cblk->data), - jas_seq2d_yend(cblk->data), jas_seq2d_xend(cblk->data) - jas_seq2d_xstart(cblk->data), - jas_seq2d_yend(cblk->data) - jas_seq2d_ystart(cblk->data)); - } - } - } - } - } - } - - return 0; + jpc_dec_tile_t *tile; + int tileno; + jpc_dec_tcomp_t *tcomp; + uint_fast16_t compno; + jpc_dec_rlvl_t *rlvl; + int rlvlno; + jpc_dec_band_t *band; + int bandno; + jpc_dec_prc_t *prc; + int prcno; + jpc_dec_cblk_t *cblk; + int cblkno; + + for (tileno = 0, tile = dec->tiles; tileno < dec->numtiles; + ++tileno, ++tile) { + for (compno = 0, tcomp = tile->tcomps; compno < dec->numcomps; + ++compno, ++tcomp) { + for (rlvlno = 0, rlvl = tcomp->rlvls; rlvlno < + tcomp->numrlvls; ++rlvlno, ++rlvl) { + fprintf(out, "RESOLUTION LEVEL %d\n", rlvlno); + fprintf(out, "xs =%d, ys = %d, xe = %d, ye = %d, " + "w = %d, h = %d\n", + (int)rlvl->xstart, (int)rlvl->ystart, + (int)rlvl->xend, (int)rlvl->yend, + (int)(rlvl->xend - rlvl->xstart), + (int)(rlvl->yend - rlvl->ystart)); + for (bandno = 0, band = rlvl->bands; + bandno < rlvl->numbands; ++bandno, ++band) { + fprintf(out, "BAND %d\n", bandno); + fprintf(out, "xs =%d, ys = %d, xe = %d, ye = %d, " + "w = %d, h = %d\n", + (int)jas_seq2d_xstart(band->data), + (int)jas_seq2d_ystart(band->data), + (int)jas_seq2d_xend(band->data), + (int)jas_seq2d_yend(band->data), + (int)(jas_seq2d_xend(band->data) - + jas_seq2d_xstart(band->data)), + (int)(jas_seq2d_yend(band->data) - + jas_seq2d_ystart(band->data))); + for (prcno = 0, prc = band->prcs; + prcno < rlvl->numprcs; + ++prcno, ++prc) { + fprintf(out, "CODE BLOCK GROUP %d\n", prcno); + fprintf(out, "xs =%d, ys = %d, xe = %d, ye = %d, " + "w = %d, h = %d\n", + (int)prc->xstart, (int)prc->ystart, + (int)prc->xend, (int)prc->yend, + (int)(prc->xend - prc->xstart), + (int)(prc->yend - prc->ystart)); + for (cblkno = 0, cblk = prc->cblks; + cblkno < prc->numcblks; + ++cblkno, ++cblk) { + fprintf(out, "CODE BLOCK %d\n", cblkno); + fprintf(out, "xs =%d, ys = %d, xe = %d, ye = %d, " + "w = %d, h = %d\n", + (int)jas_seq2d_xstart(cblk->data), + (int)jas_seq2d_ystart(cblk->data), + (int)jas_seq2d_xend(cblk->data), + (int)jas_seq2d_yend(cblk->data), + (int)(jas_seq2d_xend(cblk->data) - + jas_seq2d_xstart(cblk->data)), + (int)(jas_seq2d_yend(cblk->data) - + jas_seq2d_ystart(cblk->data))); + } + } + } + } + } + } + return 0; } jpc_streamlist_t *jpc_streamlist_create() { - jpc_streamlist_t *streamlist; - int i; - - if (!(streamlist = jas_malloc(sizeof(jpc_streamlist_t)))) { - return 0; - } - streamlist->numstreams = 0; - streamlist->maxstreams = 100; - if (!(streamlist->streams = jas_malloc(streamlist->maxstreams * - sizeof(jas_stream_t *)))) { - jas_free(streamlist); - return 0; - } - for (i = 0; i < streamlist->maxstreams; ++i) { - streamlist->streams[i] = 0; - } - return streamlist; + jpc_streamlist_t *streamlist; + int i; + + if (!(streamlist = jas_malloc(sizeof(jpc_streamlist_t)))) { + return 0; + } + streamlist->numstreams = 0; + streamlist->maxstreams = 100; + if (!(streamlist->streams = jas_malloc(streamlist->maxstreams * + sizeof(jas_stream_t *)))) { + jas_free(streamlist); + return 0; + } + for (i = 0; i < streamlist->maxstreams; ++i) { + streamlist->streams[i] = 0; + } + return streamlist; } int jpc_streamlist_insert(jpc_streamlist_t *streamlist, int streamno, jas_stream_t *stream) { - jas_stream_t **newstreams; - int newmaxstreams; - int i; - /* Grow the array of streams if necessary. */ - if (streamlist->numstreams >= streamlist->maxstreams) { - newmaxstreams = streamlist->maxstreams + 1024; - if (!(newstreams = jas_realloc(streamlist->streams, - (newmaxstreams + 1024) * sizeof(jas_stream_t *)))) { - return -1; - } - for (i = streamlist->numstreams; i < streamlist->maxstreams; ++i) { - streamlist->streams[i] = 0; - } - streamlist->maxstreams = newmaxstreams; - streamlist->streams = newstreams; - } - if (streamno != streamlist->numstreams) { - /* Can only handle insertion at start of list. */ - return -1; - } - streamlist->streams[streamno] = stream; - ++streamlist->numstreams; - return 0; + jas_stream_t **newstreams; + int newmaxstreams; + int i; + /* Grow the array of streams if necessary. */ + if (streamlist->numstreams >= streamlist->maxstreams) { + newmaxstreams = streamlist->maxstreams + 1024; + if (!(newstreams = jas_realloc(streamlist->streams, + (newmaxstreams + 1024) * sizeof(jas_stream_t *)))) { + return -1; + } + for (i = streamlist->numstreams; i < streamlist->maxstreams; ++i) { + streamlist->streams[i] = 0; + } + streamlist->maxstreams = newmaxstreams; + streamlist->streams = newstreams; + } + if (streamno != streamlist->numstreams) { + /* Can only handle insertion at start of list. */ + return -1; + } + streamlist->streams[streamno] = stream; + ++streamlist->numstreams; + return 0; } jas_stream_t *jpc_streamlist_remove(jpc_streamlist_t *streamlist, int streamno) { - jas_stream_t *stream; - int i; - if (streamno >= streamlist->numstreams) { - abort(); - } - stream = streamlist->streams[streamno]; - for (i = streamno + 1; i < streamlist->numstreams; ++i) { - streamlist->streams[i - 1] = streamlist->streams[i]; - } - --streamlist->numstreams; - return stream; + jas_stream_t *stream; + int i; + if (streamno >= streamlist->numstreams) { + abort(); + } + stream = streamlist->streams[streamno]; + for (i = streamno + 1; i < streamlist->numstreams; ++i) { + streamlist->streams[i - 1] = streamlist->streams[i]; + } + --streamlist->numstreams; + return stream; } void jpc_streamlist_destroy(jpc_streamlist_t *streamlist) { - int streamno; - if (streamlist->streams) { - for (streamno = 0; streamno < streamlist->numstreams; - ++streamno) { - jas_stream_close(streamlist->streams[streamno]); - } - jas_free(streamlist->streams); - } - jas_free(streamlist); + int streamno; + if (streamlist->streams) { + for (streamno = 0; streamno < streamlist->numstreams; + ++streamno) { + jas_stream_close(streamlist->streams[streamno]); + } + jas_free(streamlist->streams); + } + jas_free(streamlist); } jas_stream_t *jpc_streamlist_get(jpc_streamlist_t *streamlist, int streamno) { - assert(streamno < streamlist->numstreams); - return streamlist->streams[streamno]; + assert(streamno < streamlist->numstreams); + return streamlist->streams[streamno]; } int jpc_streamlist_numstreams(jpc_streamlist_t *streamlist) { - return streamlist->numstreams; + return streamlist->numstreams; } jpc_ppxstab_t *jpc_ppxstab_create() { - jpc_ppxstab_t *tab; + jpc_ppxstab_t *tab; - if (!(tab = jas_malloc(sizeof(jpc_ppxstab_t)))) { - return 0; - } - tab->numents = 0; - tab->maxents = 0; - tab->ents = 0; - return tab; + if (!(tab = jas_malloc(sizeof(jpc_ppxstab_t)))) { + return 0; + } + tab->numents = 0; + tab->maxents = 0; + tab->ents = 0; + return tab; } void jpc_ppxstab_destroy(jpc_ppxstab_t *tab) { - int i; - for (i = 0; i < tab->numents; ++i) { - jpc_ppxstabent_destroy(tab->ents[i]); - } - if (tab->ents) { - jas_free(tab->ents); - } - jas_free(tab); + int i; + for (i = 0; i < tab->numents; ++i) { + jpc_ppxstabent_destroy(tab->ents[i]); + } + if (tab->ents) { + jas_free(tab->ents); + } + jas_free(tab); } int jpc_ppxstab_grow(jpc_ppxstab_t *tab, int maxents) { - jpc_ppxstabent_t **newents; - if (tab->maxents < maxents) { - newents = (tab->ents) ? jas_realloc(tab->ents, maxents * - sizeof(jpc_ppxstabent_t *)) : jas_malloc(maxents * sizeof(jpc_ppxstabent_t *)); - if (!newents) { - return -1; - } - tab->ents = newents; - tab->maxents = maxents; - } - return 0; + jpc_ppxstabent_t **newents; + if (tab->maxents < maxents) { + newents = (tab->ents) ? jas_realloc(tab->ents, maxents * + sizeof(jpc_ppxstabent_t *)) : jas_malloc(maxents * sizeof(jpc_ppxstabent_t *)); + if (!newents) { + return -1; + } + tab->ents = newents; + tab->maxents = maxents; + } + return 0; } int jpc_ppxstab_insert(jpc_ppxstab_t *tab, jpc_ppxstabent_t *ent) { - int inspt; - int i; + int inspt; + int i; - for (i = 0; i < tab->numents; ++i) { - if (tab->ents[i]->ind > ent->ind) { - break; - } - } - inspt = i; + for (i = 0; i < tab->numents; ++i) { + if (tab->ents[i]->ind > ent->ind) { + break; + } + } + inspt = i; - if (tab->numents >= tab->maxents) { - if (jpc_ppxstab_grow(tab, tab->maxents + 128)) { - return -1; - } - } + if (tab->numents >= tab->maxents) { + if (jpc_ppxstab_grow(tab, tab->maxents + 128)) { + return -1; + } + } - for (i = tab->numents; i > inspt; --i) { - tab->ents[i] = tab->ents[i - 1]; - } - tab->ents[i] = ent; - ++tab->numents; + for (i = tab->numents; i > inspt; --i) { + tab->ents[i] = tab->ents[i - 1]; + } + tab->ents[i] = ent; + ++tab->numents; - return 0; + return 0; } jpc_streamlist_t *jpc_ppmstabtostreams(jpc_ppxstab_t *tab) { - jpc_streamlist_t *streams; - unsigned char *dataptr; - uint_fast32_t datacnt; - uint_fast32_t tpcnt; - jpc_ppxstabent_t *ent; - int entno; - jas_stream_t *stream; - int n; - - if (!(streams = jpc_streamlist_create())) { - goto error; - } - - if (!tab->numents) { - return streams; - } - - entno = 0; - ent = tab->ents[entno]; - dataptr = ent->data; - datacnt = ent->len; - for (;;) { - - /* Get the length of the packet header data for the current - tile-part. */ - if (datacnt < 4) { - goto error; - } - if (!(stream = jas_stream_memopen(0, 0))) { - goto error; - } - if (jpc_streamlist_insert(streams, jpc_streamlist_numstreams(streams), - stream)) { - goto error; - } - tpcnt = (dataptr[0] << 24) | (dataptr[1] << 16) | (dataptr[2] << 8) - | dataptr[3]; - datacnt -= 4; - dataptr += 4; - - /* Get the packet header data for the current tile-part. */ - while (tpcnt) { - if (!datacnt) { - if (++entno >= tab->numents) { - goto error; - } - ent = tab->ents[entno]; - dataptr = ent->data; - datacnt = ent->len; - } - n = JAS_MIN(tpcnt, datacnt); - if (jas_stream_write(stream, dataptr, n) != n) { - goto error; - } - tpcnt -= n; - dataptr += n; - datacnt -= n; - } - jas_stream_rewind(stream); - if (!datacnt) { - if (++entno >= tab->numents) { - break; - } - ent = tab->ents[entno]; - dataptr = ent->data; - datacnt = ent->len; - } - } - - return streams; + jpc_streamlist_t *streams; + unsigned char *dataptr; + uint_fast32_t datacnt; + uint_fast32_t tpcnt; + jpc_ppxstabent_t *ent; + int entno; + jas_stream_t *stream; + int n; + + if (!(streams = jpc_streamlist_create())) { + goto error; + } + + if (!tab->numents) { + return streams; + } + + entno = 0; + ent = tab->ents[entno]; + dataptr = ent->data; + datacnt = ent->len; + for (;;) { + + /* Get the length of the packet header data for the current + tile-part. */ + if (datacnt < 4) { + goto error; + } + if (!(stream = jas_stream_memopen(0, 0))) { + goto error; + } + if (jpc_streamlist_insert(streams, jpc_streamlist_numstreams(streams), + stream)) { + goto error; + } + tpcnt = (dataptr[0] << 24) | (dataptr[1] << 16) | (dataptr[2] << 8) + | dataptr[3]; + datacnt -= 4; + dataptr += 4; + + /* Get the packet header data for the current tile-part. */ + while (tpcnt) { + if (!datacnt) { + if (++entno >= tab->numents) { + goto error; + } + ent = tab->ents[entno]; + dataptr = ent->data; + datacnt = ent->len; + } + n = JAS_MIN(tpcnt, datacnt); + if (jas_stream_write(stream, dataptr, n) != n) { + goto error; + } + tpcnt -= n; + dataptr += n; + datacnt -= n; + } + jas_stream_rewind(stream); + if (!datacnt) { + if (++entno >= tab->numents) { + break; + } + ent = tab->ents[entno]; + dataptr = ent->data; + datacnt = ent->len; + } + } + + return streams; error: - jpc_streamlist_destroy(streams); - return 0; + jpc_streamlist_destroy(streams); + return 0; } int jpc_pptstabwrite(jas_stream_t *out, jpc_ppxstab_t *tab) { - int i; - jpc_ppxstabent_t *ent; - for (i = 0; i < tab->numents; ++i) { - ent = tab->ents[i]; - if (jas_stream_write(out, ent->data, ent->len) != ent->len) { - return -1; - } - } - return 0; + int i; + jpc_ppxstabent_t *ent; + for (i = 0; i < tab->numents; ++i) { + ent = tab->ents[i]; + if (jas_stream_write(out, ent->data, ent->len) != ent->len) { + return -1; + } + } + return 0; } jpc_ppxstabent_t *jpc_ppxstabent_create() { - jpc_ppxstabent_t *ent; - if (!(ent = jas_malloc(sizeof(jpc_ppxstabent_t)))) { - return 0; - } - ent->data = 0; - ent->len = 0; - ent->ind = 0; - return ent; + jpc_ppxstabent_t *ent; + if (!(ent = jas_malloc(sizeof(jpc_ppxstabent_t)))) { + return 0; + } + ent->data = 0; + ent->len = 0; + ent->ind = 0; + return ent; } void jpc_ppxstabent_destroy(jpc_ppxstabent_t *ent) { - if (ent->data) { - jas_free(ent->data); - } - jas_free(ent); + if (ent->data) { + jas_free(ent->data); + } + jas_free(ent); } diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_dec.h b/converter/other/jpeg2000/libjasper/jpc/jpc_dec.h index 5231048d..02c5553d 100644 --- a/converter/other/jpeg2000/libjasper/jpc/jpc_dec.h +++ b/converter/other/jpeg2000/libjasper/jpc/jpc_dec.h @@ -175,7 +175,7 @@ typedef struct { /* The number of streams in this list. */ int numstreams; - /* The maximum number of streams that can be accomodated without + /* The maximum number of streams that can be accommodated without growing the streams array. */ int maxstreams; diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_enc.c b/converter/other/jpeg2000/libjasper/jpc/jpc_enc.c index 3284dfeb..d17e9aa3 100644 --- a/converter/other/jpeg2000/libjasper/jpc/jpc_enc.c +++ b/converter/other/jpeg2000/libjasper/jpc/jpc_enc.c @@ -1,129 +1,13 @@ -/* - * Copyright (c) 1999-2000 Image Power, Inc. and the University of - * British Columbia. - * Copyright (c) 2001-2002 Michael David Adams. - * All rights reserved. - */ - -/* __START_OF_JASPER_LICENSE__ - * - * JasPer Software License - * - * IMAGE POWER JPEG-2000 PUBLIC LICENSE - * ************************************ - * - * GRANT: - * - * Permission is hereby granted, free of charge, to any person (the "User") - * obtaining a copy of this software and associated documentation, to deal - * in the JasPer Software without restriction, including without limitation - * the right to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the JasPer Software (in source and binary forms), - * and to permit persons to whom the JasPer Software is furnished to do so, - * provided further that the License Conditions below are met. - * - * License Conditions - * ****************** - * - * A. Redistributions of source code must retain the above copyright notice, - * and this list of conditions, and the following disclaimer. - * - * B. Redistributions in binary form must reproduce the above copyright - * notice, and this list of conditions, and the following disclaimer in - * the documentation and/or other materials provided with the distribution. - * - * C. Neither the name of Image Power, Inc. nor any other contributor - * (including, but not limited to, the University of British Columbia and - * Michael David Adams) may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * D. User agrees that it shall not commence any action against Image Power, - * Inc., the University of British Columbia, Michael David Adams, or any - * other contributors (collectively "Licensors") for infringement of any - * intellectual property rights ("IPR") held by the User in respect of any - * technology that User owns or has a right to license or sublicense and - * which is an element required in order to claim compliance with ISO/IEC - * 15444-1 (i.e., JPEG-2000 Part 1). "IPR" means all intellectual property - * rights worldwide arising under statutory or common law, and whether - * or not perfected, including, without limitation, all (i) patents and - * patent applications owned or licensable by User; (ii) rights associated - * with works of authorship including copyrights, copyright applications, - * copyright registrations, mask work rights, mask work applications, - * mask work registrations; (iii) rights relating to the protection of - * trade secrets and confidential information; (iv) any right analogous - * to those set forth in subsections (i), (ii), or (iii) and any other - * proprietary rights relating to intangible property (other than trademark, - * trade dress, or service mark rights); and (v) divisions, continuations, - * renewals, reissues and extensions of the foregoing (as and to the extent - * applicable) now existing, hereafter filed, issued or acquired. - * - * E. If User commences an infringement action against any Licensor(s) then - * such Licensor(s) shall have the right to terminate User's license and - * all sublicenses that have been granted hereunder by User to other parties. - * - * F. This software is for use only in hardware or software products that - * are compliant with ISO/IEC 15444-1 (i.e., JPEG-2000 Part 1). No license - * or right to this Software is granted for products that do not comply - * with ISO/IEC 15444-1. The JPEG-2000 Part 1 standard can be purchased - * from the ISO. - * - * THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. - * NO USE OF THE JASPER SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER - * THIS DISCLAIMER. THE JASPER SOFTWARE IS PROVIDED BY THE LICENSORS AND - * CONTRIBUTORS UNDER THIS LICENSE ON AN ``AS-IS'' BASIS, WITHOUT WARRANTY - * OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, - * WARRANTIES THAT THE JASPER SOFTWARE IS FREE OF DEFECTS, IS MERCHANTABLE, - * IS FIT FOR A PARTICULAR PURPOSE OR IS NON-INFRINGING. THOSE INTENDING - * TO USE THE JASPER SOFTWARE OR MODIFICATIONS THEREOF FOR USE IN HARDWARE - * OR SOFTWARE PRODUCTS ARE ADVISED THAT THEIR USE MAY INFRINGE EXISTING - * PATENTS, COPYRIGHTS, TRADEMARKS, OR OTHER INTELLECTUAL PROPERTY RIGHTS. - * THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE JASPER SOFTWARE - * IS WITH THE USER. SHOULD ANY PART OF THE JASPER SOFTWARE PROVE DEFECTIVE - * IN ANY RESPECT, THE USER (AND NOT THE INITIAL DEVELOPERS, THE UNIVERSITY - * OF BRITISH COLUMBIA, IMAGE POWER, INC., MICHAEL DAVID ADAMS, OR ANY - * OTHER CONTRIBUTOR) SHALL ASSUME THE COST OF ANY NECESSARY SERVICING, - * REPAIR OR CORRECTION. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, - * WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL THE - * INITIAL DEVELOPER, THE UNIVERSITY OF BRITISH COLUMBIA, IMAGE POWER, INC., - * MICHAEL DAVID ADAMS, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF THE - * JASPER SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO - * THE USER OR ANY OTHER PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR - * CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, - * DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR - * MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF - * SUCH PARTY HAD BEEN INFORMED, OR OUGHT TO HAVE KNOWN, OF THE POSSIBILITY - * OF SUCH DAMAGES. THE JASPER SOFTWARE AND UNDERLYING TECHNOLOGY ARE NOT - * FAULT-TOLERANT AND ARE NOT DESIGNED, MANUFACTURED OR INTENDED FOR USE OR - * RESALE AS ON-LINE CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING - * FAIL-SAFE PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, - * AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT - * LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE - * JASPER SOFTWARE OR UNDERLYING TECHNOLOGY OR PRODUCT COULD LEAD DIRECTLY - * TO DEATH, PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE - * ("HIGH RISK ACTIVITIES"). LICENSOR SPECIFICALLY DISCLAIMS ANY EXPRESS - * OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES. USER WILL NOT - * KNOWINGLY USE, DISTRIBUTE OR RESELL THE JASPER SOFTWARE OR UNDERLYING - * TECHNOLOGY OR PRODUCTS FOR HIGH RISK ACTIVITIES AND WILL ENSURE THAT ITS - * CUSTOMERS AND END-USERS OF ITS PRODUCTS ARE PROVIDED WITH A COPY OF THE - * NOTICE SPECIFIED IN THIS SECTION. - * - * __END_OF_JASPER_LICENSE__ - */ - -/* - * $Id$ - */ - -/******************************************************************************\ -* Includes. -\******************************************************************************/ - +#include #include #include #include #include #include +#include "netpbm/pm.h" +#include "netpbm/nstring.h" + #include "jasper/jas_string.h" #include "jasper/jas_malloc.h" #include "jasper/jas_image.h" @@ -147,24 +31,24 @@ #include "jpc_math.h" #include "jpc_util.h" -/******************************************************************************\ +/*****************************************************************************\ * -\******************************************************************************/ +\*****************************************************************************/ #define JPC_POW2(n) \ - (1 << (n)) + (1 << (n)) #define JPC_FLOORTOMULTPOW2(x, n) \ (((n) > 0) ? ((x) & (~((1 << n) - 1))) : (x)) /* Round to the nearest multiple of the specified power of two in the direction of negative infinity. */ -#define JPC_CEILTOMULTPOW2(x, n) \ +#define JPC_CEILTOMULTPOW2(x, n) \ (((n) > 0) ? JPC_FLOORTOMULTPOW2(((x) + (1 << (n)) - 1), n) : (x)) /* Round to the nearest multiple of the specified power of two in the direction of positive infinity. */ -#define JPC_POW2(n) \ +#define JPC_POW2(n) \ (1 << (n)) jpc_enc_tile_t *jpc_enc_tile_create(jpc_enc_cp_t *cp, jas_image_t *image, int tileno); @@ -202,180 +86,205 @@ void jpc_enc_destroy(jpc_enc_t *enc); static int jpc_enc_encodemainhdr(jpc_enc_t *enc); static int jpc_enc_encodemainbody(jpc_enc_t *enc); int jpc_enc_encodetiledata(jpc_enc_t *enc); -int rateallocate(jpc_enc_t *enc, int numlyrs, uint_fast32_t *cumlens); int setins(int numvalues, jpc_flt_t *values, jpc_flt_t value); static jpc_enc_cp_t *cp_create(char *optstr, jas_image_t *image); void jpc_enc_cp_destroy(jpc_enc_cp_t *cp); static uint_fast32_t jpc_abstorelstepsize(jpc_fix_t absdelta, int scaleexpn) { - int p; - uint_fast32_t mant; - uint_fast32_t expn; - int n; - - if (absdelta < 0) { - abort(); - } - - p = jpc_firstone(absdelta) - JPC_FIX_FRACBITS; - n = 11 - jpc_firstone(absdelta); - mant = ((n < 0) ? (absdelta >> (-n)) : (absdelta << n)) & 0x7ff; - expn = scaleexpn - p; - if (scaleexpn < p) { - abort(); - } - return JPC_QCX_EXPN(expn) | JPC_QCX_MANT(mant); + int p; + uint_fast32_t mant; + uint_fast32_t expn; + int n; + + if (absdelta < 0) { + abort(); + } + + p = jpc_firstone(absdelta) - JPC_FIX_FRACBITS; + n = 11 - jpc_firstone(absdelta); + mant = ((n < 0) ? (absdelta >> (-n)) : (absdelta << n)) & 0x7ff; + expn = scaleexpn - p; + if (scaleexpn < p) { + abort(); + } + return JPC_QCX_EXPN(expn) | JPC_QCX_MANT(mant); } typedef enum { - OPT_DEBUG, - OPT_IMGAREAOFFX, - OPT_IMGAREAOFFY, - OPT_TILEGRDOFFX, - OPT_TILEGRDOFFY, - OPT_TILEWIDTH, - OPT_TILEHEIGHT, - OPT_PRCWIDTH, - OPT_PRCHEIGHT, - OPT_CBLKWIDTH, - OPT_CBLKHEIGHT, - OPT_MODE, - OPT_PRG, - OPT_NOMCT, - OPT_MAXRLVLS, - OPT_SOP, - OPT_EPH, - OPT_LAZY, - OPT_TERMALL, - OPT_SEGSYM, - OPT_VCAUSAL, - OPT_RESET, - OPT_PTERM, - OPT_NUMGBITS, - OPT_RATE, - OPT_ILYRRATES, - OPT_JP2OVERHEAD + OPT_DEBUG, + OPT_IMGAREAOFFX, + OPT_IMGAREAOFFY, + OPT_TILEGRDOFFX, + OPT_TILEGRDOFFY, + OPT_TILEWIDTH, + OPT_TILEHEIGHT, + OPT_PRCWIDTH, + OPT_PRCHEIGHT, + OPT_CBLKWIDTH, + OPT_CBLKHEIGHT, + OPT_MODE, + OPT_PRG, + OPT_NOMCT, + OPT_MAXRLVLS, + OPT_SOP, + OPT_EPH, + OPT_LAZY, + OPT_TERMALL, + OPT_SEGSYM, + OPT_VCAUSAL, + OPT_RESET, + OPT_PTERM, + OPT_NUMGBITS, + OPT_RATE, + OPT_ILYRRATES, + OPT_JP2OVERHEAD } optid_t; jas_taginfo_t encopts[] = { - {OPT_DEBUG, "debug"}, - {OPT_IMGAREAOFFX, "imgareatlx"}, - {OPT_IMGAREAOFFY, "imgareatly"}, - {OPT_TILEGRDOFFX, "tilegrdtlx"}, - {OPT_TILEGRDOFFY, "tilegrdtly"}, - {OPT_TILEWIDTH, "tilewidth"}, - {OPT_TILEHEIGHT, "tileheight"}, - {OPT_PRCWIDTH, "prcwidth"}, - {OPT_PRCHEIGHT, "prcheight"}, - {OPT_CBLKWIDTH, "cblkwidth"}, - {OPT_CBLKHEIGHT, "cblkheight"}, - {OPT_MODE, "mode"}, - {OPT_PRG, "prg"}, - {OPT_NOMCT, "nomct"}, - {OPT_MAXRLVLS, "numrlvls"}, - {OPT_SOP, "sop"}, - {OPT_EPH, "eph"}, - {OPT_LAZY, "lazy"}, - {OPT_TERMALL, "termall"}, - {OPT_SEGSYM, "segsym"}, - {OPT_VCAUSAL, "vcausal"}, - {OPT_PTERM, "pterm"}, - {OPT_RESET, "resetprob"}, - {OPT_NUMGBITS, "numgbits"}, - {OPT_RATE, "rate"}, - {OPT_ILYRRATES, "ilyrrates"}, - {OPT_JP2OVERHEAD, "_jp2overhead"}, - {-1, 0} + {OPT_DEBUG, "debug"}, + {OPT_IMGAREAOFFX, "imgareatlx"}, + {OPT_IMGAREAOFFY, "imgareatly"}, + {OPT_TILEGRDOFFX, "tilegrdtlx"}, + {OPT_TILEGRDOFFY, "tilegrdtly"}, + {OPT_TILEWIDTH, "tilewidth"}, + {OPT_TILEHEIGHT, "tileheight"}, + {OPT_PRCWIDTH, "prcwidth"}, + {OPT_PRCHEIGHT, "prcheight"}, + {OPT_CBLKWIDTH, "cblkwidth"}, + {OPT_CBLKHEIGHT, "cblkheight"}, + {OPT_MODE, "mode"}, + {OPT_PRG, "prg"}, + {OPT_NOMCT, "nomct"}, + {OPT_MAXRLVLS, "numrlvls"}, + {OPT_SOP, "sop"}, + {OPT_EPH, "eph"}, + {OPT_LAZY, "lazy"}, + {OPT_TERMALL, "termall"}, + {OPT_SEGSYM, "segsym"}, + {OPT_VCAUSAL, "vcausal"}, + {OPT_PTERM, "pterm"}, + {OPT_RESET, "resetprob"}, + {OPT_NUMGBITS, "numgbits"}, + {OPT_RATE, "rate"}, + {OPT_ILYRRATES, "ilyrrates"}, + {OPT_JP2OVERHEAD, "_jp2overhead"}, + {-1, 0} }; typedef enum { - PO_L = 0, - PO_R + PO_L = 0, + PO_R } poid_t; jas_taginfo_t prgordtab[] = { - {JPC_COD_LRCPPRG, "lrcp"}, - {JPC_COD_RLCPPRG, "rlcp"}, - {JPC_COD_RPCLPRG, "rpcl"}, - {JPC_COD_PCRLPRG, "pcrl"}, - {JPC_COD_CPRLPRG, "cprl"}, - {-1, 0} + {JPC_COD_LRCPPRG, "lrcp"}, + {JPC_COD_RLCPPRG, "rlcp"}, + {JPC_COD_RPCLPRG, "rpcl"}, + {JPC_COD_PCRLPRG, "pcrl"}, + {JPC_COD_CPRLPRG, "cprl"}, + {-1, 0} }; typedef enum { - MODE_INT, - MODE_REAL + MODE_INT, + MODE_REAL } modeid_t; jas_taginfo_t modetab[] = { - {MODE_INT, "int"}, - {MODE_REAL, "real"}, - {-1, 0} + {MODE_INT, "int"}, + {MODE_REAL, "real"}, + {-1, 0} }; + +static void +tracev(const char * const fmt, + va_list args) { + + vfprintf(stderr, fmt, args); + + fprintf(stderr, "\n"); +} + + + +static void +trace(const char * const fmt, ...) { + + if (jas_getdbglevel() > 0) { + va_list args; + + va_start(args, fmt); + tracev(fmt, args); + va_end(args); + } +} + + + /******************************************************************************\ * The main encoder entry point. \******************************************************************************/ int jpc_encode(jas_image_t *image, jas_stream_t *out, char *optstr) { - jpc_enc_t *enc; - jpc_enc_cp_t *cp; + jpc_enc_t *enc; + jpc_enc_cp_t *cp; - enc = 0; - cp = 0; + enc = 0; + cp = 0; - jpc_initluts(); + jpc_initluts(); - if (!(cp = cp_create(optstr, image))) { - fprintf(stderr, "invalid JP encoder options\n"); - goto error; - } + if (!(cp = cp_create(optstr, image))) { + fprintf(stderr, "invalid JP encoder options\n"); + goto error; + } - if (!(enc = jpc_enc_create(cp, out, image))) { - goto error; - } - cp = 0; + if (!(enc = jpc_enc_create(cp, out, image))) { + goto error; + } + cp = 0; - /* Encode the main header. */ - if (jpc_enc_encodemainhdr(enc)) { - goto error; - } + /* Encode the main header. */ + if (jpc_enc_encodemainhdr(enc)) { + goto error; + } - /* Encode the main body. This constitutes most of the encoding work. */ - if (jpc_enc_encodemainbody(enc)) { - goto error; - } + /* Encode the main body. This constitutes most of the encoding work. */ + if (jpc_enc_encodemainbody(enc)) { + goto error; + } - /* Write EOC marker segment. */ - if (!(enc->mrk = jpc_ms_create(JPC_MS_EOC))) { - goto error; - } - if (jpc_putms(enc->out, enc->cstate, enc->mrk)) { - fprintf(stderr, "cannot write EOI marker\n"); - goto error; - } - jpc_ms_destroy(enc->mrk); - enc->mrk = 0; + /* Write EOC marker segment. */ + if (!(enc->mrk = jpc_ms_create(JPC_MS_EOC))) { + goto error; + } + if (jpc_putms(enc->out, enc->cstate, enc->mrk)) { + fprintf(stderr, "cannot write EOI marker\n"); + goto error; + } + jpc_ms_destroy(enc->mrk); + enc->mrk = 0; - if (jas_stream_flush(enc->out)) { - goto error; - } + if (jas_stream_flush(enc->out)) { + goto error; + } - jpc_enc_destroy(enc); + jpc_enc_destroy(enc); - return 0; + return 0; error: - if (cp) { - jpc_enc_cp_destroy(cp); - } - if (enc) { - jpc_enc_destroy(enc); - } - return -1; + if (cp) { + jpc_enc_cp_destroy(cp); + } + if (enc) { + jpc_enc_destroy(enc); + } + return -1; } /******************************************************************************\ @@ -384,466 +293,461 @@ error: static jpc_enc_cp_t *cp_create(char *optstr, jas_image_t *image) { - jpc_enc_cp_t *cp; - jas_tvparser_t *tvp; - int ret; - int numilyrrates; - double *ilyrrates; - int i; - int tagid; - jpc_enc_tcp_t *tcp; - jpc_enc_tccp_t *tccp; - jpc_enc_ccp_t *ccp; - uint_fast16_t cmptno; - uint_fast16_t rlvlno; - uint_fast16_t prcwidthexpn; - uint_fast16_t prcheightexpn; - bool enablemct; - uint_fast32_t jp2overhead; - uint_fast16_t lyrno; - uint_fast32_t hsteplcm; - uint_fast32_t vsteplcm; - bool mctvalid; - - tvp = 0; - cp = 0; - ilyrrates = 0; - numilyrrates = 0; - - if (!(cp = jas_malloc(sizeof(jpc_enc_cp_t)))) { - goto error; - } - - prcwidthexpn = 15; - prcheightexpn = 15; - enablemct = true; - jp2overhead = 0; - - cp->ccps = 0; - cp->debug = 0; - cp->imgareatlx = UINT_FAST32_MAX; - cp->imgareatly = UINT_FAST32_MAX; - cp->refgrdwidth = 0; - cp->refgrdheight = 0; - cp->tilegrdoffx = UINT_FAST32_MAX; - cp->tilegrdoffy = UINT_FAST32_MAX; - cp->tilewidth = 0; - cp->tileheight = 0; - cp->numcmpts = jas_image_numcmpts(image); - - hsteplcm = 1; - vsteplcm = 1; - for (cmptno = 0; cmptno < jas_image_numcmpts(image); ++cmptno) { - if (jas_image_cmptbrx(image, cmptno) + jas_image_cmpthstep(image, cmptno) <= - jas_image_brx(image) || jas_image_cmptbry(image, cmptno) + - jas_image_cmptvstep(image, cmptno) <= jas_image_bry(image)) { - fprintf(stderr, "unsupported image type\n"); - goto error; - } - /* Note: We ought to be calculating the LCMs here. Fix some day. */ - hsteplcm *= jas_image_cmpthstep(image, cmptno); - vsteplcm *= jas_image_cmptvstep(image, cmptno); - } - - if (!(cp->ccps = jas_malloc(cp->numcmpts * sizeof(jpc_enc_ccp_t)))) { - goto error; - } - for (cmptno = 0, ccp = cp->ccps; cmptno < cp->numcmpts; ++cmptno, - ++ccp) { - ccp->sampgrdstepx = jas_image_cmpthstep(image, cmptno); - ccp->sampgrdstepy = jas_image_cmptvstep(image, cmptno); - /* XXX - this isn't quite correct for more general image */ - ccp->sampgrdsubstepx = 0; - ccp->sampgrdsubstepx = 0; - ccp->prec = jas_image_cmptprec(image, cmptno); - ccp->sgnd = jas_image_cmptsgnd(image, cmptno); - ccp->numstepsizes = 0; - memset(ccp->stepsizes, 0, sizeof(ccp->stepsizes)); - } - - cp->rawsize = jas_image_rawsize(image); - cp->totalsize = UINT_FAST32_MAX; - - tcp = &cp->tcp; - tcp->csty = 0; - tcp->intmode = true; - tcp->prg = JPC_COD_LRCPPRG; - tcp->numlyrs = 1; - tcp->ilyrrates = 0; - - tccp = &cp->tccp; - tccp->csty = 0; - tccp->maxrlvls = 6; - tccp->cblkwidthexpn = 6; - tccp->cblkheightexpn = 6; - tccp->cblksty = 0; - tccp->numgbits = 2; - - if (!(tvp = jas_tvparser_create(optstr ? optstr : ""))) { - goto error; - } - - while (!(ret = jas_tvparser_next(tvp))) { - switch (jas_taginfo_nonull(jas_taginfos_lookup(encopts, - jas_tvparser_gettag(tvp)))->id) { - case OPT_DEBUG: - cp->debug = atoi(jas_tvparser_getval(tvp)); - break; - case OPT_IMGAREAOFFX: - cp->imgareatlx = atoi(jas_tvparser_getval(tvp)); - break; - case OPT_IMGAREAOFFY: - cp->imgareatly = atoi(jas_tvparser_getval(tvp)); - break; - case OPT_TILEGRDOFFX: - cp->tilegrdoffx = atoi(jas_tvparser_getval(tvp)); - break; - case OPT_TILEGRDOFFY: - cp->tilegrdoffy = atoi(jas_tvparser_getval(tvp)); - break; - case OPT_TILEWIDTH: - cp->tilewidth = atoi(jas_tvparser_getval(tvp)); - break; - case OPT_TILEHEIGHT: - cp->tileheight = atoi(jas_tvparser_getval(tvp)); - break; - case OPT_PRCWIDTH: - prcwidthexpn = jpc_floorlog2(atoi(jas_tvparser_getval(tvp))); - break; - case OPT_PRCHEIGHT: - prcheightexpn = jpc_floorlog2(atoi(jas_tvparser_getval(tvp))); - break; - case OPT_CBLKWIDTH: - tccp->cblkwidthexpn = - jpc_floorlog2(atoi(jas_tvparser_getval(tvp))); - break; - case OPT_CBLKHEIGHT: - tccp->cblkheightexpn = - jpc_floorlog2(atoi(jas_tvparser_getval(tvp))); - break; - case OPT_MODE: - if ((tagid = jas_taginfo_nonull(jas_taginfos_lookup(modetab, - jas_tvparser_getval(tvp)))->id) < 0) { - fprintf(stderr, - "ignoring invalid mode %s\n", - jas_tvparser_getval(tvp)); - } else { - tcp->intmode = (tagid == MODE_INT); - } - break; - case OPT_PRG: - if ((tagid = jas_taginfo_nonull(jas_taginfos_lookup(prgordtab, - jas_tvparser_getval(tvp)))->id) < 0) { - fprintf(stderr, - "ignoring invalid progression order %s\n", - jas_tvparser_getval(tvp)); - } else { - tcp->prg = tagid; - } - break; - case OPT_NOMCT: - enablemct = false; - break; - case OPT_MAXRLVLS: - tccp->maxrlvls = atoi(jas_tvparser_getval(tvp)); - break; - case OPT_SOP: - cp->tcp.csty |= JPC_COD_SOP; - break; - case OPT_EPH: - cp->tcp.csty |= JPC_COD_EPH; - break; - case OPT_LAZY: - tccp->cblksty |= JPC_COX_LAZY; - break; - case OPT_TERMALL: - tccp->cblksty |= JPC_COX_TERMALL; - break; - case OPT_SEGSYM: - tccp->cblksty |= JPC_COX_SEGSYM; - break; - case OPT_VCAUSAL: - tccp->cblksty |= JPC_COX_VSC; - break; - case OPT_RESET: - tccp->cblksty |= JPC_COX_RESET; - break; - case OPT_PTERM: - tccp->cblksty |= JPC_COX_PTERM; - break; - case OPT_NUMGBITS: - cp->tccp.numgbits = atoi(jas_tvparser_getval(tvp)); - break; - case OPT_RATE: - if (ratestrtosize(jas_tvparser_getval(tvp), cp->rawsize, - &cp->totalsize)) { - fprintf(stderr, - "ignoring bad rate specifier %s\n", - jas_tvparser_getval(tvp)); - } - break; - case OPT_ILYRRATES: - if (jpc_atoaf(jas_tvparser_getval(tvp), &numilyrrates, - &ilyrrates)) { - fprintf(stderr, - "warning: invalid intermediate layer rates specifier ignored (%s)\n", - jas_tvparser_getval(tvp)); - } - break; - - case OPT_JP2OVERHEAD: - jp2overhead = atoi(jas_tvparser_getval(tvp)); - break; - default: - fprintf(stderr, "warning: ignoring invalid option %s\n", - jas_tvparser_gettag(tvp)); - break; - } - } - - jas_tvparser_destroy(tvp); - tvp = 0; - - if (cp->totalsize != UINT_FAST32_MAX) { - cp->totalsize = (cp->totalsize > jp2overhead) ? - (cp->totalsize - jp2overhead) : 0; - } - - if (cp->imgareatlx == UINT_FAST32_MAX) { - cp->imgareatlx = 0; - } else { - if (hsteplcm != 1) { - fprintf(stderr, "warning: overriding imgareatlx value\n"); - } - cp->imgareatlx *= hsteplcm; - } - if (cp->imgareatly == UINT_FAST32_MAX) { - cp->imgareatly = 0; - } else { - if (vsteplcm != 1) { - fprintf(stderr, "warning: overriding imgareatly value\n"); - } - cp->imgareatly *= vsteplcm; - } - cp->refgrdwidth = cp->imgareatlx + jas_image_width(image); - cp->refgrdheight = cp->imgareatly + jas_image_height(image); - if (cp->tilegrdoffx == UINT_FAST32_MAX) { - cp->tilegrdoffx = cp->imgareatlx; - } - if (cp->tilegrdoffy == UINT_FAST32_MAX) { - cp->tilegrdoffy = cp->imgareatly; - } - if (!cp->tilewidth) { - cp->tilewidth = cp->refgrdwidth - cp->tilegrdoffx; - } - if (!cp->tileheight) { - cp->tileheight = cp->refgrdheight - cp->tilegrdoffy; - } - - if (cp->numcmpts == 3) { - mctvalid = true; - for (cmptno = 0; cmptno < jas_image_numcmpts(image); ++cmptno) { - if (jas_image_cmptprec(image, cmptno) != jas_image_cmptprec(image, 0) || - jas_image_cmptsgnd(image, cmptno) != jas_image_cmptsgnd(image, 0) || - jas_image_cmptwidth(image, cmptno) != jas_image_cmptwidth(image, 0) || - jas_image_cmptheight(image, cmptno) != jas_image_cmptheight(image, 0)) { - mctvalid = false; - } - } - } else { - mctvalid = false; - } - if (mctvalid && enablemct && jas_image_colorspace(image) != JAS_IMAGE_CS_RGB) { - fprintf(stderr, "warning: color model apparently not RGB\n"); - } - if (mctvalid && enablemct && jas_image_colorspace(image) == JAS_IMAGE_CS_RGB) { - tcp->mctid = (tcp->intmode) ? (JPC_MCT_RCT) : (JPC_MCT_ICT); - } else { - tcp->mctid = JPC_MCT_NONE; - } - tccp->qmfbid = (tcp->intmode) ? (JPC_COX_RFT) : (JPC_COX_INS); - - for (rlvlno = 0; rlvlno < tccp->maxrlvls; ++rlvlno) { - tccp->prcwidthexpns[rlvlno] = prcwidthexpn; - tccp->prcheightexpns[rlvlno] = prcheightexpn; - } - if (prcwidthexpn != 15 || prcheightexpn != 15) { - tccp->csty |= JPC_COX_PRT; - } - - /* Ensure that the tile width and height is valid. */ - if (!cp->tilewidth) { - fprintf(stderr, "invalid tile width %lu\n", (unsigned long) - cp->tilewidth); - goto error; - } - if (!cp->tileheight) { - fprintf(stderr, "invalid tile height %lu\n", (unsigned long) - cp->tileheight); - goto error; - } - - /* Ensure that the tile grid offset is valid. */ - if (cp->tilegrdoffx > cp->imgareatlx || - cp->tilegrdoffy > cp->imgareatly || - cp->tilegrdoffx + cp->tilewidth < cp->imgareatlx || - cp->tilegrdoffy + cp->tileheight < cp->imgareatly) { - fprintf(stderr, "invalid tile grid offset (%lu, %lu)\n", - (unsigned long) cp->tilegrdoffx, (unsigned long) - cp->tilegrdoffy); - goto error; - } - - cp->numhtiles = JPC_CEILDIV(cp->refgrdwidth - cp->tilegrdoffx, - cp->tilewidth); - cp->numvtiles = JPC_CEILDIV(cp->refgrdheight - cp->tilegrdoffy, - cp->tileheight); - cp->numtiles = cp->numhtiles * cp->numvtiles; - - if (ilyrrates && numilyrrates > 0) { - tcp->numlyrs = numilyrrates + 1; - if (!(tcp->ilyrrates = jas_malloc((tcp->numlyrs - 1) * - sizeof(jpc_fix_t)))) { - goto error; - } - for (i = 0; i < tcp->numlyrs - 1; ++i) { - tcp->ilyrrates[i] = jpc_dbltofix(ilyrrates[i]); - } - } - - /* Ensure that the integer mode is used in the case of lossless - coding. */ - if (cp->totalsize == UINT_FAST32_MAX && (!cp->tcp.intmode)) { - fprintf(stderr, "cannot use real mode for lossless coding\n"); - goto error; - } - - /* Ensure that the precinct width is valid. */ - if (prcwidthexpn > 15) { - fprintf(stderr, "invalid precinct width\n"); - goto error; - } - - /* Ensure that the precinct height is valid. */ - if (prcheightexpn > 15) { - fprintf(stderr, "invalid precinct height\n"); - goto error; - } - - /* Ensure that the code block width is valid. */ - if (cp->tccp.cblkwidthexpn < 2 || cp->tccp.cblkwidthexpn > 12) { - fprintf(stderr, "invalid code block width %d\n", - JPC_POW2(cp->tccp.cblkwidthexpn)); - goto error; - } - - /* Ensure that the code block height is valid. */ - if (cp->tccp.cblkheightexpn < 2 || cp->tccp.cblkheightexpn > 12) { - fprintf(stderr, "invalid code block height %d\n", - JPC_POW2(cp->tccp.cblkheightexpn)); - goto error; - } - - /* Ensure that the code block size is not too large. */ - if (cp->tccp.cblkwidthexpn + cp->tccp.cblkheightexpn > 12) { - fprintf(stderr, "code block size too large\n"); - goto error; - } - - /* Ensure that the number of layers is valid. */ - if (cp->tcp.numlyrs > 16384) { - fprintf(stderr, "too many layers\n"); - goto error; - } - - /* There must be at least one resolution level. */ - if (cp->tccp.maxrlvls < 1) { - fprintf(stderr, "must be at least one resolution level\n"); - goto error; - } - - /* Ensure that the number of guard bits is valid. */ - if (cp->tccp.numgbits > 8) { - fprintf(stderr, "invalid number of guard bits\n"); - goto error; - } - - /* Ensure that the rate is within the legal range. */ - if (cp->totalsize != UINT_FAST32_MAX && cp->totalsize > cp->rawsize) { - fprintf(stderr, "warning: specified rate is unreasonably large (%lu > %lu)\n", (unsigned long) cp->totalsize, (unsigned long) cp->rawsize); - } - - /* Ensure that the intermediate layer rates are valid. */ - if (tcp->numlyrs > 1) { - /* The intermediate layers rates must increase monotonically. */ - for (lyrno = 0; lyrno + 2 < tcp->numlyrs; ++lyrno) { - if (tcp->ilyrrates[lyrno] >= tcp->ilyrrates[lyrno + 1]) { - fprintf(stderr, "intermediate layer rates must increase monotonically\n"); - goto error; - } - } - /* The intermediate layer rates must be less than the overall rate. */ - if (cp->totalsize != UINT_FAST32_MAX) { - for (lyrno = 0; lyrno < tcp->numlyrs - 1; ++lyrno) { - if (jpc_fixtodbl(tcp->ilyrrates[lyrno]) > ((double) cp->totalsize) - / cp->rawsize) { - fprintf(stderr, "warning: intermediate layer rates must be less than overall rate\n"); - goto error; - } - } - } - } - - if (ilyrrates) { - jas_free(ilyrrates); - } - - return cp; + jpc_enc_cp_t *cp; + jas_tvparser_t *tvp; + int ret; + int numilyrrates; + double *ilyrrates; + int i; + int tagid; + jpc_enc_tcp_t *tcp; + jpc_enc_tccp_t *tccp; + jpc_enc_ccp_t *ccp; + uint_fast16_t cmptno; + uint_fast16_t rlvlno; + uint_fast16_t prcwidthexpn; + uint_fast16_t prcheightexpn; + bool enablemct; + uint_fast32_t jp2overhead; + uint_fast16_t lyrno; + uint_fast32_t hsteplcm; + uint_fast32_t vsteplcm; + bool mctvalid; + + tvp = 0; + cp = 0; + ilyrrates = 0; + numilyrrates = 0; + + if (!(cp = jas_malloc(sizeof(jpc_enc_cp_t)))) { + goto error; + } + + prcwidthexpn = 15; + prcheightexpn = 15; + enablemct = true; + jp2overhead = 0; + + cp->ccps = 0; + cp->debug = 0; + cp->imgareatlx = UINT_FAST32_MAX; + cp->imgareatly = UINT_FAST32_MAX; + cp->refgrdwidth = 0; + cp->refgrdheight = 0; + cp->tilegrdoffx = UINT_FAST32_MAX; + cp->tilegrdoffy = UINT_FAST32_MAX; + cp->tilewidth = 0; + cp->tileheight = 0; + cp->numcmpts = jas_image_numcmpts(image); + + hsteplcm = 1; + vsteplcm = 1; + for (cmptno = 0; cmptno < jas_image_numcmpts(image); ++cmptno) { + if (jas_image_cmptbrx(image, cmptno) + jas_image_cmpthstep(image, cmptno) <= + jas_image_brx(image) || jas_image_cmptbry(image, cmptno) + + jas_image_cmptvstep(image, cmptno) <= jas_image_bry(image)) { + fprintf(stderr, "We don't know how to interpret this image type\n"); + goto error; + } + /* Note: We ought to be calculating the LCMs here. Fix some day. */ + hsteplcm *= jas_image_cmpthstep(image, cmptno); + vsteplcm *= jas_image_cmptvstep(image, cmptno); + } + + if (!(cp->ccps = jas_malloc(cp->numcmpts * sizeof(jpc_enc_ccp_t)))) { + goto error; + } + for (cmptno = 0, ccp = cp->ccps; cmptno < cp->numcmpts; ++cmptno, + ++ccp) { + ccp->sampgrdstepx = jas_image_cmpthstep(image, cmptno); + ccp->sampgrdstepy = jas_image_cmptvstep(image, cmptno); + /* XXX - this isn't quite correct for more general image */ + ccp->sampgrdsubstepx = 0; + ccp->sampgrdsubstepx = 0; + ccp->prec = jas_image_cmptprec(image, cmptno); + ccp->sgnd = jas_image_cmptsgnd(image, cmptno); + ccp->numstepsizes = 0; + memset(ccp->stepsizes, 0, sizeof(ccp->stepsizes)); + } + + cp->rawsize = jas_image_rawsize(image); + cp->totalsize = UINT_FAST32_MAX; + + tcp = &cp->tcp; + tcp->csty = 0; + tcp->intmode = true; + tcp->prg = JPC_COD_LRCPPRG; + tcp->numlyrs = 1; + tcp->ilyrrates = 0; + + tccp = &cp->tccp; + tccp->csty = 0; + tccp->maxrlvls = 6; + tccp->cblkwidthexpn = 6; + tccp->cblkheightexpn = 6; + tccp->cblksty = 0; + tccp->numgbits = 2; + + if (!(tvp = jas_tvparser_create(optstr ? optstr : ""))) { + goto error; + } + + while (!(ret = jas_tvparser_next(tvp))) { + switch (jas_taginfo_nonull(jas_taginfos_lookup(encopts, + jas_tvparser_gettag(tvp)))->id) { + case OPT_DEBUG: + cp->debug = atoi(jas_tvparser_getval(tvp)); + break; + case OPT_IMGAREAOFFX: + cp->imgareatlx = atoi(jas_tvparser_getval(tvp)); + break; + case OPT_IMGAREAOFFY: + cp->imgareatly = atoi(jas_tvparser_getval(tvp)); + break; + case OPT_TILEGRDOFFX: + cp->tilegrdoffx = atoi(jas_tvparser_getval(tvp)); + break; + case OPT_TILEGRDOFFY: + cp->tilegrdoffy = atoi(jas_tvparser_getval(tvp)); + break; + case OPT_TILEWIDTH: + cp->tilewidth = atoi(jas_tvparser_getval(tvp)); + break; + case OPT_TILEHEIGHT: + cp->tileheight = atoi(jas_tvparser_getval(tvp)); + break; + case OPT_PRCWIDTH: + prcwidthexpn = jpc_floorlog2(atoi(jas_tvparser_getval(tvp))); + break; + case OPT_PRCHEIGHT: + prcheightexpn = jpc_floorlog2(atoi(jas_tvparser_getval(tvp))); + break; + case OPT_CBLKWIDTH: + tccp->cblkwidthexpn = + jpc_floorlog2(atoi(jas_tvparser_getval(tvp))); + break; + case OPT_CBLKHEIGHT: + tccp->cblkheightexpn = + jpc_floorlog2(atoi(jas_tvparser_getval(tvp))); + break; + case OPT_MODE: + if ((tagid = jas_taginfo_nonull(jas_taginfos_lookup(modetab, + jas_tvparser_getval(tvp)))->id) < 0) { + fprintf(stderr, + "ignoring invalid mode %s\n", + jas_tvparser_getval(tvp)); + } else { + tcp->intmode = (tagid == MODE_INT); + } + break; + case OPT_PRG: + if ((tagid = jas_taginfo_nonull(jas_taginfos_lookup(prgordtab, + jas_tvparser_getval(tvp)))->id) < 0) { + fprintf(stderr, + "ignoring invalid progression order %s\n", + jas_tvparser_getval(tvp)); + } else { + tcp->prg = tagid; + } + break; + case OPT_NOMCT: + enablemct = false; + break; + case OPT_MAXRLVLS: + tccp->maxrlvls = atoi(jas_tvparser_getval(tvp)); + break; + case OPT_SOP: + cp->tcp.csty |= JPC_COD_SOP; + break; + case OPT_EPH: + cp->tcp.csty |= JPC_COD_EPH; + break; + case OPT_LAZY: + tccp->cblksty |= JPC_COX_LAZY; + break; + case OPT_TERMALL: + tccp->cblksty |= JPC_COX_TERMALL; + break; + case OPT_SEGSYM: + tccp->cblksty |= JPC_COX_SEGSYM; + break; + case OPT_VCAUSAL: + tccp->cblksty |= JPC_COX_VSC; + break; + case OPT_RESET: + tccp->cblksty |= JPC_COX_RESET; + break; + case OPT_PTERM: + tccp->cblksty |= JPC_COX_PTERM; + break; + case OPT_NUMGBITS: + cp->tccp.numgbits = atoi(jas_tvparser_getval(tvp)); + break; + case OPT_RATE: + if (ratestrtosize(jas_tvparser_getval(tvp), cp->rawsize, + &cp->totalsize)) { + fprintf(stderr, + "ignoring bad rate specifier %s\n", + jas_tvparser_getval(tvp)); + } + break; + case OPT_ILYRRATES: + if (jpc_atoaf(jas_tvparser_getval(tvp), &numilyrrates, + &ilyrrates)) { + fprintf(stderr, + "warning: invalid intermediate layer rates specifier ignored (%s)\n", + jas_tvparser_getval(tvp)); + } + break; + + case OPT_JP2OVERHEAD: + jp2overhead = atoi(jas_tvparser_getval(tvp)); + break; + default: + fprintf(stderr, "warning: ignoring invalid option %s\n", + jas_tvparser_gettag(tvp)); + break; + } + } + + jas_tvparser_destroy(tvp); + tvp = 0; + + if (cp->totalsize != UINT_FAST32_MAX) { + cp->totalsize = (cp->totalsize > jp2overhead) ? + (cp->totalsize - jp2overhead) : 0; + } + + if (cp->imgareatlx == UINT_FAST32_MAX) { + cp->imgareatlx = 0; + } else { + if (hsteplcm != 1) { + fprintf(stderr, "warning: overriding imgareatlx value\n"); + } + cp->imgareatlx *= hsteplcm; + } + if (cp->imgareatly == UINT_FAST32_MAX) { + cp->imgareatly = 0; + } else { + if (vsteplcm != 1) { + fprintf(stderr, "warning: overriding imgareatly value\n"); + } + cp->imgareatly *= vsteplcm; + } + cp->refgrdwidth = cp->imgareatlx + jas_image_width(image); + cp->refgrdheight = cp->imgareatly + jas_image_height(image); + if (cp->tilegrdoffx == UINT_FAST32_MAX) { + cp->tilegrdoffx = cp->imgareatlx; + } + if (cp->tilegrdoffy == UINT_FAST32_MAX) { + cp->tilegrdoffy = cp->imgareatly; + } + if (!cp->tilewidth) { + cp->tilewidth = cp->refgrdwidth - cp->tilegrdoffx; + } + if (!cp->tileheight) { + cp->tileheight = cp->refgrdheight - cp->tilegrdoffy; + } + + if (cp->numcmpts == 3) { + mctvalid = true; + for (cmptno = 0; cmptno < jas_image_numcmpts(image); ++cmptno) { + if (jas_image_cmptprec(image, cmptno) != jas_image_cmptprec(image, 0) || + jas_image_cmptsgnd(image, cmptno) != jas_image_cmptsgnd(image, 0) || + jas_image_cmptwidth(image, cmptno) != jas_image_cmptwidth(image, 0) || + jas_image_cmptheight(image, cmptno) != jas_image_cmptheight(image, 0)) { + mctvalid = false; + } + } + } else { + mctvalid = false; + } + if (mctvalid && enablemct && jas_image_colorspace(image) != JAS_IMAGE_CS_RGB) { + fprintf(stderr, "warning: color model apparently not RGB\n"); + } + if (mctvalid && enablemct && jas_image_colorspace(image) == JAS_IMAGE_CS_RGB) { + tcp->mctid = (tcp->intmode) ? (JPC_MCT_RCT) : (JPC_MCT_ICT); + } else { + tcp->mctid = JPC_MCT_NONE; + } + tccp->qmfbid = (tcp->intmode) ? (JPC_COX_RFT) : (JPC_COX_INS); + + for (rlvlno = 0; rlvlno < tccp->maxrlvls; ++rlvlno) { + tccp->prcwidthexpns[rlvlno] = prcwidthexpn; + tccp->prcheightexpns[rlvlno] = prcheightexpn; + } + if (prcwidthexpn != 15 || prcheightexpn != 15) { + tccp->csty |= JPC_COX_PRT; + } + + /* Ensure that the tile width and height is valid. */ + if (!cp->tilewidth) { + fprintf(stderr, "invalid tile width %lu\n", (unsigned long) + cp->tilewidth); + goto error; + } + if (!cp->tileheight) { + fprintf(stderr, "invalid tile height %lu\n", (unsigned long) + cp->tileheight); + goto error; + } + + /* Ensure that the tile grid offset is valid. */ + if (cp->tilegrdoffx > cp->imgareatlx || + cp->tilegrdoffy > cp->imgareatly || + cp->tilegrdoffx + cp->tilewidth < cp->imgareatlx || + cp->tilegrdoffy + cp->tileheight < cp->imgareatly) { + fprintf(stderr, "invalid tile grid offset (%lu, %lu)\n", + (unsigned long) cp->tilegrdoffx, (unsigned long) + cp->tilegrdoffy); + goto error; + } + + cp->numhtiles = JPC_CEILDIV(cp->refgrdwidth - cp->tilegrdoffx, + cp->tilewidth); + cp->numvtiles = JPC_CEILDIV(cp->refgrdheight - cp->tilegrdoffy, + cp->tileheight); + cp->numtiles = cp->numhtiles * cp->numvtiles; + + if (ilyrrates && numilyrrates > 0) { + tcp->numlyrs = numilyrrates + 1; + if (!(tcp->ilyrrates = jas_malloc((tcp->numlyrs - 1) * + sizeof(jpc_fix_t)))) { + goto error; + } + for (i = 0; i < tcp->numlyrs - 1; ++i) { + tcp->ilyrrates[i] = jpc_dbltofix(ilyrrates[i]); + } + } + + /* Ensure that the integer mode is used in the case of lossless + coding. */ + if (cp->totalsize == UINT_FAST32_MAX && (!cp->tcp.intmode)) { + fprintf(stderr, "cannot use real mode for lossless coding\n"); + goto error; + } + + /* Ensure that the precinct width is valid. */ + if (prcwidthexpn > 15) { + fprintf(stderr, "invalid precinct width\n"); + goto error; + } + + /* Ensure that the precinct height is valid. */ + if (prcheightexpn > 15) { + fprintf(stderr, "invalid precinct height\n"); + goto error; + } + + /* Ensure that the code block width is valid. */ + if (cp->tccp.cblkwidthexpn < 2 || cp->tccp.cblkwidthexpn > 12) { + fprintf(stderr, "invalid code block width %d\n", + JPC_POW2(cp->tccp.cblkwidthexpn)); + goto error; + } + + /* Ensure that the code block height is valid. */ + if (cp->tccp.cblkheightexpn < 2 || cp->tccp.cblkheightexpn > 12) { + fprintf(stderr, "invalid code block height %d\n", + JPC_POW2(cp->tccp.cblkheightexpn)); + goto error; + } + + /* Ensure that the code block size is not too large. */ + if (cp->tccp.cblkwidthexpn + cp->tccp.cblkheightexpn > 12) { + fprintf(stderr, "code block size too large\n"); + goto error; + } + + /* Ensure that the number of layers is valid. */ + if (cp->tcp.numlyrs > 16384) { + fprintf(stderr, "too many layers\n"); + goto error; + } + + /* There must be at least one resolution level. */ + if (cp->tccp.maxrlvls < 1) { + fprintf(stderr, "must be at least one resolution level\n"); + goto error; + } + + /* Ensure that the number of guard bits is valid. */ + if (cp->tccp.numgbits > 8) { + fprintf(stderr, "invalid number of guard bits\n"); + goto error; + } + + /* Ensure that the intermediate layer rates are valid. */ + if (tcp->numlyrs > 1) { + /* The intermediate layers rates must increase monotonically. */ + for (lyrno = 0; lyrno + 2 < tcp->numlyrs; ++lyrno) { + if (tcp->ilyrrates[lyrno] >= tcp->ilyrrates[lyrno + 1]) { + fprintf(stderr, "intermediate layer rates must increase monotonically\n"); + goto error; + } + } + /* The intermediate layer rates must be less than the overall rate. */ + if (cp->totalsize != UINT_FAST32_MAX) { + for (lyrno = 0; lyrno < tcp->numlyrs - 1; ++lyrno) { + if (jpc_fixtodbl(tcp->ilyrrates[lyrno]) > ((double) cp->totalsize) + / cp->rawsize) { + fprintf(stderr, "warning: intermediate layer rates must be less than overall rate\n"); + goto error; + } + } + } + } + + if (ilyrrates) { + jas_free(ilyrrates); + } + + return cp; error: - if (ilyrrates) { - jas_free(ilyrrates); - } - if (tvp) { - jas_tvparser_destroy(tvp); - } - if (cp) { - jpc_enc_cp_destroy(cp); - } - return 0; + if (ilyrrates) { + jas_free(ilyrrates); + } + if (tvp) { + jas_tvparser_destroy(tvp); + } + if (cp) { + jpc_enc_cp_destroy(cp); + } + return 0; } void jpc_enc_cp_destroy(jpc_enc_cp_t *cp) { - if (cp->ccps) { - if (cp->tcp.ilyrrates) { - jas_free(cp->tcp.ilyrrates); - } - jas_free(cp->ccps); - } - jas_free(cp); + if (cp->ccps) { + if (cp->tcp.ilyrrates) { + jas_free(cp->tcp.ilyrrates); + } + jas_free(cp->ccps); + } + jas_free(cp); } int ratestrtosize(const char *s, uint_fast32_t rawsize, uint_fast32_t *size) { - char *cp; - jpc_flt_t f; - - /* Note: This function must not modify output size on failure. */ - if ((cp = strchr(s, 'B'))) { - *size = atoi(s); - } else { - f = atof(s); - if (f < 0) { - *size = 0; - } else if (f > 1.0) { - *size = rawsize + 1; - } else { - *size = f * rawsize; - } - } - return 0; + char *cp; + jpc_flt_t f; + + /* Note: This function must not modify output size on failure. */ + if ((cp = strchr(s, 'B'))) { + *size = atoi(s); + } else { + f = atof(s); + if (f < 0) { + *size = 0; + } else if (f > 1.0) { + *size = rawsize + 1; + } else { + *size = f * rawsize; + } + } + return 0; } /******************************************************************************\ @@ -852,58 +756,58 @@ int ratestrtosize(const char *s, uint_fast32_t rawsize, uint_fast32_t *size) jpc_enc_t *jpc_enc_create(jpc_enc_cp_t *cp, jas_stream_t *out, jas_image_t *image) { - jpc_enc_t *enc; + jpc_enc_t *enc; - enc = 0; + enc = 0; - if (!(enc = jas_malloc(sizeof(jpc_enc_t)))) { - goto error; - } + if (!(enc = jas_malloc(sizeof(jpc_enc_t)))) { + goto error; + } - enc->image = image; - enc->out = out; - enc->cp = cp; - enc->cstate = 0; - enc->tmpstream = 0; - enc->mrk = 0; - enc->curtile = 0; + enc->image = image; + enc->out = out; + enc->cp = cp; + enc->cstate = 0; + enc->tmpstream = 0; + enc->mrk = 0; + enc->curtile = 0; - if (!(enc->cstate = jpc_cstate_create())) { - goto error; - } - enc->len = 0; - enc->mainbodysize = 0; + if (!(enc->cstate = jpc_cstate_create())) { + goto error; + } + enc->len = 0; + enc->mainbodysize = 0; - return enc; + return enc; error: - if (enc) { - jpc_enc_destroy(enc); - } - return 0; + if (enc) { + jpc_enc_destroy(enc); + } + return 0; } void jpc_enc_destroy(jpc_enc_t *enc) { - /* The image object (i.e., enc->image) and output stream object - (i.e., enc->out) are created outside of the encoder. - Therefore, they must not be destroyed here. */ - - if (enc->curtile) { - jpc_enc_tile_destroy(enc->curtile); - } - if (enc->cp) { - jpc_enc_cp_destroy(enc->cp); - } - if (enc->cstate) { - jpc_cstate_destroy(enc->cstate); - } - if (enc->tmpstream) { - jas_stream_close(enc->tmpstream); - } - - jas_free(enc); + /* The image object (i.e., enc->image) and output stream object + (i.e., enc->out) are created outside of the encoder. + Therefore, they must not be destroyed here. */ + + if (enc->curtile) { + jpc_enc_tile_destroy(enc->curtile); + } + if (enc->cp) { + jpc_enc_cp_destroy(enc->cp); + } + if (enc->cstate) { + jpc_cstate_destroy(enc->cstate); + } + if (enc->tmpstream) { + jas_stream_close(enc->tmpstream); + } + + jas_free(enc); } /******************************************************************************\ @@ -912,1713 +816,2011 @@ void jpc_enc_destroy(jpc_enc_t *enc) static int jpc_enc_encodemainhdr(jpc_enc_t *enc) { - jpc_siz_t *siz; - jpc_cod_t *cod; - jpc_qcd_t *qcd; - int i; + jpc_siz_t *siz; + jpc_cod_t *cod; + jpc_qcd_t *qcd; + int i; long startoff; long mainhdrlen; - jpc_enc_cp_t *cp; - jpc_qcc_t *qcc; - jpc_enc_tccp_t *tccp; - uint_fast16_t cmptno; - jpc_tsfb_band_t bandinfos[JPC_MAXBANDS]; - jpc_fix_t mctsynweight; - jpc_enc_tcp_t *tcp; - jpc_tsfb_t *tsfb; - jpc_tsfb_band_t *bandinfo; - uint_fast16_t numbands; - uint_fast16_t bandno; - uint_fast16_t rlvlno; - uint_fast16_t analgain; - jpc_fix_t absstepsize; - char buf[1024]; - jpc_com_t *com; - - cp = enc->cp; + jpc_enc_cp_t *cp; + jpc_qcc_t *qcc; + jpc_enc_tccp_t *tccp; + uint_fast16_t cmptno; + jpc_tsfb_band_t bandinfos[JPC_MAXBANDS]; + jpc_fix_t mctsynweight; + jpc_enc_tcp_t *tcp; + jpc_tsfb_t *tsfb; + jpc_tsfb_band_t *bandinfo; + uint_fast16_t numbands; + uint_fast16_t bandno; + uint_fast16_t rlvlno; + uint_fast16_t analgain; + jpc_fix_t absstepsize; + char buf[1024]; + jpc_com_t *com; + + cp = enc->cp; startoff = jas_stream_getrwcount(enc->out); - /* Write SOC marker segment. */ - if (!(enc->mrk = jpc_ms_create(JPC_MS_SOC))) { - return -1; - } - if (jpc_putms(enc->out, enc->cstate, enc->mrk)) { - fprintf(stderr, "cannot write SOC marker\n"); - return -1; - } - jpc_ms_destroy(enc->mrk); - enc->mrk = 0; - - /* Write SIZ marker segment. */ - if (!(enc->mrk = jpc_ms_create(JPC_MS_SIZ))) { - return -1; - } - siz = &enc->mrk->parms.siz; - siz->caps = 0; - siz->xoff = cp->imgareatlx; - siz->yoff = cp->imgareatly; - siz->width = cp->refgrdwidth; - siz->height = cp->refgrdheight; - siz->tilexoff = cp->tilegrdoffx; - siz->tileyoff = cp->tilegrdoffy; - siz->tilewidth = cp->tilewidth; - siz->tileheight = cp->tileheight; - siz->numcomps = cp->numcmpts; - siz->comps = jas_malloc(siz->numcomps * sizeof(jpc_sizcomp_t)); - assert(siz->comps); - for (i = 0; i < cp->numcmpts; ++i) { - siz->comps[i].prec = cp->ccps[i].prec; - siz->comps[i].sgnd = cp->ccps[i].sgnd; - siz->comps[i].hsamp = cp->ccps[i].sampgrdstepx; - siz->comps[i].vsamp = cp->ccps[i].sampgrdstepy; - } - if (jpc_putms(enc->out, enc->cstate, enc->mrk)) { - fprintf(stderr, "cannot write SIZ marker\n"); - return -1; - } - jpc_ms_destroy(enc->mrk); - enc->mrk = 0; - - if (!(enc->mrk = jpc_ms_create(JPC_MS_COM))) { - return -1; - } - sprintf(buf, "Creator: JasPer Version %s", jas_getversion()); - com = &enc->mrk->parms.com; - com->len = strlen(buf); - com->regid = JPC_COM_LATIN; - if (!(com->data = JAS_CAST(unsigned char *, jas_strdup(buf)))) { - abort(); - } - if (jpc_putms(enc->out, enc->cstate, enc->mrk)) { - fprintf(stderr, "cannot write COM marker\n"); - return -1; - } - jpc_ms_destroy(enc->mrk); - enc->mrk = 0; + /* Write SOC marker segment. */ + if (!(enc->mrk = jpc_ms_create(JPC_MS_SOC))) { + return -1; + } + if (jpc_putms(enc->out, enc->cstate, enc->mrk)) { + fprintf(stderr, "cannot write SOC marker\n"); + return -1; + } + jpc_ms_destroy(enc->mrk); + enc->mrk = 0; + + /* Write SIZ marker segment. */ + if (!(enc->mrk = jpc_ms_create(JPC_MS_SIZ))) { + return -1; + } + siz = &enc->mrk->parms.siz; + siz->caps = 0; + siz->xoff = cp->imgareatlx; + siz->yoff = cp->imgareatly; + siz->width = cp->refgrdwidth; + siz->height = cp->refgrdheight; + siz->tilexoff = cp->tilegrdoffx; + siz->tileyoff = cp->tilegrdoffy; + siz->tilewidth = cp->tilewidth; + siz->tileheight = cp->tileheight; + siz->numcomps = cp->numcmpts; + siz->comps = jas_malloc(siz->numcomps * sizeof(jpc_sizcomp_t)); + assert(siz->comps); + for (i = 0; i < cp->numcmpts; ++i) { + siz->comps[i].prec = cp->ccps[i].prec; + siz->comps[i].sgnd = cp->ccps[i].sgnd; + siz->comps[i].hsamp = cp->ccps[i].sampgrdstepx; + siz->comps[i].vsamp = cp->ccps[i].sampgrdstepy; + } + if (jpc_putms(enc->out, enc->cstate, enc->mrk)) { + fprintf(stderr, "cannot write SIZ marker\n"); + return -1; + } + jpc_ms_destroy(enc->mrk); + enc->mrk = 0; + + if (!(enc->mrk = jpc_ms_create(JPC_MS_COM))) { + return -1; + } + sprintf(buf, "Creator: JasPer Version %s", jas_getversion()); + com = &enc->mrk->parms.com; + com->len = strlen(buf); + com->regid = JPC_COM_LATIN; + if (!(com->data = JAS_CAST(unsigned char *, jas_strdup(buf)))) { + abort(); + } + if (jpc_putms(enc->out, enc->cstate, enc->mrk)) { + fprintf(stderr, "cannot write COM marker\n"); + return -1; + } + jpc_ms_destroy(enc->mrk); + enc->mrk = 0; #if 0 - if (!(enc->mrk = jpc_ms_create(JPC_MS_CRG))) { - return -1; - } - crg = &enc->mrk->parms.crg; - crg->comps = jas_malloc(crg->numcomps * sizeof(jpc_crgcomp_t)); - if (jpc_putms(enc->out, enc->cstate, enc->mrk)) { - fprintf(stderr, "cannot write CRG marker\n"); - return -1; - } - jpc_ms_destroy(enc->mrk); - enc->mrk = 0; + if (!(enc->mrk = jpc_ms_create(JPC_MS_CRG))) { + return -1; + } + crg = &enc->mrk->parms.crg; + crg->comps = jas_malloc(crg->numcomps * sizeof(jpc_crgcomp_t)); + if (jpc_putms(enc->out, enc->cstate, enc->mrk)) { + fprintf(stderr, "cannot write CRG marker\n"); + return -1; + } + jpc_ms_destroy(enc->mrk); + enc->mrk = 0; #endif - tcp = &cp->tcp; - tccp = &cp->tccp; - for (cmptno = 0; cmptno < cp->numcmpts; ++cmptno) { - tsfb = jpc_cod_gettsfb(tccp->qmfbid, tccp->maxrlvls - 1); - jpc_tsfb_getbands(tsfb, 0, 0, 1 << tccp->maxrlvls, 1 << tccp->maxrlvls, - bandinfos); - jpc_tsfb_destroy(tsfb); - mctsynweight = jpc_mct_getsynweight(tcp->mctid, cmptno); - numbands = 3 * tccp->maxrlvls - 2; - for (bandno = 0, bandinfo = bandinfos; bandno < numbands; - ++bandno, ++bandinfo) { - rlvlno = (bandno) ? ((bandno - 1) / 3 + 1) : 0; - analgain = JPC_NOMINALGAIN(tccp->qmfbid, tccp->maxrlvls, - rlvlno, bandinfo->orient); - if (!tcp->intmode) { - absstepsize = jpc_fix_div(jpc_inttofix(1 << - (analgain + 1)), bandinfo->synenergywt); - } else { - absstepsize = jpc_inttofix(1); - } - cp->ccps[cmptno].stepsizes[bandno] = - jpc_abstorelstepsize(absstepsize, - cp->ccps[cmptno].prec + analgain); - } - cp->ccps[cmptno].numstepsizes = numbands; - } - - if (!(enc->mrk = jpc_ms_create(JPC_MS_COD))) { - return -1; - } - cod = &enc->mrk->parms.cod; - cod->csty = cp->tccp.csty | cp->tcp.csty; - cod->compparms.csty = cp->tccp.csty | cp->tcp.csty; - cod->compparms.numdlvls = cp->tccp.maxrlvls - 1; - cod->compparms.numrlvls = cp->tccp.maxrlvls; - cod->prg = cp->tcp.prg; - cod->numlyrs = cp->tcp.numlyrs; - cod->compparms.cblkwidthval = JPC_COX_CBLKSIZEEXPN(cp->tccp.cblkwidthexpn); - cod->compparms.cblkheightval = JPC_COX_CBLKSIZEEXPN(cp->tccp.cblkheightexpn); - cod->compparms.cblksty = cp->tccp.cblksty; - cod->compparms.qmfbid = cp->tccp.qmfbid; - cod->mctrans = (cp->tcp.mctid != JPC_MCT_NONE); - if (tccp->csty & JPC_COX_PRT) { - for (rlvlno = 0; rlvlno < tccp->maxrlvls; ++rlvlno) { - cod->compparms.rlvls[rlvlno].parwidthval = tccp->prcwidthexpns[rlvlno]; - cod->compparms.rlvls[rlvlno].parheightval = tccp->prcheightexpns[rlvlno]; - } - } - if (jpc_putms(enc->out, enc->cstate, enc->mrk)) { - fprintf(stderr, "cannot write COD marker\n"); - return -1; - } - jpc_ms_destroy(enc->mrk); - enc->mrk = 0; - - if (!(enc->mrk = jpc_ms_create(JPC_MS_QCD))) { - return -1; - } - qcd = &enc->mrk->parms.qcd; - qcd->compparms.qntsty = (tccp->qmfbid == JPC_COX_INS) ? - JPC_QCX_SEQNT : JPC_QCX_NOQNT; - qcd->compparms.numstepsizes = cp->ccps[0].numstepsizes; - qcd->compparms.numguard = cp->tccp.numgbits; - qcd->compparms.stepsizes = cp->ccps[0].stepsizes; - if (jpc_putms(enc->out, enc->cstate, enc->mrk)) { - return -1; - } - /* We do not want the step size array to be freed! */ - qcd->compparms.stepsizes = 0; - jpc_ms_destroy(enc->mrk); - enc->mrk = 0; - - tccp = &cp->tccp; - for (cmptno = 1; cmptno < cp->numcmpts; ++cmptno) { - if (!(enc->mrk = jpc_ms_create(JPC_MS_QCC))) { - return -1; - } - qcc = &enc->mrk->parms.qcc; - qcc->compno = cmptno; - qcc->compparms.qntsty = (tccp->qmfbid == JPC_COX_INS) ? - JPC_QCX_SEQNT : JPC_QCX_NOQNT; - qcc->compparms.numstepsizes = cp->ccps[cmptno].numstepsizes; - qcc->compparms.numguard = cp->tccp.numgbits; - qcc->compparms.stepsizes = cp->ccps[cmptno].stepsizes; - if (jpc_putms(enc->out, enc->cstate, enc->mrk)) { - return -1; - } - /* We do not want the step size array to be freed! */ - qcc->compparms.stepsizes = 0; - jpc_ms_destroy(enc->mrk); - enc->mrk = 0; - } - -#define MAINTLRLEN 2 - mainhdrlen = jas_stream_getrwcount(enc->out) - startoff; - enc->len += mainhdrlen; - if (enc->cp->totalsize != UINT_FAST32_MAX) { - uint_fast32_t overhead; - overhead = mainhdrlen + MAINTLRLEN; - enc->mainbodysize = (enc->cp->totalsize >= overhead) ? - (enc->cp->totalsize - overhead) : 0; - } else { - enc->mainbodysize = UINT_FAST32_MAX; - } - - return 0; + tcp = &cp->tcp; + tccp = &cp->tccp; + for (cmptno = 0; cmptno < cp->numcmpts; ++cmptno) { + tsfb = jpc_cod_gettsfb(tccp->qmfbid, tccp->maxrlvls - 1); + jpc_tsfb_getbands(tsfb, 0, 0, 1 << tccp->maxrlvls, 1 << tccp->maxrlvls, + bandinfos); + jpc_tsfb_destroy(tsfb); + mctsynweight = jpc_mct_getsynweight(tcp->mctid, cmptno); + numbands = 3 * tccp->maxrlvls - 2; + for (bandno = 0, bandinfo = bandinfos; bandno < numbands; + ++bandno, ++bandinfo) { + rlvlno = (bandno) ? ((bandno - 1) / 3 + 1) : 0; + analgain = JPC_NOMINALGAIN(tccp->qmfbid, tccp->maxrlvls, + rlvlno, bandinfo->orient); + if (!tcp->intmode) { + absstepsize = jpc_fix_div(jpc_inttofix(1 << + (analgain + 1)), bandinfo->synenergywt); + } else { + absstepsize = jpc_inttofix(1); + } + cp->ccps[cmptno].stepsizes[bandno] = + jpc_abstorelstepsize(absstepsize, + cp->ccps[cmptno].prec + analgain); + } + cp->ccps[cmptno].numstepsizes = numbands; + } + + if (!(enc->mrk = jpc_ms_create(JPC_MS_COD))) { + return -1; + } + cod = &enc->mrk->parms.cod; + cod->csty = cp->tccp.csty | cp->tcp.csty; + cod->compparms.csty = cp->tccp.csty | cp->tcp.csty; + cod->compparms.numdlvls = cp->tccp.maxrlvls - 1; + cod->compparms.numrlvls = cp->tccp.maxrlvls; + cod->prg = cp->tcp.prg; + cod->numlyrs = cp->tcp.numlyrs; + cod->compparms.cblkwidthval = JPC_COX_CBLKSIZEEXPN(cp->tccp.cblkwidthexpn); + cod->compparms.cblkheightval = JPC_COX_CBLKSIZEEXPN(cp->tccp.cblkheightexpn); + cod->compparms.cblksty = cp->tccp.cblksty; + cod->compparms.qmfbid = cp->tccp.qmfbid; + cod->mctrans = (cp->tcp.mctid != JPC_MCT_NONE); + if (tccp->csty & JPC_COX_PRT) { + for (rlvlno = 0; rlvlno < tccp->maxrlvls; ++rlvlno) { + cod->compparms.rlvls[rlvlno].parwidthval = tccp->prcwidthexpns[rlvlno]; + cod->compparms.rlvls[rlvlno].parheightval = tccp->prcheightexpns[rlvlno]; + } + } + if (jpc_putms(enc->out, enc->cstate, enc->mrk)) { + fprintf(stderr, "cannot write COD marker\n"); + return -1; + } + jpc_ms_destroy(enc->mrk); + enc->mrk = 0; + + if (!(enc->mrk = jpc_ms_create(JPC_MS_QCD))) { + return -1; + } + qcd = &enc->mrk->parms.qcd; + qcd->compparms.qntsty = (tccp->qmfbid == JPC_COX_INS) ? + JPC_QCX_SEQNT : JPC_QCX_NOQNT; + qcd->compparms.numstepsizes = cp->ccps[0].numstepsizes; + qcd->compparms.numguard = cp->tccp.numgbits; + qcd->compparms.stepsizes = cp->ccps[0].stepsizes; + if (jpc_putms(enc->out, enc->cstate, enc->mrk)) { + return -1; + } + /* We do not want the step size array to be freed! */ + qcd->compparms.stepsizes = 0; + jpc_ms_destroy(enc->mrk); + enc->mrk = 0; + + tccp = &cp->tccp; + for (cmptno = 1; cmptno < cp->numcmpts; ++cmptno) { + if (!(enc->mrk = jpc_ms_create(JPC_MS_QCC))) { + return -1; + } + qcc = &enc->mrk->parms.qcc; + qcc->compno = cmptno; + qcc->compparms.qntsty = (tccp->qmfbid == JPC_COX_INS) ? + JPC_QCX_SEQNT : JPC_QCX_NOQNT; + qcc->compparms.numstepsizes = cp->ccps[cmptno].numstepsizes; + qcc->compparms.numguard = cp->tccp.numgbits; + qcc->compparms.stepsizes = cp->ccps[cmptno].stepsizes; + if (jpc_putms(enc->out, enc->cstate, enc->mrk)) { + return -1; + } + /* We do not want the step size array to be freed! */ + qcc->compparms.stepsizes = 0; + jpc_ms_destroy(enc->mrk); + enc->mrk = 0; + } + +#define MAINTLRLEN 2 + mainhdrlen = jas_stream_getrwcount(enc->out) - startoff; + enc->len += mainhdrlen; + if (enc->cp->totalsize != UINT_FAST32_MAX) { + uint_fast32_t overhead; + overhead = mainhdrlen + MAINTLRLEN; + enc->mainbodysize = (enc->cp->totalsize >= overhead) ? + (enc->cp->totalsize - overhead) : 0; + } else { + enc->mainbodysize = UINT_FAST32_MAX; + } + + return 0; } -static int jpc_enc_encodemainbody(jpc_enc_t *enc) +int jpc_enc_encodetiledata(jpc_enc_t *enc) { - int tileno; - int tilex; - int tiley; - int i; - jpc_sot_t *sot; - jpc_enc_tcmpt_t *comp; - jpc_enc_tcmpt_t *endcomps; - jpc_enc_band_t *band; - jpc_enc_band_t *endbands; - jpc_enc_rlvl_t *lvl; - int rlvlno; - jpc_qcc_t *qcc; - jpc_cod_t *cod; - int adjust; - int j; - int absbandno; - long numbytes; - long tilehdrlen; - long tilelen; - jpc_enc_tile_t *tile; - jpc_enc_cp_t *cp; - double rho; - uint_fast16_t lyrno; - uint_fast16_t cmptno; - int samestepsizes; - jpc_enc_ccp_t *ccps; - jpc_enc_tccp_t *tccp; -int bandno; -uint_fast32_t x; -uint_fast32_t y; -int mingbits; -int actualnumbps; -jpc_fix_t mxmag; -jpc_fix_t mag; -int numgbits; - - cp = enc->cp; - - /* Avoid compile warnings. */ - numbytes = 0; - - for (tileno = 0; tileno < cp->numtiles; ++tileno) { - tilex = tileno % cp->numhtiles; - tiley = tileno / cp->numhtiles; - - if (!(enc->curtile = jpc_enc_tile_create(enc->cp, enc->image, tileno))) { - abort(); - } - - tile = enc->curtile; - - if (jas_getdbglevel() >= 10) { - jpc_enc_dump(enc); - } - - endcomps = &tile->tcmpts[tile->numtcmpts]; - for (cmptno = 0, comp = tile->tcmpts; cmptno < tile->numtcmpts; ++cmptno, ++comp) { - if (!cp->ccps[cmptno].sgnd) { - adjust = 1 << (cp->ccps[cmptno].prec - 1); - for (i = 0; i < jas_matrix_numrows(comp->data); ++i) { - for (j = 0; j < jas_matrix_numcols(comp->data); ++j) { - *jas_matrix_getref(comp->data, i, j) -= adjust; - } - } - } - } - - if (!tile->intmode) { - endcomps = &tile->tcmpts[tile->numtcmpts]; - for (comp = tile->tcmpts; comp != endcomps; ++comp) { - jas_matrix_asl(comp->data, JPC_FIX_FRACBITS); - } - } - - switch (tile->mctid) { - case JPC_MCT_RCT: -assert(jas_image_numcmpts(enc->image) == 3); - jpc_rct(tile->tcmpts[0].data, tile->tcmpts[1].data, - tile->tcmpts[2].data); - break; - case JPC_MCT_ICT: -assert(jas_image_numcmpts(enc->image) == 3); - jpc_ict(tile->tcmpts[0].data, tile->tcmpts[1].data, - tile->tcmpts[2].data); - break; - default: - break; - } - - for (i = 0; i < jas_image_numcmpts(enc->image); ++i) { - comp = &tile->tcmpts[i]; - jpc_tsfb_analyze(comp->tsfb, ((comp->qmfbid == JPC_COX_RFT) ? JPC_TSFB_RITIMODE : 0), comp->data); - - } - - - endcomps = &tile->tcmpts[tile->numtcmpts]; - for (cmptno = 0, comp = tile->tcmpts; comp != endcomps; ++cmptno, ++comp) { - mingbits = 0; - absbandno = 0; - /* All bands must have a corresponding quantizer step size, - even if they contain no samples and are never coded. */ - /* Some bands may not be hit by the loop below, so we must - initialize all of the step sizes to a sane value. */ - memset(comp->stepsizes, 0, sizeof(comp->stepsizes)); - for (rlvlno = 0, lvl = comp->rlvls; rlvlno < comp->numrlvls; ++rlvlno, ++lvl) { - if (!lvl->bands) { - absbandno += rlvlno ? 3 : 1; - continue; - } - endbands = &lvl->bands[lvl->numbands]; - for (band = lvl->bands; band != endbands; ++band) { - if (!band->data) { - ++absbandno; - continue; - } - actualnumbps = 0; - mxmag = 0; - for (y = 0; y < jas_matrix_numrows(band->data); ++y) { - for (x = 0; x < jas_matrix_numcols(band->data); ++x) { - mag = abs(jas_matrix_get(band->data, y, x)); - if (mag > mxmag) { - mxmag = mag; - } - } - } - if (tile->intmode) { - actualnumbps = jpc_firstone(mxmag) + 1; - } else { - actualnumbps = jpc_firstone(mxmag) + 1 - JPC_FIX_FRACBITS; - } - numgbits = actualnumbps - (cp->ccps[cmptno].prec - 1 + - band->analgain); -#if 0 -fprintf(stderr, "%d %d mag=%d actual=%d numgbits=%d\n", cp->ccps[cmptno].prec, band->analgain, mxmag, actualnumbps, numgbits); -#endif - if (numgbits > mingbits) { - mingbits = numgbits; - } - if (!tile->intmode) { - band->absstepsize = jpc_fix_div(jpc_inttofix(1 - << (band->analgain + 1)), - band->synweight); - } else { - band->absstepsize = jpc_inttofix(1); - } - band->stepsize = jpc_abstorelstepsize( - band->absstepsize, cp->ccps[cmptno].prec + - band->analgain); - band->numbps = cp->tccp.numgbits + - JPC_QCX_GETEXPN(band->stepsize) - 1; - - if ((!tile->intmode) && band->data) { - quantize(band->data, band->absstepsize); - } - - comp->stepsizes[absbandno] = band->stepsize; - ++absbandno; - } - } - - assert(JPC_FIX_FRACBITS >= JPC_NUMEXTRABITS); - if (!tile->intmode) { - jas_matrix_divpow2(comp->data, JPC_FIX_FRACBITS - JPC_NUMEXTRABITS); - } else { - jas_matrix_asl(comp->data, JPC_NUMEXTRABITS); - } - } -#if 0 -fprintf(stderr, "mingbits %d\n", mingbits); -#endif +assert(enc->tmpstream); + if (jpc_enc_encpkts(enc, enc->tmpstream)) { + return -1; + } + return 0; +} - if (mingbits > cp->tccp.numgbits) { - fprintf(stderr, "error: too few guard bits (need at least %d)\n", - mingbits); - return -1; - } - - if (!(enc->tmpstream = jas_stream_memopen(0, 0))) { - fprintf(stderr, "cannot open tmp file\n"); - return -1; - } - - /* Write the tile header. */ - if (!(enc->mrk = jpc_ms_create(JPC_MS_SOT))) { - return -1; - } - sot = &enc->mrk->parms.sot; - sot->len = 0; - sot->tileno = tileno; - sot->partno = 0; - sot->numparts = 1; - if (jpc_putms(enc->tmpstream, enc->cstate, enc->mrk)) { - fprintf(stderr, "cannot write SOT marker\n"); - return -1; - } - jpc_ms_destroy(enc->mrk); - enc->mrk = 0; +void quantize(jas_matrix_t *data, jpc_fix_t stepsize) +{ + int i; + int j; + jpc_fix_t t; -/************************************************************************/ -/************************************************************************/ -/************************************************************************/ + if (stepsize == jpc_inttofix(1)) { + return; + } - tccp = &cp->tccp; - for (cmptno = 0; cmptno < cp->numcmpts; ++cmptno) { - comp = &tile->tcmpts[cmptno]; - if (comp->numrlvls != tccp->maxrlvls) { - if (!(enc->mrk = jpc_ms_create(JPC_MS_COD))) { - return -1; - } -/* XXX = this is not really correct. we are using comp #0's precint sizes -and other characteristics */ - comp = &tile->tcmpts[0]; - cod = &enc->mrk->parms.cod; - cod->compparms.csty = 0; - cod->compparms.numdlvls = comp->numrlvls - 1; - cod->prg = tile->prg; - cod->numlyrs = tile->numlyrs; - cod->compparms.cblkwidthval = JPC_COX_CBLKSIZEEXPN(comp->cblkwidthexpn); - cod->compparms.cblkheightval = JPC_COX_CBLKSIZEEXPN(comp->cblkheightexpn); - cod->compparms.cblksty = comp->cblksty; - cod->compparms.qmfbid = comp->qmfbid; - cod->mctrans = (tile->mctid != JPC_MCT_NONE); - for (i = 0; i < comp->numrlvls; ++i) { - cod->compparms.rlvls[i].parwidthval = comp->rlvls[i].prcwidthexpn; - cod->compparms.rlvls[i].parheightval = comp->rlvls[i].prcheightexpn; - } - if (jpc_putms(enc->tmpstream, enc->cstate, enc->mrk)) { - return -1; - } - jpc_ms_destroy(enc->mrk); - enc->mrk = 0; - } - } - - for (cmptno = 0, comp = tile->tcmpts; cmptno < cp->numcmpts; ++cmptno, ++comp) { - ccps = &cp->ccps[cmptno]; - if (ccps->numstepsizes == comp->numstepsizes) { - samestepsizes = 1; - for (bandno = 0; bandno < ccps->numstepsizes; ++bandno) { - if (ccps->stepsizes[bandno] != comp->stepsizes[bandno]) { - samestepsizes = 0; - break; - } - } - } else { - samestepsizes = 0; - } - if (!samestepsizes) { - if (!(enc->mrk = jpc_ms_create(JPC_MS_QCC))) { - return -1; - } - qcc = &enc->mrk->parms.qcc; - qcc->compno = cmptno; - qcc->compparms.numguard = cp->tccp.numgbits; - qcc->compparms.qntsty = (comp->qmfbid == JPC_COX_INS) ? - JPC_QCX_SEQNT : JPC_QCX_NOQNT; - qcc->compparms.numstepsizes = comp->numstepsizes; - qcc->compparms.stepsizes = comp->stepsizes; - if (jpc_putms(enc->tmpstream, enc->cstate, enc->mrk)) { - return -1; - } - qcc->compparms.stepsizes = 0; - jpc_ms_destroy(enc->mrk); - enc->mrk = 0; - } - } - - /* Write a SOD marker to indicate the end of the tile header. */ - if (!(enc->mrk = jpc_ms_create(JPC_MS_SOD))) { - return -1; - } - if (jpc_putms(enc->tmpstream, enc->cstate, enc->mrk)) { - fprintf(stderr, "cannot write SOD marker\n"); - return -1; - } - jpc_ms_destroy(enc->mrk); - enc->mrk = 0; -tilehdrlen = jas_stream_getrwcount(enc->tmpstream); + for (i = 0; i < jas_matrix_numrows(data); ++i) { + for (j = 0; j < jas_matrix_numcols(data); ++j) { + t = jas_matrix_get(data, i, j); -/************************************************************************/ -/************************************************************************/ -/************************************************************************/ +{ + if (t < 0) { + t = jpc_fix_neg(jpc_fix_div(jpc_fix_neg(t), stepsize)); + } else { + t = jpc_fix_div(t, stepsize); + } +} -if (jpc_enc_enccblks(enc)) { - abort(); - return -1; + jas_matrix_set(data, i, j, t); + } + } } - cp = enc->cp; - rho = (double) (tile->brx - tile->tlx) * (tile->bry - tile->tly) / - ((cp->refgrdwidth - cp->imgareatlx) * (cp->refgrdheight - - cp->imgareatly)); - tile->rawsize = cp->rawsize * rho; - - for (lyrno = 0; lyrno < tile->numlyrs - 1; ++lyrno) { - tile->lyrsizes[lyrno] = tile->rawsize * jpc_fixtodbl( - cp->tcp.ilyrrates[lyrno]); - } - tile->lyrsizes[tile->numlyrs - 1] = (cp->totalsize != UINT_FAST32_MAX) ? - (rho * enc->mainbodysize) : UINT_FAST32_MAX; - for (lyrno = 0; lyrno < tile->numlyrs; ++lyrno) { - if (tile->lyrsizes[lyrno] != UINT_FAST32_MAX) { - if (tilehdrlen <= tile->lyrsizes[lyrno]) { - tile->lyrsizes[lyrno] -= tilehdrlen; - } else { - tile->lyrsizes[lyrno] = 0; - } - } - } - - if (rateallocate(enc, tile->numlyrs, tile->lyrsizes)) { - return -1; - } +static void calcrdslopes(jpc_enc_cblk_t *cblk) +{ + jpc_enc_pass_t *endpasses; + jpc_enc_pass_t *pass0; + jpc_enc_pass_t *pass1; + jpc_enc_pass_t *pass2; + jpc_flt_t slope0; + jpc_flt_t slope; + jpc_flt_t dd; + long dr; + + endpasses = &cblk->passes[cblk->numpasses]; + pass2 = cblk->passes; + slope0 = 0; + while (pass2 != endpasses) { + pass0 = 0; + for (pass1 = cblk->passes; pass1 != endpasses; ++pass1) { + dd = pass1->cumwmsedec; + dr = pass1->end; + if (pass0) { + dd -= pass0->cumwmsedec; + dr -= pass0->end; + } + if (dd <= 0) { + pass1->rdslope = JPC_BADRDSLOPE; + if (pass1 >= pass2) { + pass2 = &pass1[1]; + } + continue; + } + if (pass1 < pass2 && pass1->rdslope <= 0) { + continue; + } + if (!dr) { + assert(pass0); + pass0->rdslope = 0; + break; + } + slope = dd / dr; + if (pass0 && slope >= slope0) { + pass0->rdslope = 0; + break; + } + pass1->rdslope = slope; + if (pass1 >= pass2) { + pass2 = &pass1[1]; + } + pass0 = pass1; + slope0 = slope; + } + } #if 0 -fprintf(stderr, "ENCODE TILE DATA\n"); + for (pass0 = cblk->passes; pass0 != endpasses; ++pass0) { +if (pass0->rdslope > 0.0) { + fprintf(stderr, "pass %02d nmsedec=%lf dec=%lf end=%d %lf\n", pass0 - cblk->passes, + fixtodbl(pass0->nmsedec), pass0->wmsedec, pass0->end, pass0->rdslope); +} + } #endif - if (jpc_enc_encodetiledata(enc)) { - fprintf(stderr, "dotile failed\n"); - return -1; - } +} -/************************************************************************/ -/************************************************************************/ -/************************************************************************/ -/************************************************************************/ -/************************************************************************/ -/************************************************************************/ - tilelen = jas_stream_tell(enc->tmpstream); +static void +traceLayerSizes(const uint_fast32_t * const lyrSizes, + unsigned int const layerCt) { + + if (jas_getdbglevel() > 0) { + unsigned int i; + for (i = 0; i < layerCt; ++i) { + fprintf(stderr, "Layer %u size = ", i); - if (jas_stream_seek(enc->tmpstream, 6, SEEK_SET) < 0) { - return -1; - } - jpc_putuint32(enc->tmpstream, tilelen); + if (lyrSizes[i] == UINT_FAST32_MAX) + fprintf(stderr, "Unlimited"); + else + fprintf(stderr, "%u", (unsigned)lyrSizes[i]); + fprintf(stderr, "\n"); + } + } +} - if (jas_stream_seek(enc->tmpstream, 0, SEEK_SET) < 0) { - return -1; - } - if (jpc_putdata(enc->out, enc->tmpstream, -1)) { - return -1; - } - enc->len += tilelen; - jas_stream_close(enc->tmpstream); - enc->tmpstream = 0; - jpc_enc_tile_destroy(enc->curtile); - enc->curtile = 0; +static void +computeLayerSizes(jpc_enc_t * const encP, + jpc_enc_tile_t * const tileP, + jpc_enc_cp_t * const cpP, + double const rho, + long const tilehdrlen, + const char ** const errorP) { - } + /* Note that in allowed sizes, UINT_FAST32_MAX is a special value meaning + "unlimited". + */ - return 0; -} + unsigned int const lastLyrno = tileP->numlyrs - 1; -int jpc_enc_encodetiledata(jpc_enc_t *enc) -{ -assert(enc->tmpstream); - if (jpc_enc_encpkts(enc, enc->tmpstream)) { - return -1; - } - return 0; -} + unsigned int lyrno; -void quantize(jas_matrix_t *data, jpc_fix_t stepsize) -{ - int i; - int j; - jpc_fix_t t; + assert(tileP->numlyrs > 0); - if (stepsize == jpc_inttofix(1)) { - return; - } + for (lyrno = 0; lyrno < lastLyrno; ++lyrno) { + tileP->lyrsizes[lyrno] = tileP->rawsize * jpc_fixtodbl( + cpP->tcp.ilyrrates[lyrno]); + } - for (i = 0; i < jas_matrix_numrows(data); ++i) { - for (j = 0; j < jas_matrix_numcols(data); ++j) { - t = jas_matrix_get(data, i, j); + tileP->lyrsizes[lastLyrno] = + (cpP->totalsize != UINT_FAST32_MAX) ? + (rho * encP->mainbodysize) : UINT_FAST32_MAX; -{ - if (t < 0) { - t = jpc_fix_neg(jpc_fix_div(jpc_fix_neg(t), stepsize)); - } else { - t = jpc_fix_div(t, stepsize); - } -} - jas_matrix_set(data, i, j, t); - } - } + /* Subtract 'tilehdrlen' from every layer. */ + + for (lyrno = 0; lyrno < tileP->numlyrs; ++lyrno) { + if (tileP->lyrsizes[lyrno] != UINT_FAST32_MAX) { + if (tilehdrlen <= tileP->lyrsizes[lyrno]) { + tileP->lyrsizes[lyrno] -= tilehdrlen; + } else { + tileP->lyrsizes[lyrno] = 0; + } + } + } + + if (tileP->lyrsizes[lastLyrno] < 1) + pm_asprintf(errorP, "Cannot make image that small (%u bytes). " + "Even with pixels compressed as far as possible, metadata " + "would exceed the limit", + (unsigned)cpP->totalsize); + else + *errorP = NULL; + + traceLayerSizes(tileP->lyrsizes, tileP->numlyrs); } -static void calcrdslopes(jpc_enc_cblk_t *cblk) + + +static void dump_layeringinfo(jpc_enc_t *enc) { - jpc_enc_pass_t *endpasses; - jpc_enc_pass_t *pass0; - jpc_enc_pass_t *pass1; - jpc_enc_pass_t *pass2; - jpc_flt_t slope0; - jpc_flt_t slope; - jpc_flt_t dd; - long dr; - - endpasses = &cblk->passes[cblk->numpasses]; - pass2 = cblk->passes; - slope0 = 0; - while (pass2 != endpasses) { - pass0 = 0; - for (pass1 = cblk->passes; pass1 != endpasses; ++pass1) { - dd = pass1->cumwmsedec; - dr = pass1->end; - if (pass0) { - dd -= pass0->cumwmsedec; - dr -= pass0->end; - } - if (dd <= 0) { - pass1->rdslope = JPC_BADRDSLOPE; - if (pass1 >= pass2) { - pass2 = &pass1[1]; - } - continue; - } - if (pass1 < pass2 && pass1->rdslope <= 0) { - continue; - } - if (!dr) { - assert(pass0); - pass0->rdslope = 0; - break; - } - slope = dd / dr; - if (pass0 && slope >= slope0) { - pass0->rdslope = 0; - break; - } - pass1->rdslope = slope; - if (pass1 >= pass2) { - pass2 = &pass1[1]; - } - pass0 = pass1; - slope0 = slope; - } - } -#if 0 - for (pass0 = cblk->passes; pass0 != endpasses; ++pass0) { -if (pass0->rdslope > 0.0) { - fprintf(stderr, "pass %02d nmsedec=%lf dec=%lf end=%d %lf\n", pass0 - cblk->passes, - fixtodbl(pass0->nmsedec), pass0->wmsedec, pass0->end, pass0->rdslope); + jpc_enc_tcmpt_t *tcmpt; + uint_fast16_t tcmptno; + jpc_enc_rlvl_t *rlvl; + uint_fast16_t rlvlno; + jpc_enc_band_t *band; + uint_fast16_t bandno; + jpc_enc_prc_t *prc; + uint_fast32_t prcno; + jpc_enc_cblk_t *cblk; + uint_fast16_t cblkno; + jpc_enc_pass_t *pass; + uint_fast16_t passno; + int lyrno; + jpc_enc_tile_t *tile; + + tile = enc->curtile; + + for (lyrno = 0; lyrno < tile->numlyrs; ++lyrno) { + fprintf(stderr, "lyrno = %02d\n", lyrno); + for (tcmptno = 0, tcmpt = tile->tcmpts; tcmptno < tile->numtcmpts; + ++tcmptno, ++tcmpt) { + for (rlvlno = 0, rlvl = tcmpt->rlvls; rlvlno < tcmpt->numrlvls; + ++rlvlno, ++rlvl) { + if (!rlvl->bands) { + continue; + } + for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands; + ++bandno, ++band) { + if (!band->data) { + continue; + } + for (prcno = 0, prc = band->prcs; prcno < rlvl->numprcs; + ++prcno, ++prc) { + if (!prc->cblks) { + continue; + } + for (cblkno = 0, cblk = prc->cblks; cblkno < + prc->numcblks; ++cblkno, ++cblk) { + for (passno = 0, pass = cblk->passes; + passno < cblk->numpasses && + pass->lyrno == lyrno; + ++passno, ++pass) { + fprintf(stderr, + "lyrno=%02d cmptno=%02d " + "rlvlno=%02d bandno=%02d " + "prcno=%02d cblkno=%03d " + "passno=%03d\n", + lyrno, (int)tcmptno, (int)rlvlno, + (int)bandno, (int)prcno, (int) cblkno, + (int)passno); + } + } + } + } + } + } + } } - } -#endif + + + + +static void +trace_layeringinfo(jpc_enc_t * const encP) { + + if (jas_getdbglevel() >= 5) + dump_layeringinfo(encP); } -static void dump_layeringinfo(jpc_enc_t *enc) -{ - jpc_enc_tcmpt_t *tcmpt; - uint_fast16_t tcmptno; - jpc_enc_rlvl_t *rlvl; - uint_fast16_t rlvlno; - jpc_enc_band_t *band; - uint_fast16_t bandno; - jpc_enc_prc_t *prc; - uint_fast32_t prcno; - jpc_enc_cblk_t *cblk; - uint_fast16_t cblkno; - jpc_enc_pass_t *pass; - uint_fast16_t passno; - int lyrno; - jpc_enc_tile_t *tile; - - tile = enc->curtile; - - for (lyrno = 0; lyrno < tile->numlyrs; ++lyrno) { - fprintf(stderr, "lyrno = %02d\n", lyrno); - for (tcmptno = 0, tcmpt = tile->tcmpts; tcmptno < tile->numtcmpts; - ++tcmptno, ++tcmpt) { - for (rlvlno = 0, rlvl = tcmpt->rlvls; rlvlno < tcmpt->numrlvls; - ++rlvlno, ++rlvl) { - if (!rlvl->bands) { - continue; - } - for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands; - ++bandno, ++band) { - if (!band->data) { - continue; - } - for (prcno = 0, prc = band->prcs; prcno < rlvl->numprcs; - ++prcno, ++prc) { - if (!prc->cblks) { - continue; - } - for (cblkno = 0, cblk = prc->cblks; cblkno < - prc->numcblks; ++cblkno, ++cblk) { - for (passno = 0, pass = cblk->passes; passno < - cblk->numpasses && pass->lyrno == lyrno; - ++passno, ++pass) { - fprintf(stderr, "lyrno=%02d cmptno=%02d rlvlno=%02d bandno=%02d prcno=%02d cblkno=%03d passno=%03d\n", lyrno, tcmptno, rlvlno, bandno, prcno, cblkno, passno); - } - } - } - } - } - } - } + +static void +validateCumlensIncreases(const uint_fast32_t * const cumlens, + unsigned int const numlyrs) { + unsigned int lyrno; + + for (lyrno = 1; lyrno < numlyrs - 1; ++lyrno) { + if (cumlens[lyrno - 1] > cumlens[lyrno]) { + abort(); + } + } } -int rateallocate(jpc_enc_t *enc, int numlyrs, uint_fast32_t *cumlens) -{ - jpc_flt_t lo; - jpc_flt_t hi; - jas_stream_t *out; - long cumlen; - int lyrno; - jpc_flt_t thresh; - jpc_flt_t goodthresh; - int success; - long pos; - long oldpos; - int numiters; - - jpc_enc_tcmpt_t *comp; - jpc_enc_tcmpt_t *endcomps; - jpc_enc_rlvl_t *lvl; - jpc_enc_rlvl_t *endlvls; - jpc_enc_band_t *band; - jpc_enc_band_t *endbands; - jpc_enc_cblk_t *cblk; - jpc_enc_cblk_t *endcblks; - jpc_enc_pass_t *pass; - jpc_enc_pass_t *endpasses; - jpc_enc_pass_t *pass1; - jpc_flt_t mxrdslope; - jpc_flt_t mnrdslope; - jpc_enc_tile_t *tile; - jpc_enc_prc_t *prc; - uint_fast32_t prcno; - - tile = enc->curtile; - - for (lyrno = 1; lyrno < numlyrs - 1; ++lyrno) { - if (cumlens[lyrno - 1] > cumlens[lyrno]) { - abort(); - } - } - - if (!(out = jas_stream_memopen(0, 0))) { - return -1; - } - - - /* Find minimum and maximum R-D slope values. */ - mnrdslope = DBL_MAX; - mxrdslope = 0; - endcomps = &tile->tcmpts[tile->numtcmpts]; - for (comp = tile->tcmpts; comp != endcomps; ++comp) { - endlvls = &comp->rlvls[comp->numrlvls]; - for (lvl = comp->rlvls; lvl != endlvls; ++lvl) { - if (!lvl->bands) { - continue; - } - endbands = &lvl->bands[lvl->numbands]; - for (band = lvl->bands; band != endbands; ++band) { - if (!band->data) { - continue; - } - for (prcno = 0, prc = band->prcs; prcno < lvl->numprcs; ++prcno, ++prc) { - if (!prc->cblks) { - continue; - } - endcblks = &prc->cblks[prc->numcblks]; - for (cblk = prc->cblks; cblk != endcblks; ++cblk) { - calcrdslopes(cblk); - endpasses = &cblk->passes[cblk->numpasses]; - for (pass = cblk->passes; pass != endpasses; ++pass) { - if (pass->rdslope > 0) { - if (pass->rdslope < mnrdslope) { - mnrdslope = pass->rdslope; - } - if (pass->rdslope > mxrdslope) { - mxrdslope = pass->rdslope; - } - } - } - } - } - } - } - } -if (jas_getdbglevel()) { - fprintf(stderr, "min rdslope = %f max rdslope = %f\n", mnrdslope, mxrdslope); + + +static void +findMinMaxRDSlopeValues(jpc_enc_tile_t * const tileP, + jpc_flt_t * const mnrdslopeP, + jpc_flt_t * const mxrdslopeP) { +/*---------------------------------------------------------------------------- + Find minimum and maximum R-D slope values. +-----------------------------------------------------------------------------*/ + jpc_flt_t mxrdslope; + jpc_flt_t mnrdslope; + jpc_enc_tcmpt_t * endcomps; + jpc_enc_tcmpt_t * compP; + + mnrdslope = DBL_MAX; + mxrdslope = 0; + endcomps = &tileP->tcmpts[tileP->numtcmpts]; + + for (compP = tileP->tcmpts; compP != endcomps; ++compP) { + jpc_enc_rlvl_t * const endlvlsP = &compP->rlvls[compP->numrlvls]; + + jpc_enc_rlvl_t * lvlP; + + for (lvlP = compP->rlvls; lvlP != endlvlsP; ++lvlP) { + jpc_enc_band_t * endbandsP; + jpc_enc_band_t * bandP; + + if (lvlP->bands) { + endbandsP = &lvlP->bands[lvlP->numbands]; + for (bandP = lvlP->bands; bandP != endbandsP; ++bandP) { + uint_fast32_t prcno; + jpc_enc_prc_t * prcP; + + if (bandP->data) { + for (prcno = 0, prcP = bandP->prcs; + prcno < lvlP->numprcs; + ++prcno, ++prcP) { + + jpc_enc_cblk_t * endcblksP; + jpc_enc_cblk_t * cblkP; + + if (prcP->cblks) { + endcblksP = &prcP->cblks[prcP->numcblks]; + for (cblkP = prcP->cblks; + cblkP != endcblksP; + ++cblkP) { + jpc_enc_pass_t * endpassesP; + jpc_enc_pass_t * passP; + + calcrdslopes(cblkP); + endpassesP = + &cblkP->passes[cblkP->numpasses]; + for (passP = cblkP->passes; + passP != endpassesP; + ++passP) { + if (passP->rdslope > 0) { + mnrdslope = + MIN(passP->rdslope, mnrdslope); + mxrdslope = + MAX(passP->rdslope, mxrdslope); + } + } + } + } + } + } + } + } + } + } + trace("min rdslope = %f max rdslope = %f", mnrdslope, mxrdslope); + + *mnrdslopeP = mnrdslope; + *mxrdslopeP = mxrdslope; } - jpc_init_t2state(enc, 1); - - for (lyrno = 0; lyrno < numlyrs; ++lyrno) { - - lo = mnrdslope; - hi = mxrdslope; - - success = 0; - goodthresh = 0; - numiters = 0; - - do { - - cumlen = cumlens[lyrno]; - if (cumlen == UINT_FAST32_MAX) { - /* Only the last layer can be free of a rate - constraint (e.g., for lossless coding). */ - assert(lyrno == numlyrs - 1); - goodthresh = -1; - success = 1; - break; - } - - thresh = (lo + hi) / 2; - - /* Save the tier 2 coding state. */ - jpc_save_t2state(enc); - oldpos = jas_stream_tell(out); - assert(oldpos >= 0); - - /* Assign all passes with R-D slopes greater than or - equal to the current threshold to this layer. */ - endcomps = &tile->tcmpts[tile->numtcmpts]; - for (comp = tile->tcmpts; comp != endcomps; ++comp) { - endlvls = &comp->rlvls[comp->numrlvls]; - for (lvl = comp->rlvls; lvl != endlvls; ++lvl) { - if (!lvl->bands) { - continue; - } - endbands = &lvl->bands[lvl->numbands]; - for (band = lvl->bands; band != endbands; ++band) { - if (!band->data) { - continue; - } - for (prcno = 0, prc = band->prcs; prcno < lvl->numprcs; ++prcno, ++prc) { - if (!prc->cblks) { - continue; - } - endcblks = &prc->cblks[prc->numcblks]; - for (cblk = prc->cblks; cblk != endcblks; ++cblk) { - if (cblk->curpass) { - endpasses = &cblk->passes[cblk->numpasses]; - pass1 = cblk->curpass; - for (pass = cblk->curpass; pass != endpasses; ++pass) { - if (pass->rdslope >= thresh) { - pass1 = &pass[1]; - } - } - for (pass = cblk->curpass; pass != pass1; ++pass) { - pass->lyrno = lyrno; - } - for (; pass != endpasses; ++pass) { - pass->lyrno = -1; - } - } - } - } - } - } - } - - /* Perform tier 2 coding. */ - endcomps = &tile->tcmpts[tile->numtcmpts]; - for (comp = tile->tcmpts; comp != endcomps; ++comp) { - endlvls = &comp->rlvls[comp->numrlvls]; - for (lvl = comp->rlvls; lvl != endlvls; ++lvl) { - if (!lvl->bands) { - continue; - } - for (prcno = 0; prcno < lvl->numprcs; ++prcno) { - if (jpc_enc_encpkt(enc, out, comp - tile->tcmpts, lvl - comp->rlvls, prcno, lyrno)) { - return -1; - } - } - } - } - - pos = jas_stream_tell(out); - - /* Check the rate constraint. */ - assert(pos >= 0); - if (pos > cumlen) { - /* The rate is too high. */ - lo = thresh; - } else if (pos <= cumlen) { - /* The rate is low enough, so try higher. */ - hi = thresh; - if (!success || thresh < goodthresh) { - goodthresh = thresh; - success = 1; - } - } - - /* Save the tier 2 coding state. */ - jpc_restore_t2state(enc); - if (jas_stream_seek(out, oldpos, SEEK_SET) < 0) { - abort(); - } - -if (jas_getdbglevel()) { -fprintf(stderr, "maxlen=%08ld actuallen=%08ld thresh=%f\n", cumlen, pos, thresh); + + +static void +performTier2CodingOneLayer(jpc_enc_t * const encP, + jpc_enc_tile_t * const tileP, + unsigned int const lyrno, + jas_stream_t * const outP, + const char ** const errorP) { +/*---------------------------------------------------------------------------- + Encode Layer 'lyrno' of tile *tileP to stream *outP. + + Use the pass assignment already in *tileP. +-----------------------------------------------------------------------------*/ + jpc_enc_tcmpt_t * const endcompsP = &tileP->tcmpts[tileP->numtcmpts]; + + jpc_enc_tcmpt_t * compP; + + *errorP = NULL; /* initial assumption */ + + for (compP = tileP->tcmpts; compP != endcompsP && !*errorP; ++compP) { + jpc_enc_rlvl_t * const endlvlsP = &compP->rlvls[compP->numrlvls]; + + jpc_enc_rlvl_t * lvlP; + + for (lvlP = compP->rlvls; lvlP != endlvlsP && !*errorP; ++lvlP) { + if (lvlP->bands) { + uint_fast32_t prcno; + for (prcno = 0; prcno < lvlP->numprcs && !*errorP; ++prcno) { + int rc; + rc = jpc_enc_encpkt(encP, outP, compP - tileP->tcmpts, + lvlP - compP->rlvls, prcno, lyrno); + if (rc != 0) + pm_asprintf(errorP, "jpc_enc_encpkt() failed on " + "precinct %u", (unsigned)prcno); + } + } + } + } } - ++numiters; - } while (lo < hi - 1e-3 && numiters < 32); - if (!success) { - fprintf(stderr, "warning: empty layer generated\n"); - } -if (jas_getdbglevel()) { -fprintf(stderr, "success %d goodthresh %f\n", success, goodthresh); +static void +assignHighSlopePassesToLayer(jpc_enc_t * const encP, + jpc_enc_tile_t * const tileP, + unsigned int const lyrno, + bool const haveThresh, + jpc_flt_t const thresh) { +/*---------------------------------------------------------------------------- + Assign all passes with R-D slopes greater than or equal to 'thresh' to layer + 'lyrno' and the rest to no layer. + + If 'haveThresh' is false, assign all passes to no layer. +-----------------------------------------------------------------------------*/ + jpc_enc_tcmpt_t * endcompsP; + jpc_enc_tcmpt_t * compP; + + endcompsP = &tileP->tcmpts[tileP->numtcmpts]; + for (compP = tileP->tcmpts; compP != endcompsP; ++compP) { + jpc_enc_rlvl_t * const endlvlsP = &compP->rlvls[compP->numrlvls]; + + jpc_enc_rlvl_t * lvlP; + + for (lvlP = compP->rlvls; lvlP != endlvlsP; ++lvlP) { + if (lvlP->bands) { + jpc_enc_band_t * const endbandsP = + &lvlP->bands[lvlP->numbands]; + jpc_enc_band_t * bandP; + for (bandP = lvlP->bands; bandP != endbandsP; ++bandP) { + if (bandP->data) { + jpc_enc_prc_t * prcP; + uint_fast32_t prcno; + for (prcno = 0, prcP = bandP->prcs; + prcno < lvlP->numprcs; + ++prcno, ++prcP) { + if (prcP->cblks) { + jpc_enc_cblk_t * const endcblksP = + &prcP->cblks[prcP->numcblks]; + jpc_enc_cblk_t * cblkP; + for (cblkP = prcP->cblks; + cblkP != endcblksP; + ++cblkP) { + if (cblkP->curpass) { + jpc_enc_pass_t * const endpassesP = + &cblkP->passes[cblkP->numpasses]; + jpc_enc_pass_t * pass1P; + jpc_enc_pass_t * passP; + + pass1P = cblkP->curpass; + if (haveThresh) { + jpc_enc_pass_t * passP; + for (passP = cblkP->curpass; + passP != endpassesP; + ++passP) { + if (passP->rdslope >= thresh) + pass1P = passP + 1; + } + } + for (passP = cblkP->curpass; + passP != pass1P; + ++passP) { + passP->lyrno = lyrno; + } + for (; passP != endpassesP; ++passP) { + passP->lyrno = -1; + } + + } + } + } + } + } + } + } + } + } } - /* Assign all passes with R-D slopes greater than or - equal to the selected threshold to this layer. */ - endcomps = &tile->tcmpts[tile->numtcmpts]; - for (comp = tile->tcmpts; comp != endcomps; ++comp) { - endlvls = &comp->rlvls[comp->numrlvls]; - for (lvl = comp->rlvls; lvl != endlvls; ++lvl) { -if (!lvl->bands) { - continue; + + +static void +doLayer(jpc_enc_t * const encP, + jpc_enc_tile_t * const tileP, + unsigned int const lyrno, + uint_fast32_t const allowedSize, + jpc_flt_t const mnrdslope, + jpc_flt_t const mxrdslope, + jas_stream_t * const outP, + const char ** const errorP) { +/*---------------------------------------------------------------------------- + Assign passes to layer 'lyrno' such that the cumulative size through + this layer is as close as possible to, but not exceeding, 'allowedSize'. +-----------------------------------------------------------------------------*/ + bool haveGoodThresh; + jpc_flt_t goodThresh; + + if (allowedSize == UINT_FAST32_MAX) { + /* There's no rate constraint (This can be true of the last layer, + e.g. for lossless coding). */ + goodThresh = -1; + haveGoodThresh = true; + *errorP = NULL; + } else { + /* Iterate through successive approximations of the threshold, finding + the threshold that gets us closest to 'allowedSize' without going + over. In each iteration, we do the full encoding, note the size, + and then restore the previous state. + */ + long pos; + jpc_flt_t lo; + jpc_flt_t hi; + unsigned int numiters; + + lo = mnrdslope; /* initial value */ + hi = mxrdslope; /* initial value */ + numiters = 0; /* initial value */ + haveGoodThresh = false; /* initial value */ + goodThresh = 0; /* initial value */ + + do { + if (allowedSize == UINT_FAST32_MAX) { + /* There's no rate constraint (This can be true of the last + layer, e.g. for lossless coding). */ + goodThresh = -1; + haveGoodThresh = true; + } else { + jpc_flt_t const thresh = (lo + hi) / 2; + + int rc; + long oldpos; + + /* Save the tier 2 coding state. */ + jpc_save_t2state(encP); + oldpos = jas_stream_tell(outP); + assert(oldpos >= 0); + + assignHighSlopePassesToLayer(encP, tileP, lyrno, true, thresh); + + performTier2CodingOneLayer(encP, tileP, lyrno, outP, errorP); + + if (!*errorP) { + pos = jas_stream_tell(outP); + + /* Check the rate constraint. */ + assert(pos >= 0); + if (pos > allowedSize) { + /* The rate is too high. */ + lo = thresh; + } else if (pos <= allowedSize) { + /* The rate is low enough, so try higher. */ + hi = thresh; + if (!haveGoodThresh || thresh < goodThresh) { + goodThresh = thresh; + haveGoodThresh = true; + } + } + } + /* Restore the tier 2 coding state. */ + jpc_restore_t2state(encP); + rc = jas_stream_seek(outP, oldpos, SEEK_SET); + if (rc < 0) + abort(); + + trace("iter %u: allowedlen=%08ld actuallen=%08ld thresh=%f", + numiters, allowedSize, pos, thresh); + } + ++numiters; + } while (lo < hi - 1e-3 && numiters < 32 && !*errorP); + } + + if (!*errorP) { + if (!haveGoodThresh) + fprintf(stderr, "warning: empty layer generated\n"); + + trace("haveGoodThresh %u goodthresh %f", haveGoodThresh, goodThresh); + + assignHighSlopePassesToLayer(encP, tileP, lyrno, + haveGoodThresh, goodThresh); + + performTier2CodingOneLayer(encP, tileP, lyrno, outP, errorP); + } } - endbands = &lvl->bands[lvl->numbands]; - for (band = lvl->bands; band != endbands; ++band) { - if (!band->data) { - continue; - } - for (prcno = 0, prc = band->prcs; prcno < lvl->numprcs; ++prcno, ++prc) { - if (!prc->cblks) { - continue; - } - endcblks = &prc->cblks[prc->numcblks]; - for (cblk = prc->cblks; cblk != endcblks; ++cblk) { - if (cblk->curpass) { - endpasses = &cblk->passes[cblk->numpasses]; - pass1 = cblk->curpass; - if (success) { - for (pass = cblk->curpass; pass != endpasses; ++pass) { - if (pass->rdslope >= goodthresh) { - pass1 = &pass[1]; - } - } - } - for (pass = cblk->curpass; pass != pass1; ++pass) { - pass->lyrno = lyrno; - } - for (; pass != endpasses; ++pass) { - pass->lyrno = -1; - } - } - } - } - } - } - } - - /* Perform tier 2 coding. */ - endcomps = &tile->tcmpts[tile->numtcmpts]; - for (comp = tile->tcmpts; comp != endcomps; ++comp) { - endlvls = &comp->rlvls[comp->numrlvls]; - for (lvl = comp->rlvls; lvl != endlvls; ++lvl) { - if (!lvl->bands) { - continue; - } - for (prcno = 0; prcno < lvl->numprcs; ++prcno) { - if (jpc_enc_encpkt(enc, out, comp - tile->tcmpts, lvl - comp->rlvls, prcno, lyrno)) { - return -1; - } - } - } - } - } - - if (jas_getdbglevel() >= 5) { - dump_layeringinfo(enc); - } - - jas_stream_close(out); - - JAS_DBGLOG(10, ("done doing rateallocation\n")); -#if 0 -fprintf(stderr, "DONE RATE ALLOCATE\n"); -#endif - return 0; + + +static void +performTier2Coding(jpc_enc_t * const encP, + unsigned int const numlyrs, + uint_fast32_t * const cumlens, + const char ** const errorP) { +/*---------------------------------------------------------------------------- + Encode in 'numlyrs' layers, such that at each layer L, the size is + cumlens[L]. +-----------------------------------------------------------------------------*/ + jpc_enc_tile_t * const tileP = encP->curtile; + + jas_stream_t * outP; + unsigned int lyrno; + jpc_flt_t mnrdslope; + jpc_flt_t mxrdslope; + + validateCumlensIncreases(cumlens, numlyrs); + + outP = jas_stream_memopen(0, 0); + + if (!outP) + pm_asprintf(errorP, "jas_stream_memopen() failed"); + else { + findMinMaxRDSlopeValues(tileP, &mnrdslope, &mxrdslope); + + jpc_init_t2state(encP, 1); + + for (lyrno = 0, *errorP = NULL; + lyrno < numlyrs && !*errorP; + ++lyrno) { + doLayer(encP, tileP, lyrno, cumlens[lyrno], + mnrdslope, mxrdslope, outP, errorP); + } + + if (!*errorP) { + trace_layeringinfo(encP); + + jas_stream_close(outP); + } + } + JAS_DBGLOG(10, ("done doing rateallocation\n")); } -/******************************************************************************\ +/*****************************************************************************\ * Tile constructors and destructors. -\******************************************************************************/ +\*****************************************************************************/ jpc_enc_tile_t *jpc_enc_tile_create(jpc_enc_cp_t *cp, jas_image_t *image, int tileno) { - jpc_enc_tile_t *tile; - uint_fast32_t htileno; - uint_fast32_t vtileno; - uint_fast16_t lyrno; - uint_fast16_t cmptno; - jpc_enc_tcmpt_t *tcmpt; - - if (!(tile = jas_malloc(sizeof(jpc_enc_tile_t)))) { - goto error; - } - - /* Initialize a few members used in error recovery. */ - tile->tcmpts = 0; - tile->lyrsizes = 0; - tile->numtcmpts = cp->numcmpts; - tile->pi = 0; - - tile->tileno = tileno; - htileno = tileno % cp->numhtiles; - vtileno = tileno / cp->numhtiles; - - /* Calculate the coordinates of the top-left and bottom-right - corners of the tile. */ - tile->tlx = JAS_MAX(cp->tilegrdoffx + htileno * cp->tilewidth, - cp->imgareatlx); - tile->tly = JAS_MAX(cp->tilegrdoffy + vtileno * cp->tileheight, - cp->imgareatly); - tile->brx = JAS_MIN(cp->tilegrdoffx + (htileno + 1) * cp->tilewidth, - cp->refgrdwidth); - tile->bry = JAS_MIN(cp->tilegrdoffy + (vtileno + 1) * cp->tileheight, - cp->refgrdheight); - - /* Initialize some tile coding parameters. */ - tile->intmode = cp->tcp.intmode; - tile->csty = cp->tcp.csty; - tile->prg = cp->tcp.prg; - tile->mctid = cp->tcp.mctid; - - tile->numlyrs = cp->tcp.numlyrs; - if (!(tile->lyrsizes = jas_malloc(tile->numlyrs * - sizeof(uint_fast32_t)))) { - goto error; - } - for (lyrno = 0; lyrno < tile->numlyrs; ++lyrno) { - tile->lyrsizes[lyrno] = 0; - } - - /* Allocate an array for the per-tile-component information. */ - if (!(tile->tcmpts = jas_malloc(cp->numcmpts * sizeof(jpc_enc_tcmpt_t)))) { - goto error; - } - /* Initialize a few members critical for error recovery. */ - for (cmptno = 0, tcmpt = tile->tcmpts; cmptno < cp->numcmpts; - ++cmptno, ++tcmpt) { - tcmpt->rlvls = 0; - tcmpt->tsfb = 0; - tcmpt->data = 0; - } - /* Initialize the per-tile-component information. */ - for (cmptno = 0, tcmpt = tile->tcmpts; cmptno < cp->numcmpts; - ++cmptno, ++tcmpt) { - if (!tcmpt_create(tcmpt, cp, image, tile)) { - goto error; - } - } - - /* Initialize the synthesis weights for the MCT. */ - switch (tile->mctid) { - case JPC_MCT_RCT: - tile->tcmpts[0].synweight = jpc_dbltofix(sqrt(3.0)); - tile->tcmpts[1].synweight = jpc_dbltofix(sqrt(0.6875)); - tile->tcmpts[2].synweight = jpc_dbltofix(sqrt(0.6875)); - break; - case JPC_MCT_ICT: - tile->tcmpts[0].synweight = jpc_dbltofix(sqrt(3.0000)); - tile->tcmpts[1].synweight = jpc_dbltofix(sqrt(3.2584)); - tile->tcmpts[2].synweight = jpc_dbltofix(sqrt(2.4755)); - break; - default: - case JPC_MCT_NONE: - for (cmptno = 0, tcmpt = tile->tcmpts; cmptno < cp->numcmpts; - ++cmptno, ++tcmpt) { - tcmpt->synweight = JPC_FIX_ONE; - } - break; - } - - if (!(tile->pi = jpc_enc_pi_create(cp, tile))) { - goto error; - } - - return tile; + jpc_enc_tile_t *tile; + uint_fast32_t htileno; + uint_fast32_t vtileno; + uint_fast16_t lyrno; + uint_fast16_t cmptno; + jpc_enc_tcmpt_t *tcmpt; + + if (!(tile = jas_malloc(sizeof(jpc_enc_tile_t)))) { + goto error; + } + + /* Initialize a few members used in error recovery. */ + tile->tcmpts = 0; + tile->lyrsizes = 0; + tile->numtcmpts = cp->numcmpts; + tile->pi = 0; + + tile->tileno = tileno; + htileno = tileno % cp->numhtiles; + vtileno = tileno / cp->numhtiles; + + /* Calculate the coordinates of the top-left and bottom-right + corners of the tile. */ + tile->tlx = JAS_MAX(cp->tilegrdoffx + htileno * cp->tilewidth, + cp->imgareatlx); + tile->tly = JAS_MAX(cp->tilegrdoffy + vtileno * cp->tileheight, + cp->imgareatly); + tile->brx = JAS_MIN(cp->tilegrdoffx + (htileno + 1) * cp->tilewidth, + cp->refgrdwidth); + tile->bry = JAS_MIN(cp->tilegrdoffy + (vtileno + 1) * cp->tileheight, + cp->refgrdheight); + + /* Initialize some tile coding parameters. */ + tile->intmode = cp->tcp.intmode; + tile->csty = cp->tcp.csty; + tile->prg = cp->tcp.prg; + tile->mctid = cp->tcp.mctid; + + tile->numlyrs = cp->tcp.numlyrs; + if (!(tile->lyrsizes = jas_malloc(tile->numlyrs * + sizeof(uint_fast32_t)))) { + goto error; + } + for (lyrno = 0; lyrno < tile->numlyrs; ++lyrno) { + tile->lyrsizes[lyrno] = 0; + } + + /* Allocate an array for the per-tile-component information. */ + if (!(tile->tcmpts = jas_malloc(cp->numcmpts * sizeof(jpc_enc_tcmpt_t)))) { + goto error; + } + /* Initialize a few members critical for error recovery. */ + for (cmptno = 0, tcmpt = tile->tcmpts; cmptno < cp->numcmpts; + ++cmptno, ++tcmpt) { + tcmpt->rlvls = 0; + tcmpt->tsfb = 0; + tcmpt->data = 0; + } + /* Initialize the per-tile-component information. */ + for (cmptno = 0, tcmpt = tile->tcmpts; cmptno < cp->numcmpts; + ++cmptno, ++tcmpt) { + if (!tcmpt_create(tcmpt, cp, image, tile)) { + goto error; + } + } + + /* Initialize the synthesis weights for the MCT. */ + switch (tile->mctid) { + case JPC_MCT_RCT: + tile->tcmpts[0].synweight = jpc_dbltofix(sqrt(3.0)); + tile->tcmpts[1].synweight = jpc_dbltofix(sqrt(0.6875)); + tile->tcmpts[2].synweight = jpc_dbltofix(sqrt(0.6875)); + break; + case JPC_MCT_ICT: + tile->tcmpts[0].synweight = jpc_dbltofix(sqrt(3.0000)); + tile->tcmpts[1].synweight = jpc_dbltofix(sqrt(3.2584)); + tile->tcmpts[2].synweight = jpc_dbltofix(sqrt(2.4755)); + break; + default: + case JPC_MCT_NONE: + for (cmptno = 0, tcmpt = tile->tcmpts; cmptno < cp->numcmpts; + ++cmptno, ++tcmpt) { + tcmpt->synweight = JPC_FIX_ONE; + } + break; + } + + if (!(tile->pi = jpc_enc_pi_create(cp, tile))) { + goto error; + } + + return tile; error: - if (tile) { - jpc_enc_tile_destroy(tile); - } - return 0; + if (tile) { + jpc_enc_tile_destroy(tile); + } + return 0; } void jpc_enc_tile_destroy(jpc_enc_tile_t *tile) { - jpc_enc_tcmpt_t *tcmpt; - uint_fast16_t cmptno; - - if (tile->tcmpts) { - for (cmptno = 0, tcmpt = tile->tcmpts; cmptno < - tile->numtcmpts; ++cmptno, ++tcmpt) { - tcmpt_destroy(tcmpt); - } - jas_free(tile->tcmpts); - } - if (tile->lyrsizes) { - jas_free(tile->lyrsizes); - } - if (tile->pi) { - jpc_pi_destroy(tile->pi); - } - jas_free(tile); + jpc_enc_tcmpt_t *tcmpt; + uint_fast16_t cmptno; + + if (tile->tcmpts) { + for (cmptno = 0, tcmpt = tile->tcmpts; cmptno < + tile->numtcmpts; ++cmptno, ++tcmpt) { + tcmpt_destroy(tcmpt); + } + jas_free(tile->tcmpts); + } + if (tile->lyrsizes) { + jas_free(tile->lyrsizes); + } + if (tile->pi) { + jpc_pi_destroy(tile->pi); + } + jas_free(tile); } static jpc_enc_tcmpt_t *tcmpt_create(jpc_enc_tcmpt_t *tcmpt, jpc_enc_cp_t *cp, jas_image_t *image, jpc_enc_tile_t *tile) { - uint_fast16_t cmptno; - uint_fast16_t rlvlno; - jpc_enc_rlvl_t *rlvl; - uint_fast32_t tlx; - uint_fast32_t tly; - uint_fast32_t brx; - uint_fast32_t bry; - uint_fast32_t cmpttlx; - uint_fast32_t cmpttly; - jpc_enc_ccp_t *ccp; - jpc_tsfb_band_t bandinfos[JPC_MAXBANDS]; - - tcmpt->tile = tile; - tcmpt->tsfb = 0; - tcmpt->data = 0; - tcmpt->rlvls = 0; - - /* Deduce the component number. */ - cmptno = tcmpt - tile->tcmpts; - - ccp = &cp->ccps[cmptno]; - - /* Compute the coordinates of the top-left and bottom-right - corners of this tile-component. */ - tlx = JPC_CEILDIV(tile->tlx, ccp->sampgrdstepx); - tly = JPC_CEILDIV(tile->tly, ccp->sampgrdstepy); - brx = JPC_CEILDIV(tile->brx, ccp->sampgrdstepx); - bry = JPC_CEILDIV(tile->bry, ccp->sampgrdstepy); - - /* Create a sequence to hold the tile-component sample data. */ - if (!(tcmpt->data = jas_seq2d_create(tlx, tly, brx, bry))) { - goto error; - } - - /* Get the image data associated with this tile-component. */ - cmpttlx = JPC_CEILDIV(cp->imgareatlx, ccp->sampgrdstepx); - cmpttly = JPC_CEILDIV(cp->imgareatly, ccp->sampgrdstepy); - if (jas_image_readcmpt(image, cmptno, tlx - cmpttlx, tly - cmpttly, - brx - tlx, bry - tly, tcmpt->data)) { - goto error; - } - - tcmpt->synweight = 0; - tcmpt->qmfbid = cp->tccp.qmfbid; - tcmpt->numrlvls = cp->tccp.maxrlvls; - tcmpt->numbands = 3 * tcmpt->numrlvls - 2; - if (!(tcmpt->tsfb = jpc_cod_gettsfb(tcmpt->qmfbid, tcmpt->numrlvls - 1))) { - goto error; - } - - for (rlvlno = 0; rlvlno < tcmpt->numrlvls; ++rlvlno) { - tcmpt->prcwidthexpns[rlvlno] = cp->tccp.prcwidthexpns[rlvlno]; - tcmpt->prcheightexpns[rlvlno] = cp->tccp.prcheightexpns[rlvlno]; - } - tcmpt->cblkwidthexpn = cp->tccp.cblkwidthexpn; - tcmpt->cblkheightexpn = cp->tccp.cblkheightexpn; - tcmpt->cblksty = cp->tccp.cblksty; - tcmpt->csty = cp->tccp.csty; - - tcmpt->numstepsizes = tcmpt->numbands; - assert(tcmpt->numstepsizes <= JPC_MAXBANDS); - memset(tcmpt->stepsizes, 0, sizeof(tcmpt->numstepsizes * - sizeof(uint_fast16_t))); - - /* Retrieve information about the various bands. */ - jpc_tsfb_getbands(tcmpt->tsfb, jas_seq2d_xstart(tcmpt->data), - jas_seq2d_ystart(tcmpt->data), jas_seq2d_xend(tcmpt->data), - jas_seq2d_yend(tcmpt->data), bandinfos); - - if (!(tcmpt->rlvls = jas_malloc(tcmpt->numrlvls * sizeof(jpc_enc_rlvl_t)))) { - goto error; - } - for (rlvlno = 0, rlvl = tcmpt->rlvls; rlvlno < tcmpt->numrlvls; - ++rlvlno, ++rlvl) { - rlvl->bands = 0; - rlvl->tcmpt = tcmpt; - } - for (rlvlno = 0, rlvl = tcmpt->rlvls; rlvlno < tcmpt->numrlvls; - ++rlvlno, ++rlvl) { - if (!rlvl_create(rlvl, cp, tcmpt, bandinfos)) { - goto error; - } - } - - return tcmpt; + uint_fast16_t cmptno; + uint_fast16_t rlvlno; + jpc_enc_rlvl_t *rlvl; + uint_fast32_t tlx; + uint_fast32_t tly; + uint_fast32_t brx; + uint_fast32_t bry; + uint_fast32_t cmpttlx; + uint_fast32_t cmpttly; + jpc_enc_ccp_t *ccp; + jpc_tsfb_band_t bandinfos[JPC_MAXBANDS]; + + tcmpt->tile = tile; + tcmpt->tsfb = 0; + tcmpt->data = 0; + tcmpt->rlvls = 0; + + /* Deduce the component number. */ + cmptno = tcmpt - tile->tcmpts; + + ccp = &cp->ccps[cmptno]; + + /* Compute the coordinates of the top-left and bottom-right + corners of this tile-component. */ + tlx = JPC_CEILDIV(tile->tlx, ccp->sampgrdstepx); + tly = JPC_CEILDIV(tile->tly, ccp->sampgrdstepy); + brx = JPC_CEILDIV(tile->brx, ccp->sampgrdstepx); + bry = JPC_CEILDIV(tile->bry, ccp->sampgrdstepy); + + /* Create a sequence to hold the tile-component sample data. */ + if (!(tcmpt->data = jas_seq2d_create(tlx, tly, brx, bry))) { + goto error; + } + + /* Get the image data associated with this tile-component. */ + cmpttlx = JPC_CEILDIV(cp->imgareatlx, ccp->sampgrdstepx); + cmpttly = JPC_CEILDIV(cp->imgareatly, ccp->sampgrdstepy); + if (jas_image_readcmpt(image, cmptno, tlx - cmpttlx, tly - cmpttly, + brx - tlx, bry - tly, tcmpt->data)) { + goto error; + } + + tcmpt->synweight = 0; + tcmpt->qmfbid = cp->tccp.qmfbid; + tcmpt->numrlvls = cp->tccp.maxrlvls; + tcmpt->numbands = 3 * tcmpt->numrlvls - 2; + if (!(tcmpt->tsfb = jpc_cod_gettsfb(tcmpt->qmfbid, tcmpt->numrlvls - 1))) { + goto error; + } + + for (rlvlno = 0; rlvlno < tcmpt->numrlvls; ++rlvlno) { + tcmpt->prcwidthexpns[rlvlno] = cp->tccp.prcwidthexpns[rlvlno]; + tcmpt->prcheightexpns[rlvlno] = cp->tccp.prcheightexpns[rlvlno]; + } + tcmpt->cblkwidthexpn = cp->tccp.cblkwidthexpn; + tcmpt->cblkheightexpn = cp->tccp.cblkheightexpn; + tcmpt->cblksty = cp->tccp.cblksty; + tcmpt->csty = cp->tccp.csty; + + tcmpt->numstepsizes = tcmpt->numbands; + assert(tcmpt->numstepsizes <= JPC_MAXBANDS); + memset(tcmpt->stepsizes, 0, sizeof(tcmpt->numstepsizes * + sizeof(uint_fast16_t))); + + /* Retrieve information about the various bands. */ + jpc_tsfb_getbands(tcmpt->tsfb, jas_seq2d_xstart(tcmpt->data), + jas_seq2d_ystart(tcmpt->data), jas_seq2d_xend(tcmpt->data), + jas_seq2d_yend(tcmpt->data), bandinfos); + + if (!(tcmpt->rlvls = jas_malloc(tcmpt->numrlvls * sizeof(jpc_enc_rlvl_t)))) { + goto error; + } + for (rlvlno = 0, rlvl = tcmpt->rlvls; rlvlno < tcmpt->numrlvls; + ++rlvlno, ++rlvl) { + rlvl->bands = 0; + rlvl->tcmpt = tcmpt; + } + for (rlvlno = 0, rlvl = tcmpt->rlvls; rlvlno < tcmpt->numrlvls; + ++rlvlno, ++rlvl) { + if (!rlvl_create(rlvl, cp, tcmpt, bandinfos)) { + goto error; + } + } + + return tcmpt; error: - tcmpt_destroy(tcmpt); - return 0; + tcmpt_destroy(tcmpt); + return 0; } static void tcmpt_destroy(jpc_enc_tcmpt_t *tcmpt) { - jpc_enc_rlvl_t *rlvl; - uint_fast16_t rlvlno; - - if (tcmpt->rlvls) { - for (rlvlno = 0, rlvl = tcmpt->rlvls; rlvlno < tcmpt->numrlvls; - ++rlvlno, ++rlvl) { - rlvl_destroy(rlvl); - } - jas_free(tcmpt->rlvls); - } - - if (tcmpt->data) { - jas_seq2d_destroy(tcmpt->data); - } - if (tcmpt->tsfb) { - jpc_tsfb_destroy(tcmpt->tsfb); - } + jpc_enc_rlvl_t *rlvl; + uint_fast16_t rlvlno; + + if (tcmpt->rlvls) { + for (rlvlno = 0, rlvl = tcmpt->rlvls; rlvlno < tcmpt->numrlvls; + ++rlvlno, ++rlvl) { + rlvl_destroy(rlvl); + } + jas_free(tcmpt->rlvls); + } + + if (tcmpt->data) { + jas_seq2d_destroy(tcmpt->data); + } + if (tcmpt->tsfb) { + jpc_tsfb_destroy(tcmpt->tsfb); + } } static jpc_enc_rlvl_t *rlvl_create(jpc_enc_rlvl_t *rlvl, jpc_enc_cp_t *cp, jpc_enc_tcmpt_t *tcmpt, jpc_tsfb_band_t *bandinfos) { - uint_fast16_t rlvlno; - uint_fast32_t tlprctlx; - uint_fast32_t tlprctly; - uint_fast32_t brprcbrx; - uint_fast32_t brprcbry; - uint_fast16_t bandno; - jpc_enc_band_t *band; - - /* Deduce the resolution level. */ - rlvlno = rlvl - tcmpt->rlvls; - - /* Initialize members required for error recovery. */ - rlvl->bands = 0; - rlvl->tcmpt = tcmpt; - - /* Compute the coordinates of the top-left and bottom-right - corners of the tile-component at this resolution. */ - rlvl->tlx = JPC_CEILDIVPOW2(jas_seq2d_xstart(tcmpt->data), tcmpt->numrlvls - - 1 - rlvlno); - rlvl->tly = JPC_CEILDIVPOW2(jas_seq2d_ystart(tcmpt->data), tcmpt->numrlvls - - 1 - rlvlno); - rlvl->brx = JPC_CEILDIVPOW2(jas_seq2d_xend(tcmpt->data), tcmpt->numrlvls - - 1 - rlvlno); - rlvl->bry = JPC_CEILDIVPOW2(jas_seq2d_yend(tcmpt->data), tcmpt->numrlvls - - 1 - rlvlno); - - if (rlvl->tlx >= rlvl->brx || rlvl->tly >= rlvl->bry) { - rlvl->numhprcs = 0; - rlvl->numvprcs = 0; - rlvl->numprcs = 0; - return rlvl; - } - - rlvl->numbands = (!rlvlno) ? 1 : 3; - rlvl->prcwidthexpn = cp->tccp.prcwidthexpns[rlvlno]; - rlvl->prcheightexpn = cp->tccp.prcheightexpns[rlvlno]; - if (!rlvlno) { - rlvl->cbgwidthexpn = rlvl->prcwidthexpn; - rlvl->cbgheightexpn = rlvl->prcheightexpn; - } else { - rlvl->cbgwidthexpn = rlvl->prcwidthexpn - 1; - rlvl->cbgheightexpn = rlvl->prcheightexpn - 1; - } - rlvl->cblkwidthexpn = JAS_MIN(cp->tccp.cblkwidthexpn, rlvl->cbgwidthexpn); - rlvl->cblkheightexpn = JAS_MIN(cp->tccp.cblkheightexpn, rlvl->cbgheightexpn); - - /* Compute the number of precincts. */ - tlprctlx = JPC_FLOORTOMULTPOW2(rlvl->tlx, rlvl->prcwidthexpn); - tlprctly = JPC_FLOORTOMULTPOW2(rlvl->tly, rlvl->prcheightexpn); - brprcbrx = JPC_CEILTOMULTPOW2(rlvl->brx, rlvl->prcwidthexpn); - brprcbry = JPC_CEILTOMULTPOW2(rlvl->bry, rlvl->prcheightexpn); - rlvl->numhprcs = JPC_FLOORDIVPOW2(brprcbrx - tlprctlx, rlvl->prcwidthexpn); - rlvl->numvprcs = JPC_FLOORDIVPOW2(brprcbry - tlprctly, rlvl->prcheightexpn); - rlvl->numprcs = rlvl->numhprcs * rlvl->numvprcs; - - if (!(rlvl->bands = jas_malloc(rlvl->numbands * sizeof(jpc_enc_band_t)))) { - goto error; - } - for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands; - ++bandno, ++band) { - band->prcs = 0; - band->data = 0; - band->rlvl = rlvl; - } - for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands; - ++bandno, ++band) { - if (!band_create(band, cp, rlvl, bandinfos)) { - goto error; - } - } - - return rlvl; + uint_fast16_t rlvlno; + uint_fast32_t tlprctlx; + uint_fast32_t tlprctly; + uint_fast32_t brprcbrx; + uint_fast32_t brprcbry; + uint_fast16_t bandno; + jpc_enc_band_t *band; + + /* Deduce the resolution level. */ + rlvlno = rlvl - tcmpt->rlvls; + + /* Initialize members required for error recovery. */ + rlvl->bands = 0; + rlvl->tcmpt = tcmpt; + + /* Compute the coordinates of the top-left and bottom-right + corners of the tile-component at this resolution. */ + rlvl->tlx = JPC_CEILDIVPOW2(jas_seq2d_xstart(tcmpt->data), tcmpt->numrlvls - + 1 - rlvlno); + rlvl->tly = JPC_CEILDIVPOW2(jas_seq2d_ystart(tcmpt->data), tcmpt->numrlvls - + 1 - rlvlno); + rlvl->brx = JPC_CEILDIVPOW2(jas_seq2d_xend(tcmpt->data), tcmpt->numrlvls - + 1 - rlvlno); + rlvl->bry = JPC_CEILDIVPOW2(jas_seq2d_yend(tcmpt->data), tcmpt->numrlvls - + 1 - rlvlno); + + if (rlvl->tlx >= rlvl->brx || rlvl->tly >= rlvl->bry) { + rlvl->numhprcs = 0; + rlvl->numvprcs = 0; + rlvl->numprcs = 0; + return rlvl; + } + + rlvl->numbands = (!rlvlno) ? 1 : 3; + rlvl->prcwidthexpn = cp->tccp.prcwidthexpns[rlvlno]; + rlvl->prcheightexpn = cp->tccp.prcheightexpns[rlvlno]; + if (!rlvlno) { + rlvl->cbgwidthexpn = rlvl->prcwidthexpn; + rlvl->cbgheightexpn = rlvl->prcheightexpn; + } else { + rlvl->cbgwidthexpn = rlvl->prcwidthexpn - 1; + rlvl->cbgheightexpn = rlvl->prcheightexpn - 1; + } + rlvl->cblkwidthexpn = JAS_MIN(cp->tccp.cblkwidthexpn, rlvl->cbgwidthexpn); + rlvl->cblkheightexpn = JAS_MIN(cp->tccp.cblkheightexpn, rlvl->cbgheightexpn); + + /* Compute the number of precincts. */ + tlprctlx = JPC_FLOORTOMULTPOW2(rlvl->tlx, rlvl->prcwidthexpn); + tlprctly = JPC_FLOORTOMULTPOW2(rlvl->tly, rlvl->prcheightexpn); + brprcbrx = JPC_CEILTOMULTPOW2(rlvl->brx, rlvl->prcwidthexpn); + brprcbry = JPC_CEILTOMULTPOW2(rlvl->bry, rlvl->prcheightexpn); + rlvl->numhprcs = JPC_FLOORDIVPOW2(brprcbrx - tlprctlx, rlvl->prcwidthexpn); + rlvl->numvprcs = JPC_FLOORDIVPOW2(brprcbry - tlprctly, rlvl->prcheightexpn); + rlvl->numprcs = rlvl->numhprcs * rlvl->numvprcs; + + if (!(rlvl->bands = jas_malloc(rlvl->numbands * sizeof(jpc_enc_band_t)))) { + goto error; + } + for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands; + ++bandno, ++band) { + band->prcs = 0; + band->data = 0; + band->rlvl = rlvl; + } + for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands; + ++bandno, ++band) { + if (!band_create(band, cp, rlvl, bandinfos)) { + goto error; + } + } + + return rlvl; error: - rlvl_destroy(rlvl); - return 0; + rlvl_destroy(rlvl); + return 0; } static void rlvl_destroy(jpc_enc_rlvl_t *rlvl) { - jpc_enc_band_t *band; - uint_fast16_t bandno; - - if (rlvl->bands) { - for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands; - ++bandno, ++band) { - band_destroy(band); - } - jas_free(rlvl->bands); - } + jpc_enc_band_t *band; + uint_fast16_t bandno; + + if (rlvl->bands) { + for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands; + ++bandno, ++band) { + band_destroy(band); + } + jas_free(rlvl->bands); + } } static jpc_enc_band_t *band_create(jpc_enc_band_t *band, jpc_enc_cp_t *cp, jpc_enc_rlvl_t *rlvl, jpc_tsfb_band_t *bandinfos) { - uint_fast16_t bandno; - uint_fast16_t gblbandno; - uint_fast16_t rlvlno; - jpc_tsfb_band_t *bandinfo; - jpc_enc_tcmpt_t *tcmpt; - uint_fast32_t prcno; - jpc_enc_prc_t *prc; - - tcmpt = rlvl->tcmpt; - band->data = 0; - band->prcs = 0; - band->rlvl = rlvl; - - /* Deduce the resolution level and band number. */ - rlvlno = rlvl - rlvl->tcmpt->rlvls; - bandno = band - rlvl->bands; - gblbandno = (!rlvlno) ? 0 : (3 * (rlvlno - 1) + bandno + 1); - - bandinfo = &bandinfos[gblbandno]; + uint_fast16_t bandno; + uint_fast16_t gblbandno; + uint_fast16_t rlvlno; + jpc_tsfb_band_t *bandinfo; + jpc_enc_tcmpt_t *tcmpt; + uint_fast32_t prcno; + jpc_enc_prc_t *prc; + + tcmpt = rlvl->tcmpt; + band->data = 0; + band->prcs = 0; + band->rlvl = rlvl; + + /* Deduce the resolution level and band number. */ + rlvlno = rlvl - rlvl->tcmpt->rlvls; + bandno = band - rlvl->bands; + gblbandno = (!rlvlno) ? 0 : (3 * (rlvlno - 1) + bandno + 1); + + bandinfo = &bandinfos[gblbandno]; if (bandinfo->xstart != bandinfo->xend && bandinfo->ystart != bandinfo->yend) { - if (!(band->data = jas_seq2d_create(0, 0, 0, 0))) { - goto error; - } - jas_seq2d_bindsub(band->data, tcmpt->data, bandinfo->locxstart, - bandinfo->locystart, bandinfo->locxend, bandinfo->locyend); - jas_seq2d_setshift(band->data, bandinfo->xstart, bandinfo->ystart); + if (!(band->data = jas_seq2d_create(0, 0, 0, 0))) { + goto error; + } + jas_seq2d_bindsub(band->data, tcmpt->data, bandinfo->locxstart, + bandinfo->locystart, bandinfo->locxend, bandinfo->locyend); + jas_seq2d_setshift(band->data, bandinfo->xstart, bandinfo->ystart); } - band->orient = bandinfo->orient; - band->analgain = JPC_NOMINALGAIN(cp->tccp.qmfbid, tcmpt->numrlvls, rlvlno, - band->orient); - band->numbps = 0; - band->absstepsize = 0; - band->stepsize = 0; - band->synweight = bandinfo->synenergywt; + band->orient = bandinfo->orient; + band->analgain = JPC_NOMINALGAIN(cp->tccp.qmfbid, tcmpt->numrlvls, rlvlno, + band->orient); + band->numbps = 0; + band->absstepsize = 0; + band->stepsize = 0; + band->synweight = bandinfo->synenergywt; if (band->data) { - if (!(band->prcs = jas_malloc(rlvl->numprcs * sizeof(jpc_enc_prc_t)))) { - goto error; - } - for (prcno = 0, prc = band->prcs; prcno < rlvl->numprcs; ++prcno, - ++prc) { - prc->cblks = 0; - prc->incltree = 0; - prc->nlibtree = 0; - prc->savincltree = 0; - prc->savnlibtree = 0; - prc->band = band; - } - for (prcno = 0, prc = band->prcs; prcno < rlvl->numprcs; ++prcno, - ++prc) { - if (!prc_create(prc, cp, band)) { - goto error; - } - } + if (!(band->prcs = jas_malloc(rlvl->numprcs * sizeof(jpc_enc_prc_t)))) { + goto error; + } + for (prcno = 0, prc = band->prcs; prcno < rlvl->numprcs; ++prcno, + ++prc) { + prc->cblks = 0; + prc->incltree = 0; + prc->nlibtree = 0; + prc->savincltree = 0; + prc->savnlibtree = 0; + prc->band = band; + } + for (prcno = 0, prc = band->prcs; prcno < rlvl->numprcs; ++prcno, + ++prc) { + if (!prc_create(prc, cp, band)) { + goto error; + } + } } - return band; + return band; error: - band_destroy(band); - return 0; + band_destroy(band); + return 0; } static void band_destroy(jpc_enc_band_t *band) { - jpc_enc_prc_t *prc; - jpc_enc_rlvl_t *rlvl; - uint_fast32_t prcno; - - if (band->prcs) { - rlvl = band->rlvl; - for (prcno = 0, prc = band->prcs; prcno < rlvl->numprcs; - ++prcno, ++prc) { - prc_destroy(prc); - } - jas_free(band->prcs); - } - if (band->data) { - jas_seq2d_destroy(band->data); - } + jpc_enc_prc_t *prc; + jpc_enc_rlvl_t *rlvl; + uint_fast32_t prcno; + + if (band->prcs) { + rlvl = band->rlvl; + for (prcno = 0, prc = band->prcs; prcno < rlvl->numprcs; + ++prcno, ++prc) { + prc_destroy(prc); + } + jas_free(band->prcs); + } + if (band->data) { + jas_seq2d_destroy(band->data); + } } static jpc_enc_prc_t *prc_create(jpc_enc_prc_t *prc, jpc_enc_cp_t *cp, jpc_enc_band_t *band) { - uint_fast32_t prcno; - uint_fast32_t prcxind; - uint_fast32_t prcyind; - uint_fast32_t cbgtlx; - uint_fast32_t cbgtly; - uint_fast32_t tlprctlx; - uint_fast32_t tlprctly; - uint_fast32_t tlcbgtlx; - uint_fast32_t tlcbgtly; - uint_fast16_t rlvlno; - jpc_enc_rlvl_t *rlvl; - uint_fast32_t tlcblktlx; - uint_fast32_t tlcblktly; - uint_fast32_t brcblkbrx; - uint_fast32_t brcblkbry; - uint_fast32_t cblkno; - jpc_enc_cblk_t *cblk; - jpc_enc_tcmpt_t *tcmpt; - - prc->cblks = 0; - prc->incltree = 0; - prc->savincltree = 0; - prc->nlibtree = 0; - prc->savnlibtree = 0; - - rlvl = band->rlvl; - tcmpt = rlvl->tcmpt; + uint_fast32_t prcno; + uint_fast32_t prcxind; + uint_fast32_t prcyind; + uint_fast32_t cbgtlx; + uint_fast32_t cbgtly; + uint_fast32_t tlprctlx; + uint_fast32_t tlprctly; + uint_fast32_t tlcbgtlx; + uint_fast32_t tlcbgtly; + uint_fast16_t rlvlno; + jpc_enc_rlvl_t *rlvl; + uint_fast32_t tlcblktlx; + uint_fast32_t tlcblktly; + uint_fast32_t brcblkbrx; + uint_fast32_t brcblkbry; + uint_fast32_t cblkno; + jpc_enc_cblk_t *cblk; + jpc_enc_tcmpt_t *tcmpt; + + prc->cblks = 0; + prc->incltree = 0; + prc->savincltree = 0; + prc->nlibtree = 0; + prc->savnlibtree = 0; + + rlvl = band->rlvl; + tcmpt = rlvl->tcmpt; rlvlno = rlvl - tcmpt->rlvls; - prcno = prc - band->prcs; - prcxind = prcno % rlvl->numhprcs; - prcyind = prcno / rlvl->numhprcs; - prc->band = band; + prcno = prc - band->prcs; + prcxind = prcno % rlvl->numhprcs; + prcyind = prcno / rlvl->numhprcs; + prc->band = band; tlprctlx = JPC_FLOORTOMULTPOW2(rlvl->tlx, rlvl->prcwidthexpn); tlprctly = JPC_FLOORTOMULTPOW2(rlvl->tly, rlvl->prcheightexpn); if (!rlvlno) { - tlcbgtlx = tlprctlx; - tlcbgtly = tlprctly; + tlcbgtlx = tlprctlx; + tlcbgtly = tlprctly; } else { - tlcbgtlx = JPC_CEILDIVPOW2(tlprctlx, 1); - tlcbgtly = JPC_CEILDIVPOW2(tlprctly, 1); + tlcbgtlx = JPC_CEILDIVPOW2(tlprctlx, 1); + tlcbgtly = JPC_CEILDIVPOW2(tlprctly, 1); } - /* Compute the coordinates of the top-left and bottom-right - corners of the precinct. */ - cbgtlx = tlcbgtlx + (prcxind << rlvl->cbgwidthexpn); - cbgtly = tlcbgtly + (prcyind << rlvl->cbgheightexpn); - prc->tlx = JAS_MAX(jas_seq2d_xstart(band->data), cbgtlx); - prc->tly = JAS_MAX(jas_seq2d_ystart(band->data), cbgtly); - prc->brx = JAS_MIN(jas_seq2d_xend(band->data), cbgtlx + - (1 << rlvl->cbgwidthexpn)); - prc->bry = JAS_MIN(jas_seq2d_yend(band->data), cbgtly + - (1 << rlvl->cbgheightexpn)); - - if (prc->tlx < prc->brx && prc->tly < prc->bry) { - /* The precinct contains at least one code block. */ - - tlcblktlx = JPC_FLOORTOMULTPOW2(prc->tlx, rlvl->cblkwidthexpn); - tlcblktly = JPC_FLOORTOMULTPOW2(prc->tly, rlvl->cblkheightexpn); - brcblkbrx = JPC_CEILTOMULTPOW2(prc->brx, rlvl->cblkwidthexpn); - brcblkbry = JPC_CEILTOMULTPOW2(prc->bry, rlvl->cblkheightexpn); - prc->numhcblks = JPC_FLOORDIVPOW2(brcblkbrx - tlcblktlx, - rlvl->cblkwidthexpn); - prc->numvcblks = JPC_FLOORDIVPOW2(brcblkbry - tlcblktly, - rlvl->cblkheightexpn); - prc->numcblks = prc->numhcblks * prc->numvcblks; - - if (!(prc->incltree = jpc_tagtree_create(prc->numhcblks, - prc->numvcblks))) { - goto error; - } - if (!(prc->nlibtree = jpc_tagtree_create(prc->numhcblks, - prc->numvcblks))) { - goto error; - } - if (!(prc->savincltree = jpc_tagtree_create(prc->numhcblks, - prc->numvcblks))) { - goto error; - } - if (!(prc->savnlibtree = jpc_tagtree_create(prc->numhcblks, - prc->numvcblks))) { - goto error; - } - - if (!(prc->cblks = jas_malloc(prc->numcblks * sizeof(jpc_enc_cblk_t)))) { - goto error; - } - for (cblkno = 0, cblk = prc->cblks; cblkno < prc->numcblks; - ++cblkno, ++cblk) { - cblk->passes = 0; - cblk->stream = 0; - cblk->mqenc = 0; - cblk->data = 0; - cblk->flags = 0; - cblk->prc = prc; - } - for (cblkno = 0, cblk = prc->cblks; cblkno < prc->numcblks; - ++cblkno, ++cblk) { - if (!cblk_create(cblk, cp, prc)) { - goto error; - } - } - } else { - /* The precinct does not contain any code blocks. */ - prc->tlx = prc->brx; - prc->tly = prc->bry; - prc->numcblks = 0; - prc->numhcblks = 0; - prc->numvcblks = 0; - prc->cblks = 0; - prc->incltree = 0; - prc->nlibtree = 0; - prc->savincltree = 0; - prc->savnlibtree = 0; - } - - return prc; + /* Compute the coordinates of the top-left and bottom-right + corners of the precinct. */ + cbgtlx = tlcbgtlx + (prcxind << rlvl->cbgwidthexpn); + cbgtly = tlcbgtly + (prcyind << rlvl->cbgheightexpn); + prc->tlx = JAS_MAX(jas_seq2d_xstart(band->data), cbgtlx); + prc->tly = JAS_MAX(jas_seq2d_ystart(band->data), cbgtly); + prc->brx = JAS_MIN(jas_seq2d_xend(band->data), cbgtlx + + (1 << rlvl->cbgwidthexpn)); + prc->bry = JAS_MIN(jas_seq2d_yend(band->data), cbgtly + + (1 << rlvl->cbgheightexpn)); + + if (prc->tlx < prc->brx && prc->tly < prc->bry) { + /* The precinct contains at least one code block. */ + + tlcblktlx = JPC_FLOORTOMULTPOW2(prc->tlx, rlvl->cblkwidthexpn); + tlcblktly = JPC_FLOORTOMULTPOW2(prc->tly, rlvl->cblkheightexpn); + brcblkbrx = JPC_CEILTOMULTPOW2(prc->brx, rlvl->cblkwidthexpn); + brcblkbry = JPC_CEILTOMULTPOW2(prc->bry, rlvl->cblkheightexpn); + prc->numhcblks = JPC_FLOORDIVPOW2(brcblkbrx - tlcblktlx, + rlvl->cblkwidthexpn); + prc->numvcblks = JPC_FLOORDIVPOW2(brcblkbry - tlcblktly, + rlvl->cblkheightexpn); + prc->numcblks = prc->numhcblks * prc->numvcblks; + + if (!(prc->incltree = jpc_tagtree_create(prc->numhcblks, + prc->numvcblks))) { + goto error; + } + if (!(prc->nlibtree = jpc_tagtree_create(prc->numhcblks, + prc->numvcblks))) { + goto error; + } + if (!(prc->savincltree = jpc_tagtree_create(prc->numhcblks, + prc->numvcblks))) { + goto error; + } + if (!(prc->savnlibtree = jpc_tagtree_create(prc->numhcblks, + prc->numvcblks))) { + goto error; + } + + if (!(prc->cblks = jas_malloc(prc->numcblks * sizeof(jpc_enc_cblk_t)))) { + goto error; + } + for (cblkno = 0, cblk = prc->cblks; cblkno < prc->numcblks; + ++cblkno, ++cblk) { + cblk->passes = 0; + cblk->stream = 0; + cblk->mqenc = 0; + cblk->data = 0; + cblk->flags = 0; + cblk->prc = prc; + } + for (cblkno = 0, cblk = prc->cblks; cblkno < prc->numcblks; + ++cblkno, ++cblk) { + if (!cblk_create(cblk, cp, prc)) { + goto error; + } + } + } else { + /* The precinct does not contain any code blocks. */ + prc->tlx = prc->brx; + prc->tly = prc->bry; + prc->numcblks = 0; + prc->numhcblks = 0; + prc->numvcblks = 0; + prc->cblks = 0; + prc->incltree = 0; + prc->nlibtree = 0; + prc->savincltree = 0; + prc->savnlibtree = 0; + } + + return prc; error: - prc_destroy(prc); - return 0; + prc_destroy(prc); + return 0; } static void prc_destroy(jpc_enc_prc_t *prc) { - jpc_enc_cblk_t *cblk; - uint_fast32_t cblkno; - - if (prc->cblks) { - for (cblkno = 0, cblk = prc->cblks; cblkno < prc->numcblks; - ++cblkno, ++cblk) { - cblk_destroy(cblk); - } - jas_free(prc->cblks); - } - if (prc->incltree) { - jpc_tagtree_destroy(prc->incltree); - } - if (prc->nlibtree) { - jpc_tagtree_destroy(prc->nlibtree); - } - if (prc->savincltree) { - jpc_tagtree_destroy(prc->savincltree); - } - if (prc->savnlibtree) { - jpc_tagtree_destroy(prc->savnlibtree); - } + jpc_enc_cblk_t *cblk; + uint_fast32_t cblkno; + + if (prc->cblks) { + for (cblkno = 0, cblk = prc->cblks; cblkno < prc->numcblks; + ++cblkno, ++cblk) { + cblk_destroy(cblk); + } + jas_free(prc->cblks); + } + if (prc->incltree) { + jpc_tagtree_destroy(prc->incltree); + } + if (prc->nlibtree) { + jpc_tagtree_destroy(prc->nlibtree); + } + if (prc->savincltree) { + jpc_tagtree_destroy(prc->savincltree); + } + if (prc->savnlibtree) { + jpc_tagtree_destroy(prc->savnlibtree); + } } static jpc_enc_cblk_t *cblk_create(jpc_enc_cblk_t *cblk, jpc_enc_cp_t *cp, jpc_enc_prc_t *prc) { - jpc_enc_band_t *band; - uint_fast32_t cblktlx; - uint_fast32_t cblktly; - uint_fast32_t cblkbrx; - uint_fast32_t cblkbry; - jpc_enc_rlvl_t *rlvl; - uint_fast32_t cblkxind; - uint_fast32_t cblkyind; - uint_fast32_t cblkno; - uint_fast32_t tlcblktlx; - uint_fast32_t tlcblktly; - - cblkno = cblk - prc->cblks; - cblkxind = cblkno % prc->numhcblks; - cblkyind = cblkno / prc->numhcblks; - rlvl = prc->band->rlvl; - cblk->prc = prc; - - cblk->numpasses = 0; - cblk->passes = 0; - cblk->numencpasses = 0; - cblk->numimsbs = 0; - cblk->numlenbits = 0; - cblk->stream = 0; - cblk->mqenc = 0; - cblk->flags = 0; - cblk->numbps = 0; - cblk->curpass = 0; - cblk->data = 0; - cblk->savedcurpass = 0; - cblk->savednumlenbits = 0; - cblk->savednumencpasses = 0; - - band = prc->band; - tlcblktlx = JPC_FLOORTOMULTPOW2(prc->tlx, rlvl->cblkwidthexpn); - tlcblktly = JPC_FLOORTOMULTPOW2(prc->tly, rlvl->cblkheightexpn); - cblktlx = JAS_MAX(tlcblktlx + (cblkxind << rlvl->cblkwidthexpn), prc->tlx); - cblktly = JAS_MAX(tlcblktly + (cblkyind << rlvl->cblkheightexpn), prc->tly); - cblkbrx = JAS_MIN(tlcblktlx + ((cblkxind + 1) << rlvl->cblkwidthexpn), - prc->brx); - cblkbry = JAS_MIN(tlcblktly + ((cblkyind + 1) << rlvl->cblkheightexpn), - prc->bry); - - assert(cblktlx < cblkbrx && cblktly < cblkbry); - if (!(cblk->data = jas_seq2d_create(0, 0, 0, 0))) { - goto error; - } - jas_seq2d_bindsub(cblk->data, band->data, cblktlx, cblktly, cblkbrx, cblkbry); - - return cblk; + jpc_enc_band_t *band; + uint_fast32_t cblktlx; + uint_fast32_t cblktly; + uint_fast32_t cblkbrx; + uint_fast32_t cblkbry; + jpc_enc_rlvl_t *rlvl; + uint_fast32_t cblkxind; + uint_fast32_t cblkyind; + uint_fast32_t cblkno; + uint_fast32_t tlcblktlx; + uint_fast32_t tlcblktly; + + cblkno = cblk - prc->cblks; + cblkxind = cblkno % prc->numhcblks; + cblkyind = cblkno / prc->numhcblks; + rlvl = prc->band->rlvl; + cblk->prc = prc; + + cblk->numpasses = 0; + cblk->passes = 0; + cblk->numencpasses = 0; + cblk->numimsbs = 0; + cblk->numlenbits = 0; + cblk->stream = 0; + cblk->mqenc = 0; + cblk->flags = 0; + cblk->numbps = 0; + cblk->curpass = 0; + cblk->data = 0; + cblk->savedcurpass = 0; + cblk->savednumlenbits = 0; + cblk->savednumencpasses = 0; + + band = prc->band; + tlcblktlx = JPC_FLOORTOMULTPOW2(prc->tlx, rlvl->cblkwidthexpn); + tlcblktly = JPC_FLOORTOMULTPOW2(prc->tly, rlvl->cblkheightexpn); + cblktlx = JAS_MAX(tlcblktlx + (cblkxind << rlvl->cblkwidthexpn), prc->tlx); + cblktly = JAS_MAX(tlcblktly + (cblkyind << rlvl->cblkheightexpn), prc->tly); + cblkbrx = JAS_MIN(tlcblktlx + ((cblkxind + 1) << rlvl->cblkwidthexpn), + prc->brx); + cblkbry = JAS_MIN(tlcblktly + ((cblkyind + 1) << rlvl->cblkheightexpn), + prc->bry); + + assert(cblktlx < cblkbrx && cblktly < cblkbry); + if (!(cblk->data = jas_seq2d_create(0, 0, 0, 0))) { + goto error; + } + jas_seq2d_bindsub(cblk->data, band->data, cblktlx, cblktly, cblkbrx, cblkbry); + + return cblk; error: - cblk_destroy(cblk); - return 0; + cblk_destroy(cblk); + return 0; } static void cblk_destroy(jpc_enc_cblk_t *cblk) { - uint_fast16_t passno; - jpc_enc_pass_t *pass; - if (cblk->passes) { - for (passno = 0, pass = cblk->passes; passno < cblk->numpasses; - ++passno, ++pass) { - pass_destroy(pass); - } - jas_free(cblk->passes); - } - if (cblk->stream) { - jas_stream_close(cblk->stream); - } - if (cblk->mqenc) { - jpc_mqenc_destroy(cblk->mqenc); - } - if (cblk->data) { - jas_seq2d_destroy(cblk->data); - } - if (cblk->flags) { - jas_seq2d_destroy(cblk->flags); - } + uint_fast16_t passno; + jpc_enc_pass_t *pass; + if (cblk->passes) { + for (passno = 0, pass = cblk->passes; passno < cblk->numpasses; + ++passno, ++pass) { + pass_destroy(pass); + } + jas_free(cblk->passes); + } + if (cblk->stream) { + jas_stream_close(cblk->stream); + } + if (cblk->mqenc) { + jpc_mqenc_destroy(cblk->mqenc); + } + if (cblk->data) { + jas_seq2d_destroy(cblk->data); + } + if (cblk->flags) { + jas_seq2d_destroy(cblk->flags); + } } static void pass_destroy(jpc_enc_pass_t *pass) { - /* XXX - need to free resources here */ + /* XXX - need to free resources here */ } void jpc_enc_dump(jpc_enc_t *enc) { - jpc_enc_tile_t *tile; - jpc_enc_tcmpt_t *tcmpt; - jpc_enc_rlvl_t *rlvl; - jpc_enc_band_t *band; - jpc_enc_prc_t *prc; - jpc_enc_cblk_t *cblk; - uint_fast16_t cmptno; - uint_fast16_t rlvlno; - uint_fast16_t bandno; - uint_fast32_t prcno; - uint_fast32_t cblkno; - - tile = enc->curtile; - - for (cmptno = 0, tcmpt = tile->tcmpts; cmptno < tile->numtcmpts; ++cmptno, - ++tcmpt) { - fprintf(stderr, " tcmpt %5d %5d %5d %5d\n", jas_seq2d_xstart(tcmpt->data), jas_seq2d_ystart(tcmpt->data), jas_seq2d_xend(tcmpt->data), jas_seq2d_yend(tcmpt->data)); - for (rlvlno = 0, rlvl = tcmpt->rlvls; rlvlno < tcmpt->numrlvls; - ++rlvlno, ++rlvl) { - fprintf(stderr, " rlvl %5d %5d %5d %5d\n", rlvl->tlx, rlvl->tly, rlvl->brx, rlvl->bry); - for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands; - ++bandno, ++band) { - if (!band->data) { - continue; - } - fprintf(stderr, " band %5d %5d %5d %5d\n", jas_seq2d_xstart(band->data), jas_seq2d_ystart(band->data), jas_seq2d_xend(band->data), jas_seq2d_yend(band->data)); - for (prcno = 0, prc = band->prcs; prcno < rlvl->numprcs; - ++prcno, ++prc) { - fprintf(stderr, " prc %5d %5d %5d %5d (%5d %5d)\n", prc->tlx, prc->tly, prc->brx, prc->bry, prc->brx - prc->tlx, prc->bry - prc->tly); - if (!prc->cblks) { - continue; - } - for (cblkno = 0, cblk = prc->cblks; cblkno < prc->numcblks; - ++cblkno, ++cblk) { - fprintf(stderr, " cblk %5d %5d %5d %5d\n", jas_seq2d_xstart(cblk->data), jas_seq2d_ystart(cblk->data), jas_seq2d_xend(cblk->data), jas_seq2d_yend(cblk->data)); - } - } - } - } - } + jpc_enc_tile_t *tile; + jpc_enc_tcmpt_t *tcmpt; + jpc_enc_rlvl_t *rlvl; + jpc_enc_band_t *band; + jpc_enc_prc_t *prc; + jpc_enc_cblk_t *cblk; + uint_fast16_t cmptno; + uint_fast16_t rlvlno; + uint_fast16_t bandno; + uint_fast32_t prcno; + uint_fast32_t cblkno; + + tile = enc->curtile; + + for (cmptno = 0, tcmpt = tile->tcmpts; + cmptno < tile->numtcmpts; + ++cmptno, ++tcmpt) { + fprintf(stderr, " tcmpt %5d %5d %5d %5d\n", + (int)jas_seq2d_xstart(tcmpt->data), + (int)jas_seq2d_ystart(tcmpt->data), + (int)jas_seq2d_xend(tcmpt->data), + (int)jas_seq2d_yend(tcmpt->data)); + for (rlvlno = 0, rlvl = tcmpt->rlvls; + rlvlno < tcmpt->numrlvls; + ++rlvlno, ++rlvl) { + fprintf(stderr, " rlvl %5d %5d %5d %5d\n", + (int)rlvl->tlx, (int)rlvl->tly, + (int)rlvl->brx, (int)rlvl->bry); + for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands; + ++bandno, ++band) { + if (!band->data) { + continue; + } + fprintf(stderr, " band %5d %5d %5d %5d\n", + (int)jas_seq2d_xstart(band->data), + (int)jas_seq2d_ystart(band->data), + (int)jas_seq2d_xend(band->data), + (int)jas_seq2d_yend(band->data)); + for (prcno = 0, prc = band->prcs; + prcno < rlvl->numprcs; + ++prcno, ++prc) { + fprintf(stderr, " prc %5d %5d %5d %5d (%5d %5d)\n", + (int)prc->tlx, (int)prc->tly, + (int)prc->brx, (int)prc->bry, + (int)(prc->brx - prc->tlx), + (int)(prc->bry - prc->tly)); + if (!prc->cblks) { + continue; + } + for (cblkno = 0, cblk = prc->cblks; cblkno < prc->numcblks; + ++cblkno, ++cblk) { + fprintf(stderr, " cblk %5d %5d %5d %5d\n", + (int)jas_seq2d_xstart(cblk->data), + (int)jas_seq2d_ystart(cblk->data), + (int)jas_seq2d_xend(cblk->data), + (int)jas_seq2d_yend(cblk->data)); + } + } + } + } + } +} + + + +static int jpc_enc_encodemainbody(jpc_enc_t *enc) +{ + int tileno; + int tilex; + int tiley; + int i; + jpc_sot_t *sot; + jpc_enc_tcmpt_t *comp; + jpc_enc_tcmpt_t *endcomps; + jpc_enc_band_t *band; + jpc_enc_band_t *endbands; + jpc_enc_rlvl_t *lvl; + int rlvlno; + jpc_qcc_t *qcc; + jpc_cod_t *cod; + int adjust; + int j; + int absbandno; + long numbytes; + long tilehdrlen; + long tilelen; + jpc_enc_tile_t *tile; + jpc_enc_cp_t *cp; + double rho; + uint_fast16_t cmptno; + int samestepsizes; + jpc_enc_ccp_t *ccps; + jpc_enc_tccp_t *tccp; + int bandno; + uint_fast32_t x; + uint_fast32_t y; + int mingbits; + int actualnumbps; + jpc_fix_t mxmag; + jpc_fix_t mag; + int numgbits; + const char * error; + + cp = enc->cp; + + /* Avoid compile warnings. */ + numbytes = 0; + + for (tileno = 0; tileno < cp->numtiles; ++tileno) { + tilex = tileno % cp->numhtiles; + tiley = tileno / cp->numhtiles; + + enc->curtile = jpc_enc_tile_create(enc->cp, enc->image, tileno); + if (!enc->curtile) + abort(); + + tile = enc->curtile; + + if (jas_getdbglevel() >= 10) { + jpc_enc_dump(enc); + } + + endcomps = &tile->tcmpts[tile->numtcmpts]; + for (cmptno = 0, comp = tile->tcmpts; + cmptno < tile->numtcmpts; + ++cmptno, ++comp) { + if (!cp->ccps[cmptno].sgnd) { + adjust = 1 << (cp->ccps[cmptno].prec - 1); + for (i = 0; i < jas_matrix_numrows(comp->data); ++i) { + for (j = 0; j < jas_matrix_numcols(comp->data); ++j) { + *jas_matrix_getref(comp->data, i, j) -= adjust; + } + } + } + } + + if (!tile->intmode) { + endcomps = &tile->tcmpts[tile->numtcmpts]; + for (comp = tile->tcmpts; comp != endcomps; ++comp) { + jas_matrix_asl(comp->data, JPC_FIX_FRACBITS); + } + } + + switch (tile->mctid) { + case JPC_MCT_RCT: + assert(jas_image_numcmpts(enc->image) == 3); + jpc_rct(tile->tcmpts[0].data, tile->tcmpts[1].data, + tile->tcmpts[2].data); + break; + case JPC_MCT_ICT: + assert(jas_image_numcmpts(enc->image) == 3); + jpc_ict(tile->tcmpts[0].data, tile->tcmpts[1].data, + tile->tcmpts[2].data); + break; + default: + break; + } + + for (i = 0; i < jas_image_numcmpts(enc->image); ++i) { + comp = &tile->tcmpts[i]; + jpc_tsfb_analyze(comp->tsfb, + ((comp->qmfbid == JPC_COX_RFT) ? + JPC_TSFB_RITIMODE : 0), comp->data); + + } + + + endcomps = &tile->tcmpts[tile->numtcmpts]; + for (cmptno = 0, comp = tile->tcmpts; + comp != endcomps; + ++cmptno, ++comp) { + mingbits = 0; + absbandno = 0; + /* All bands must have a corresponding quantizer step size, + even if they contain no samples and are never coded. */ + /* Some bands may not be hit by the loop below, so we must + initialize all of the step sizes to a sane value. */ + memset(comp->stepsizes, 0, sizeof(comp->stepsizes)); + for (rlvlno = 0, lvl = comp->rlvls; + rlvlno < comp->numrlvls; + ++rlvlno, ++lvl) { + if (!lvl->bands) { + absbandno += rlvlno ? 3 : 1; + continue; + } + endbands = &lvl->bands[lvl->numbands]; + for (band = lvl->bands; band != endbands; ++band) { + if (!band->data) { + ++absbandno; + continue; + } + actualnumbps = 0; + mxmag = 0; + for (y = 0; y < jas_matrix_numrows(band->data); ++y) { + for (x = 0; x < jas_matrix_numcols(band->data); ++x) { + mag = abs(jas_matrix_get(band->data, y, x)); + if (mag > mxmag) { + mxmag = mag; + } + } + } + if (tile->intmode) { + actualnumbps = + jpc_firstone(mxmag) + 1; + } else { + actualnumbps = + jpc_firstone(mxmag) + 1 - JPC_FIX_FRACBITS; + } + numgbits = actualnumbps - (cp->ccps[cmptno].prec - 1 + + band->analgain); + if (numgbits > mingbits) { + mingbits = numgbits; + } + if (!tile->intmode) { + band->absstepsize = + jpc_fix_div( + jpc_inttofix(1 << (band->analgain + 1)), + band->synweight); + } else { + band->absstepsize = jpc_inttofix(1); + } + band->stepsize = jpc_abstorelstepsize( + band->absstepsize, cp->ccps[cmptno].prec + + band->analgain); + band->numbps = cp->tccp.numgbits + + JPC_QCX_GETEXPN(band->stepsize) - 1; + + if ((!tile->intmode) && band->data) { + quantize(band->data, band->absstepsize); + } + + comp->stepsizes[absbandno] = band->stepsize; + ++absbandno; + } + } + + assert(JPC_FIX_FRACBITS >= JPC_NUMEXTRABITS); + if (!tile->intmode) { + jas_matrix_divpow2(comp->data, + JPC_FIX_FRACBITS - JPC_NUMEXTRABITS); + } else { + jas_matrix_asl(comp->data, JPC_NUMEXTRABITS); + } + } + + if (mingbits > cp->tccp.numgbits) { + fprintf(stderr, "error: too few guard bits (need at least %d)\n", + mingbits); + return -1; + } + + if (!(enc->tmpstream = jas_stream_memopen(0, 0))) { + fprintf(stderr, "cannot open tmp file\n"); + return -1; + } + + /* Write the tile header. */ + if (!(enc->mrk = jpc_ms_create(JPC_MS_SOT))) { + return -1; + } + sot = &enc->mrk->parms.sot; + sot->len = 0; + sot->tileno = tileno; + sot->partno = 0; + sot->numparts = 1; + if (jpc_putms(enc->tmpstream, enc->cstate, enc->mrk)) { + fprintf(stderr, "cannot write SOT marker\n"); + return -1; + } + jpc_ms_destroy(enc->mrk); + enc->mrk = 0; + +/************************************************************************/ +/************************************************************************/ +/************************************************************************/ + + tccp = &cp->tccp; + for (cmptno = 0; cmptno < cp->numcmpts; ++cmptno) { + comp = &tile->tcmpts[cmptno]; + if (comp->numrlvls != tccp->maxrlvls) { + if (!(enc->mrk = jpc_ms_create(JPC_MS_COD))) { + return -1; + } + /* XXX = this is not really correct. we are using comp #0's + precint sizes and other characteristics */ + comp = &tile->tcmpts[0]; + cod = &enc->mrk->parms.cod; + cod->compparms.csty = 0; + cod->compparms.numdlvls = comp->numrlvls - 1; + cod->prg = tile->prg; + cod->numlyrs = tile->numlyrs; + cod->compparms.cblkwidthval = + JPC_COX_CBLKSIZEEXPN(comp->cblkwidthexpn); + cod->compparms.cblkheightval = + JPC_COX_CBLKSIZEEXPN(comp->cblkheightexpn); + cod->compparms.cblksty = comp->cblksty; + cod->compparms.qmfbid = comp->qmfbid; + cod->mctrans = (tile->mctid != JPC_MCT_NONE); + for (i = 0; i < comp->numrlvls; ++i) { + cod->compparms.rlvls[i].parwidthval = + comp->rlvls[i].prcwidthexpn; + cod->compparms.rlvls[i].parheightval = + comp->rlvls[i].prcheightexpn; + } + if (jpc_putms(enc->tmpstream, enc->cstate, enc->mrk)) { + return -1; + } + jpc_ms_destroy(enc->mrk); + enc->mrk = 0; + } + } + + for (cmptno = 0, comp = tile->tcmpts; + cmptno < cp->numcmpts; + ++cmptno, ++comp) { + ccps = &cp->ccps[cmptno]; + if (ccps->numstepsizes == comp->numstepsizes) { + samestepsizes = 1; + for (bandno = 0; bandno < ccps->numstepsizes; ++bandno) { + if (ccps->stepsizes[bandno] != comp->stepsizes[bandno]) { + samestepsizes = 0; + break; + } + } + } else { + samestepsizes = 0; + } + if (!samestepsizes) { + if (!(enc->mrk = jpc_ms_create(JPC_MS_QCC))) { + return -1; + } + qcc = &enc->mrk->parms.qcc; + qcc->compno = cmptno; + qcc->compparms.numguard = cp->tccp.numgbits; + qcc->compparms.qntsty = (comp->qmfbid == JPC_COX_INS) ? + JPC_QCX_SEQNT : JPC_QCX_NOQNT; + qcc->compparms.numstepsizes = comp->numstepsizes; + qcc->compparms.stepsizes = comp->stepsizes; + if (jpc_putms(enc->tmpstream, enc->cstate, enc->mrk)) { + return -1; + } + qcc->compparms.stepsizes = 0; + jpc_ms_destroy(enc->mrk); + enc->mrk = 0; + } + } + + /* Write a SOD marker to indicate the end of the tile header. */ + if (!(enc->mrk = jpc_ms_create(JPC_MS_SOD))) { + return -1; + } + if (jpc_putms(enc->tmpstream, enc->cstate, enc->mrk)) { + fprintf(stderr, "cannot write SOD marker\n"); + return -1; + } + jpc_ms_destroy(enc->mrk); + enc->mrk = 0; + tilehdrlen = jas_stream_getrwcount(enc->tmpstream); + +/************************************************************************/ +/************************************************************************/ +/************************************************************************/ + + if (jpc_enc_enccblks(enc)) { + abort(); + return -1; + } + + cp = enc->cp; + rho = (double) (tile->brx - tile->tlx) * (tile->bry - tile->tly) / + ((cp->refgrdwidth - cp->imgareatlx) * (cp->refgrdheight - + cp->imgareatly)); + tile->rawsize = cp->rawsize * rho; + + computeLayerSizes(enc, tile, cp, rho, tilehdrlen, &error); + + if (!error) { + int rc; + performTier2Coding(enc, tile->numlyrs, tile->lyrsizes, &error); + + rc = jpc_enc_encodetiledata(enc); + if (rc != 0) + pm_asprintf(&error, "jpc_enc_encodetiledata() failed\n"); + } + + if (error) { + fprintf(stderr, "%s\n", error); + pm_strfree(error); + return -1; + } + + tilelen = jas_stream_tell(enc->tmpstream); + + if (jas_stream_seek(enc->tmpstream, 6, SEEK_SET) < 0) { + return -1; + } + jpc_putuint32(enc->tmpstream, tilelen); + + if (jas_stream_seek(enc->tmpstream, 0, SEEK_SET) < 0) { + return -1; + } + if (jpc_putdata(enc->out, enc->tmpstream, -1)) { + return -1; + } + enc->len += tilelen; + + jas_stream_close(enc->tmpstream); + enc->tmpstream = 0; + + jpc_enc_tile_destroy(enc->curtile); + enc->curtile = 0; + + } + + return 0; } + + + +/* + * Copyright (c) 1999-2000 Image Power, Inc. and the University of + * British Columbia. + * Copyright (c) 2001-2002 Michael David Adams. + * All rights reserved. + */ + +/* __START_OF_JASPER_LICENSE__ + * + * JasPer Software License + * + * IMAGE POWER JPEG-2000 PUBLIC LICENSE + * ************************************ + * + * GRANT: + * + * Permission is hereby granted, free of charge, to any person (the "User") + * obtaining a copy of this software and associated documentation, to deal + * in the JasPer Software without restriction, including without limitation + * the right to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the JasPer Software (in source and binary forms), + * and to permit persons to whom the JasPer Software is furnished to do so, + * provided further that the License Conditions below are met. + * + * License Conditions + * ****************** + * + * A. Redistributions of source code must retain the above copyright notice, + * and this list of conditions, and the following disclaimer. + * + * B. Redistributions in binary form must reproduce the above copyright + * notice, and this list of conditions, and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * + * C. Neither the name of Image Power, Inc. nor any other contributor + * (including, but not limited to, the University of British Columbia and + * Michael David Adams) may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * D. User agrees that it shall not commence any action against Image Power, + * Inc., the University of British Columbia, Michael David Adams, or any + * other contributors (collectively "Licensors") for infringement of any + * intellectual property rights ("IPR") held by the User in respect of any + * technology that User owns or has a right to license or sublicense and + * which is an element required in order to claim compliance with ISO/IEC + * 15444-1 (i.e., JPEG-2000 Part 1). "IPR" means all intellectual property + * rights worldwide arising under statutory or common law, and whether + * or not perfected, including, without limitation, all (i) patents and + * patent applications owned or licensable by User; (ii) rights associated + * with works of authorship including copyrights, copyright applications, + * copyright registrations, mask work rights, mask work applications, + * mask work registrations; (iii) rights relating to the protection of + * trade secrets and confidential information; (iv) any right analogous + * to those set forth in subsections (i), (ii), or (iii) and any other + * proprietary rights relating to intangible property (other than trademark, + * trade dress, or service mark rights); and (v) divisions, continuations, + * renewals, reissues and extensions of the foregoing (as and to the extent + * applicable) now existing, hereafter filed, issued or acquired. + * + * E. If User commences an infringement action against any Licensor(s) then + * such Licensor(s) shall have the right to terminate User's license and + * all sublicenses that have been granted hereunder by User to other parties. + * + * F. This software is for use only in hardware or software products that + * are compliant with ISO/IEC 15444-1 (i.e., JPEG-2000 Part 1). No license + * or right to this Software is granted for products that do not comply + * with ISO/IEC 15444-1. The JPEG-2000 Part 1 standard can be purchased + * from the ISO. + * + * THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. + * NO USE OF THE JASPER SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER + * THIS DISCLAIMER. THE JASPER SOFTWARE IS PROVIDED BY THE LICENSORS AND + * CONTRIBUTORS UNDER THIS LICENSE ON AN ``AS-IS'' BASIS, WITHOUT WARRANTY + * OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, + * WARRANTIES THAT THE JASPER SOFTWARE IS FREE OF DEFECTS, IS MERCHANTABLE, + * IS FIT FOR A PARTICULAR PURPOSE OR IS NON-INFRINGING. THOSE INTENDING + * TO USE THE JASPER SOFTWARE OR MODIFICATIONS THEREOF FOR USE IN HARDWARE + * OR SOFTWARE PRODUCTS ARE ADVISED THAT THEIR USE MAY INFRINGE EXISTING + * PATENTS, COPYRIGHTS, TRADEMARKS, OR OTHER INTELLECTUAL PROPERTY RIGHTS. + * THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE JASPER SOFTWARE + * IS WITH THE USER. SHOULD ANY PART OF THE JASPER SOFTWARE PROVE DEFECTIVE + * IN ANY RESPECT, THE USER (AND NOT THE INITIAL DEVELOPERS, THE UNIVERSITY + * OF BRITISH COLUMBIA, IMAGE POWER, INC., MICHAEL DAVID ADAMS, OR ANY + * OTHER CONTRIBUTOR) SHALL ASSUME THE COST OF ANY NECESSARY SERVICING, + * REPAIR OR CORRECTION. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, + * WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL THE + * INITIAL DEVELOPER, THE UNIVERSITY OF BRITISH COLUMBIA, IMAGE POWER, INC., + * MICHAEL DAVID ADAMS, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF THE + * JASPER SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO + * THE USER OR ANY OTHER PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR + * CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, + * DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR + * MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF + * SUCH PARTY HAD BEEN INFORMED, OR OUGHT TO HAVE KNOWN, OF THE POSSIBILITY + * OF SUCH DAMAGES. THE JASPER SOFTWARE AND UNDERLYING TECHNOLOGY ARE NOT + * FAULT-TOLERANT AND ARE NOT DESIGNED, MANUFACTURED OR INTENDED FOR USE OR + * RESALE AS ON-LINE CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING + * FAIL-SAFE PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, + * AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT + * LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE + * JASPER SOFTWARE OR UNDERLYING TECHNOLOGY OR PRODUCT COULD LEAD DIRECTLY + * TO DEATH, PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE + * ("HIGH RISK ACTIVITIES"). LICENSOR SPECIFICALLY DISCLAIMS ANY EXPRESS + * OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES. USER WILL NOT + * KNOWINGLY USE, DISTRIBUTE OR RESELL THE JASPER SOFTWARE OR UNDERLYING + * TECHNOLOGY OR PRODUCTS FOR HIGH RISK ACTIVITIES AND WILL ENSURE THAT ITS + * CUSTOMERS AND END-USERS OF ITS PRODUCTS ARE PROVIDED WITH A COPY OF THE + * NOTICE SPECIFIED IN THIS SECTION. + * + * __END_OF_JASPER_LICENSE__ + */ + diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_math.h b/converter/other/jpeg2000/libjasper/jpc/jpc_math.h index e343bab1..77df0c62 100644 --- a/converter/other/jpeg2000/libjasper/jpc/jpc_math.h +++ b/converter/other/jpeg2000/libjasper/jpc/jpc_math.h @@ -135,7 +135,7 @@ #define JPC_CEILDIVPOW2(x, y) \ (assert(x >= 0 && y >= 0), ((x) + (1 << (y)) - 1) >> (y)) /* JPC_CEILDIVPOW2U is for unsigned arguments (JPC_CEILDIVPOW2 would generate - compiler warnings due to its superfluous >= 0 check) + compiler warnings because of its superfluous >= 0 check) */ #define JPC_CEILDIVPOW2U(x, y) \ (((x) + (1 << (y)) - 1) >> (y)) diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_mqcod.h b/converter/other/jpeg2000/libjasper/jpc/jpc_mqcod.h index 914f8e8a..5f99e021 100644 --- a/converter/other/jpeg2000/libjasper/jpc/jpc_mqcod.h +++ b/converter/other/jpeg2000/libjasper/jpc/jpc_mqcod.h @@ -123,7 +123,7 @@ * Includes. \*****************************************************************************/ -#include "pm_c_util.h" +#include "netpbm/pm_c_util.h" #include "jasper/jas_types.h" /*****************************************************************************\ diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_mqenc.c b/converter/other/jpeg2000/libjasper/jpc/jpc_mqenc.c index 0219a000..3f6122e3 100644 --- a/converter/other/jpeg2000/libjasper/jpc/jpc_mqenc.c +++ b/converter/other/jpeg2000/libjasper/jpc/jpc_mqenc.c @@ -135,91 +135,91 @@ \******************************************************************************/ #if defined(DEBUG) -#define JPC_MQENC_CALL(n, x) \ - ((jas_getdbglevel() >= (n)) ? ((void)(x)) : ((void)0)) +#define JPC_MQENC_CALL(n, x) \ + ((jas_getdbglevel() >= (n)) ? ((void)(x)) : ((void)0)) #else -#define JPC_MQENC_CALL(n, x) +#define JPC_MQENC_CALL(n, x) #endif -#define jpc_mqenc_codemps9(areg, creg, ctreg, curctx, enc) \ +#define jpc_mqenc_codemps9(areg, creg, ctreg, curctx, enc) \ { \ - jpc_mqstate_t *state = *(curctx); \ - (areg) -= state->qeval; \ - if (!((areg) & 0x8000)) { \ - if ((areg) < state->qeval) { \ - (areg) = state->qeval; \ - } else { \ - (creg) += state->qeval; \ - } \ - *(curctx) = state->nmps; \ - jpc_mqenc_renorme((areg), (creg), (ctreg), (enc)); \ - } else { \ - (creg) += state->qeval; \ - } \ + jpc_mqstate_t *state = *(curctx); \ + (areg) -= state->qeval; \ + if (!((areg) & 0x8000)) { \ + if ((areg) < state->qeval) { \ + (areg) = state->qeval; \ + } else { \ + (creg) += state->qeval; \ + } \ + *(curctx) = state->nmps; \ + jpc_mqenc_renorme((areg), (creg), (ctreg), (enc)); \ + } else { \ + (creg) += state->qeval; \ + } \ } -#define jpc_mqenc_codelps2(areg, creg, ctreg, curctx, enc) \ +#define jpc_mqenc_codelps2(areg, creg, ctreg, curctx, enc) \ { \ - jpc_mqstate_t *state = *(curctx); \ - (areg) -= state->qeval; \ - if ((areg) < state->qeval) { \ - (creg) += state->qeval; \ - } else { \ - (areg) = state->qeval; \ - } \ - *(curctx) = state->nlps; \ - jpc_mqenc_renorme((areg), (creg), (ctreg), (enc)); \ + jpc_mqstate_t *state = *(curctx); \ + (areg) -= state->qeval; \ + if ((areg) < state->qeval) { \ + (creg) += state->qeval; \ + } else { \ + (areg) = state->qeval; \ + } \ + *(curctx) = state->nlps; \ + jpc_mqenc_renorme((areg), (creg), (ctreg), (enc)); \ } -#define jpc_mqenc_renorme(areg, creg, ctreg, enc) \ +#define jpc_mqenc_renorme(areg, creg, ctreg, enc) \ { \ - do { \ - (areg) <<= 1; \ - (creg) <<= 1; \ - if (!--(ctreg)) { \ - jpc_mqenc_byteout((areg), (creg), (ctreg), (enc)); \ - } \ - } while (!((areg) & 0x8000)); \ + do { \ + (areg) <<= 1; \ + (creg) <<= 1; \ + if (!--(ctreg)) { \ + jpc_mqenc_byteout((areg), (creg), (ctreg), (enc)); \ + } \ + } while (!((areg) & 0x8000)); \ } -#define jpc_mqenc_byteout(areg, creg, ctreg, enc) \ +#define jpc_mqenc_byteout(areg, creg, ctreg, enc) \ { \ - if ((enc)->outbuf != 0xff) { \ - if ((creg) & 0x8000000) { \ - if (++((enc)->outbuf) == 0xff) { \ - (creg) &= 0x7ffffff; \ - jpc_mqenc_byteout2(enc); \ - enc->outbuf = ((creg) >> 20) & 0xff; \ - (creg) &= 0xfffff; \ - (ctreg) = 7; \ - } else { \ - jpc_mqenc_byteout2(enc); \ - enc->outbuf = ((creg) >> 19) & 0xff; \ - (creg) &= 0x7ffff; \ - (ctreg) = 8; \ - } \ - } else { \ - jpc_mqenc_byteout2(enc); \ - (enc)->outbuf = ((creg) >> 19) & 0xff; \ - (creg) &= 0x7ffff; \ - (ctreg) = 8; \ - } \ - } else { \ - jpc_mqenc_byteout2(enc); \ - (enc)->outbuf = ((creg) >> 20) & 0xff; \ - (creg) &= 0xfffff; \ - (ctreg) = 7; \ - } \ + if ((enc)->outbuf != 0xff) { \ + if ((creg) & 0x8000000) { \ + if (++((enc)->outbuf) == 0xff) { \ + (creg) &= 0x7ffffff; \ + jpc_mqenc_byteout2(enc); \ + enc->outbuf = ((creg) >> 20) & 0xff; \ + (creg) &= 0xfffff; \ + (ctreg) = 7; \ + } else { \ + jpc_mqenc_byteout2(enc); \ + enc->outbuf = ((creg) >> 19) & 0xff; \ + (creg) &= 0x7ffff; \ + (ctreg) = 8; \ + } \ + } else { \ + jpc_mqenc_byteout2(enc); \ + (enc)->outbuf = ((creg) >> 19) & 0xff; \ + (creg) &= 0x7ffff; \ + (ctreg) = 8; \ + } \ + } else { \ + jpc_mqenc_byteout2(enc); \ + (enc)->outbuf = ((creg) >> 20) & 0xff; \ + (creg) &= 0xfffff; \ + (ctreg) = 7; \ + } \ } -#define jpc_mqenc_byteout2(enc) \ +#define jpc_mqenc_byteout2(enc) \ { \ - if (enc->outbuf >= 0) { \ - if (jas_stream_putc(enc->out, (unsigned char)enc->outbuf) == EOF) { \ - enc->err |= 1; \ - } \ - } \ - enc->lastbyte = enc->outbuf; \ + if (enc->outbuf >= 0) { \ + if (jas_stream_putc(enc->out, (unsigned char)enc->outbuf) == EOF) { \ + enc->err |= 1; \ + } \ + } \ + enc->lastbyte = enc->outbuf; \ } /******************************************************************************\ @@ -236,45 +236,45 @@ static void jpc_mqenc_setbits(jpc_mqenc_t *mqenc); jpc_mqenc_t *jpc_mqenc_create(int maxctxs, jas_stream_t *out) { - jpc_mqenc_t *mqenc; + jpc_mqenc_t *mqenc; - /* Allocate memory for the MQ encoder. */ - if (!(mqenc = jas_malloc(sizeof(jpc_mqenc_t)))) { - goto error; - } - mqenc->out = out; - mqenc->maxctxs = maxctxs; + /* Allocate memory for the MQ encoder. */ + if (!(mqenc = jas_malloc(sizeof(jpc_mqenc_t)))) { + goto error; + } + mqenc->out = out; + mqenc->maxctxs = maxctxs; - /* Allocate memory for the per-context state information. */ - if (!(mqenc->ctxs = jas_malloc(mqenc->maxctxs * sizeof(jpc_mqstate_t *)))) { - goto error; - } + /* Allocate memory for the per-context state information. */ + if (!(mqenc->ctxs = jas_malloc(mqenc->maxctxs * sizeof(jpc_mqstate_t *)))) { + goto error; + } - /* Set the current context to the first one. */ - mqenc->curctx = mqenc->ctxs; + /* Set the current context to the first one. */ + mqenc->curctx = mqenc->ctxs; - jpc_mqenc_init(mqenc); + jpc_mqenc_init(mqenc); - /* Initialize the per-context state information to something sane. */ - jpc_mqenc_setctxs(mqenc, 0, 0); + /* Initialize the per-context state information to something sane. */ + jpc_mqenc_setctxs(mqenc, 0, 0); - return mqenc; + return mqenc; error: - if (mqenc) { - jpc_mqenc_destroy(mqenc); - } - return 0; + if (mqenc) { + jpc_mqenc_destroy(mqenc); + } + return 0; } /* Destroy a MQ encoder. */ void jpc_mqenc_destroy(jpc_mqenc_t *mqenc) { - if (mqenc->ctxs) { - jas_free(mqenc->ctxs); - } - jas_free(mqenc); + if (mqenc->ctxs) { + jas_free(mqenc->ctxs); + } + jas_free(mqenc); } /******************************************************************************\ @@ -285,33 +285,33 @@ void jpc_mqenc_destroy(jpc_mqenc_t *mqenc) void jpc_mqenc_init(jpc_mqenc_t *mqenc) { - mqenc->areg = 0x8000; - mqenc->outbuf = -1; - mqenc->creg = 0; - mqenc->ctreg = 12; - mqenc->lastbyte = -1; - mqenc->err = 0; + mqenc->areg = 0x8000; + mqenc->outbuf = -1; + mqenc->creg = 0; + mqenc->ctreg = 12; + mqenc->lastbyte = -1; + mqenc->err = 0; } /* Initialize one or more contexts. */ void jpc_mqenc_setctxs(jpc_mqenc_t *mqenc, int numctxs, jpc_mqctx_t *ctxs) { - jpc_mqstate_t **ctx; - int n; - - ctx = mqenc->ctxs; - n = JAS_MIN(mqenc->maxctxs, numctxs); - while (--n >= 0) { - *ctx = &jpc_mqstates[2 * ctxs->ind + ctxs->mps]; - ++ctx; - ++ctxs; - } - n = mqenc->maxctxs - numctxs; - while (--n >= 0) { - *ctx = &jpc_mqstates[0]; - ++ctx; - } + jpc_mqstate_t **ctx; + int n; + + ctx = mqenc->ctxs; + n = JAS_MIN(mqenc->maxctxs, numctxs); + while (--n >= 0) { + *ctx = &jpc_mqstates[2 * ctxs->ind + ctxs->mps]; + ++ctx; + ++ctxs; + } + n = mqenc->maxctxs - numctxs; + while (--n >= 0) { + *ctx = &jpc_mqstates[0]; + ++ctx; + } } @@ -319,10 +319,10 @@ void jpc_mqenc_setctxs(jpc_mqenc_t *mqenc, int numctxs, jpc_mqctx_t *ctxs) void jpc_mqenc_getstate(jpc_mqenc_t *mqenc, jpc_mqencstate_t *state) { - state->areg = mqenc->areg; - state->creg = mqenc->creg; - state->ctreg = mqenc->ctreg; - state->lastbyte = mqenc->lastbyte; + state->areg = mqenc->areg; + state->creg = mqenc->creg; + state->ctreg = mqenc->ctreg; + state->lastbyte = mqenc->lastbyte; } /******************************************************************************\ @@ -333,49 +333,49 @@ void jpc_mqenc_getstate(jpc_mqenc_t *mqenc, jpc_mqencstate_t *state) int jpc_mqenc_putbit_func(jpc_mqenc_t *mqenc, int bit) { - const jpc_mqstate_t *state; - JAS_DBGLOG(100, ("jpc_mqenc_putbit(%p, %d)\n", mqenc, bit)); - JPC_MQENC_CALL(100, jpc_mqenc_dump(mqenc, stderr)); - - state = *(mqenc->curctx); - - if (state->mps == bit) { - /* Apply the CODEMPS algorithm as defined in the standard. */ - mqenc->areg -= state->qeval; - if (!(mqenc->areg & 0x8000)) { - jpc_mqenc_codemps2(mqenc); - } else { - mqenc->creg += state->qeval; - } - } else { - /* Apply the CODELPS algorithm as defined in the standard. */ - jpc_mqenc_codelps2(mqenc->areg, mqenc->creg, mqenc->ctreg, mqenc->curctx, mqenc); - } - - return jpc_mqenc_error(mqenc) ? (-1) : 0; + const jpc_mqstate_t *state; + JAS_DBGLOG(100, ("jpc_mqenc_putbit(%p, %d)\n", mqenc, bit)); + JPC_MQENC_CALL(100, jpc_mqenc_dump(mqenc, stderr)); + + state = *(mqenc->curctx); + + if (state->mps == bit) { + /* Apply the CODEMPS algorithm as defined in the standard. */ + mqenc->areg -= state->qeval; + if (!(mqenc->areg & 0x8000)) { + jpc_mqenc_codemps2(mqenc); + } else { + mqenc->creg += state->qeval; + } + } else { + /* Apply the CODELPS algorithm as defined in the standard. */ + jpc_mqenc_codelps2(mqenc->areg, mqenc->creg, mqenc->ctreg, mqenc->curctx, mqenc); + } + + return jpc_mqenc_error(mqenc) ? (-1) : 0; } int jpc_mqenc_codemps2(jpc_mqenc_t *mqenc) { - /* Note: This function only performs part of the work associated with - the CODEMPS algorithm from the standard. Some of the work is also - performed by the caller. */ - - jpc_mqstate_t *state = *(mqenc->curctx); - if (mqenc->areg < state->qeval) { - mqenc->areg = state->qeval; - } else { - mqenc->creg += state->qeval; - } - *mqenc->curctx = state->nmps; - jpc_mqenc_renorme(mqenc->areg, mqenc->creg, mqenc->ctreg, mqenc); - return jpc_mqenc_error(mqenc) ? (-1) : 0; + /* Note: This function only performs part of the work associated with + the CODEMPS algorithm from the standard. Some of the work is also + performed by the caller. */ + + jpc_mqstate_t *state = *(mqenc->curctx); + if (mqenc->areg < state->qeval) { + mqenc->areg = state->qeval; + } else { + mqenc->creg += state->qeval; + } + *mqenc->curctx = state->nmps; + jpc_mqenc_renorme(mqenc->areg, mqenc->creg, mqenc->ctreg, mqenc); + return jpc_mqenc_error(mqenc) ? (-1) : 0; } int jpc_mqenc_codelps(jpc_mqenc_t *mqenc) { - jpc_mqenc_codelps2(mqenc->areg, mqenc->creg, mqenc->ctreg, mqenc->curctx, mqenc); - return jpc_mqenc_error(mqenc) ? (-1) : 0; + jpc_mqenc_codelps2(mqenc->areg, mqenc->creg, mqenc->ctreg, mqenc->curctx, mqenc); + return jpc_mqenc_error(mqenc) ? (-1) : 0; } /******************************************************************************\ @@ -386,56 +386,56 @@ int jpc_mqenc_codelps(jpc_mqenc_t *mqenc) int jpc_mqenc_flush(jpc_mqenc_t *mqenc, int termmode) { - int_fast16_t k; - - switch (termmode) { - case JPC_MQENC_PTERM: - k = 11 - mqenc->ctreg + 1; - while (k > 0) { - mqenc->creg <<= mqenc->ctreg; - mqenc->ctreg = 0; - jpc_mqenc_byteout(mqenc->areg, mqenc->creg, mqenc->ctreg, - mqenc); - k -= mqenc->ctreg; - } - if (mqenc->outbuf != 0xff) { - jpc_mqenc_byteout(mqenc->areg, mqenc->creg, mqenc->ctreg, mqenc); - } - break; - case JPC_MQENC_DEFTERM: - jpc_mqenc_setbits(mqenc); - mqenc->creg <<= mqenc->ctreg; - jpc_mqenc_byteout(mqenc->areg, mqenc->creg, mqenc->ctreg, mqenc); - mqenc->creg <<= mqenc->ctreg; - jpc_mqenc_byteout(mqenc->areg, mqenc->creg, mqenc->ctreg, mqenc); - if (mqenc->outbuf != 0xff) { - jpc_mqenc_byteout(mqenc->areg, mqenc->creg, mqenc->ctreg, mqenc); - } - break; - default: - abort(); - break; - } - return 0; + int_fast16_t k; + + switch (termmode) { + case JPC_MQENC_PTERM: + k = 11 - mqenc->ctreg + 1; + while (k > 0) { + mqenc->creg <<= mqenc->ctreg; + mqenc->ctreg = 0; + jpc_mqenc_byteout(mqenc->areg, mqenc->creg, mqenc->ctreg, + mqenc); + k -= mqenc->ctreg; + } + if (mqenc->outbuf != 0xff) { + jpc_mqenc_byteout(mqenc->areg, mqenc->creg, mqenc->ctreg, mqenc); + } + break; + case JPC_MQENC_DEFTERM: + jpc_mqenc_setbits(mqenc); + mqenc->creg <<= mqenc->ctreg; + jpc_mqenc_byteout(mqenc->areg, mqenc->creg, mqenc->ctreg, mqenc); + mqenc->creg <<= mqenc->ctreg; + jpc_mqenc_byteout(mqenc->areg, mqenc->creg, mqenc->ctreg, mqenc); + if (mqenc->outbuf != 0xff) { + jpc_mqenc_byteout(mqenc->areg, mqenc->creg, mqenc->ctreg, mqenc); + } + break; + default: + abort(); + break; + } + return 0; } static void jpc_mqenc_setbits(jpc_mqenc_t *mqenc) { - uint_fast32_t tmp = mqenc->creg + mqenc->areg; - mqenc->creg |= 0xffff; - if (mqenc->creg >= tmp) { - mqenc->creg -= 0x8000; - } + uint_fast32_t tmp = mqenc->creg + mqenc->areg; + mqenc->creg |= 0xffff; + if (mqenc->creg >= tmp) { + mqenc->creg -= 0x8000; + } } /* Dump a MQ encoder to a stream for debugging. */ int jpc_mqenc_dump(jpc_mqenc_t *mqenc, FILE *out) { - fprintf(out, "AREG = %08x, CREG = %08x, CTREG = %d\n", - mqenc->areg, mqenc->creg, mqenc->ctreg); - fprintf(out, "IND = %02d, MPS = %d, QEVAL = %04x\n", - *mqenc->curctx - jpc_mqstates, (*mqenc->curctx)->mps, - (*mqenc->curctx)->qeval); - return 0; + fprintf(out, "AREG = %08x, CREG = %08x, CTREG = %d\n", + (unsigned)mqenc->areg, (unsigned)mqenc->creg, (int)mqenc->ctreg); + fprintf(out, "IND = %02d, MPS = %d, QEVAL = %04x\n", + (int)(*mqenc->curctx - jpc_mqstates), (int)(*mqenc->curctx)->mps, + (unsigned)(*mqenc->curctx)->qeval); + return 0; } diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_qmfb.c b/converter/other/jpeg2000/libjasper/jpc/jpc_qmfb.c index 1d41d5c5..80bc5aa5 100644 --- a/converter/other/jpeg2000/libjasper/jpc/jpc_qmfb.c +++ b/converter/other/jpeg2000/libjasper/jpc/jpc_qmfb.c @@ -900,8 +900,8 @@ static void jpc_ns_analyze(jpc_qmfb1d_t *qmfb, int flags, jas_seq2d_t *x) startptr += interstep; } } else { - /* The reversible integer-to-integer mode is not supported - for this transform. */ + /* The reversible integer-to-integer mode is not valid for this + transform. */ abort(); } } @@ -973,8 +973,8 @@ static void jpc_ns_synthesize(jpc_qmfb1d_t *qmfb, int flags, jas_seq2d_t *x) startptr += interstep; } } else { - /* The reversible integer-to-integer mode is not supported - for this transform. */ + /* The reversible integer-to-integer mode is not valid + for this transform. */ abort(); } } diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_t2cod.h b/converter/other/jpeg2000/libjasper/jpc/jpc_t2cod.h index 05f41b9e..82dafcce 100644 --- a/converter/other/jpeg2000/libjasper/jpc/jpc_t2cod.h +++ b/converter/other/jpeg2000/libjasper/jpc/jpc_t2cod.h @@ -136,7 +136,7 @@ typedef struct { /* The number of progression changes. */ int numpchgs; - /* The maximum number of progression changes that can be accomodated + /* The maximum number of progression changes that can be accommodated without growing the progression change array. */ int maxpchgs; @@ -253,7 +253,7 @@ typedef struct { /* The progression change list. */ jpc_pchglist_t *pchglist; - /* The progression to use in the absense of explicit specification. */ + /* The progression to use in the absence of explicit specification. */ jpc_pchg_t defaultpchg; /* The current progression change number. */ diff --git a/converter/other/jpeg2000/pamtojpeg2k.c b/converter/other/jpeg2000/pamtojpeg2k.c index 70774725..b8905518 100644 --- a/converter/other/jpeg2000/pamtojpeg2k.c +++ b/converter/other/jpeg2000/pamtojpeg2k.c @@ -9,17 +9,24 @@ *****************************************************************************/ #define _BSD_SOURCE 1 /* Make sure strdup() is in string.h */ -/* Make sure strdup() is in string.h and int_fast32_t is in inttypes.h */ -#define _XOPEN_SOURCE 600 +#define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */ + /* In 2014.09, this was _XOPEN_SOURCE 600, with a comment saying it was + necessary to make define int_fast32_t, etc. on AIX. + does use int_fast32_t and does include , + but plenty of source files of libjasper do too, and they did not have + _XOPEN_SOURCE 600, so it would seem to be superfluous here too. + */ + #include +#include + #include "pm_c_util.h" #include "pam.h" #include "shhopt.h" #include "nstring.h" #include "mallocvar.h" -#include #include "libjasper_compat.h" @@ -43,7 +50,8 @@ struct cmdlineInfo { unsigned int cblkwidth; unsigned int cblkheight; enum compmode compmode; - float compressionRatio; + unsigned int compressionSpec; + float compression; char * ilyrrates; enum progression progression; unsigned int numrlvls; @@ -81,7 +89,7 @@ parseCommandLine(int argc, char ** argv, unsigned int tilewidthSpec, tileheightSpec; unsigned int prcwidthSpec, prcheightSpec; unsigned int cblkwidthSpec, cblkheightSpec; - unsigned int modeSpec, compressionSpec, ilyrratesSpec; + unsigned int modeSpec, ilyrratesSpec; unsigned int progressionSpec, numrlvlsSpec, numgbitsSpec; unsigned int debuglevelSpec; @@ -115,8 +123,8 @@ parseCommandLine(int argc, char ** argv, &cblkheightSpec, 0); OPTENT3(0, "mode", OPT_STRING, &modeOpt, &modeSpec, 0); - OPTENT3(0, "compression", OPT_FLOAT, &cmdlineP->compressionRatio, - &compressionSpec, 0); + OPTENT3(0, "compression", OPT_FLOAT, &cmdlineP->compression, + &cmdlineP->compressionSpec, 0); OPTENT3(0, "ilyrrates", OPT_STRING, &cmdlineP->ilyrrates, &ilyrratesSpec, 0); OPTENT3(0, "progression", OPT_STRING, &progressionOpt, @@ -152,7 +160,7 @@ parseCommandLine(int argc, char ** argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); if (!imgareatlxSpec) cmdlineP->imgareatlx = 0; @@ -184,11 +192,6 @@ parseCommandLine(int argc, char ** argv, "valid values are 'INTEGER' and 'REAL'", modeOpt); } else cmdlineP->compmode = COMPMODE_INTEGER; - if (compressionSpec) { - if (cmdlineP->compressionRatio < 1.0) - pm_error("Compression ratio less than 1 does not make sense."); - } else - cmdlineP->compressionRatio = 1.0; if (!ilyrratesSpec) cmdlineP->ilyrrates = (char*) ""; if (progressionSpec) { @@ -230,7 +233,10 @@ parseCommandLine(int argc, char ** argv, static void createJasperRaster(struct pam * const inpamP, jas_image_t * const jasperP) { - +/*---------------------------------------------------------------------------- + Create the raster in the *jasperP object, reading the raster from the + input file described by *inpamP, which is positioned to the raster. +-----------------------------------------------------------------------------*/ jas_matrix_t ** matrix; /* malloc'ed */ /* matrix[X] is the data for Plane X of the current row */ unsigned int plane; @@ -380,7 +386,7 @@ writeJpc(jas_image_t * const jasperP, specifying garbage for the -ilyrrates option */ if (strlen(cmdline.ilyrrates) > 0) - asprintfN(&ilyrratesOpt, "ilyrrates=%s", cmdline.ilyrrates); + pm_asprintf(&ilyrratesOpt, "ilyrrates=%s", cmdline.ilyrrates); else ilyrratesOpt = strdup(""); @@ -394,55 +400,62 @@ writeJpc(jas_image_t * const jasperP, /* Note that asprintfN() doesn't understand %f, but sprintf() does */ - sprintf(rateOpt, "%1.9f", 1.0/cmdline.compressionRatio); - - asprintfN(&options, - "imgareatlx=%u " - "imgareatly=%u " - "tilegrdtlx=%u " - "tilegrdtly=%u " - "tilewidth=%u " - "tileheight=%u " - "prcwidth=%u " - "prcheight=%u " - "cblkwidth=%u " - "cblkheight=%u " - "mode=%s " - "rate=%s " - "%s " - "prg=%s " - "numrlvls=%u " - "numgbits=%u " - "%s %s %s %s %s %s %s %s %s", - - cmdline.imgareatlx, - cmdline.imgareatly, - cmdline.tilegrdtlx, - cmdline.tilegrdtlx, - cmdline.tilewidth, - cmdline.tileheight, - cmdline.prcwidth, - cmdline.prcheight, - cmdline.cblkwidth, - cmdline.cblkheight, - cmdline.compmode == COMPMODE_INTEGER ? "int" : "real", - rateOpt, - ilyrratesOpt, - prgValue, - cmdline.numrlvls, - cmdline.numgbits, - cmdline.nomct ? "nomct" : "", - cmdline.sop ? "sop" : "", - cmdline.eph ? "eph" : "", - cmdline.lazy ? "lazy" : "", - cmdline.termall ? "termall" : "", - cmdline.segsym ? "segsym" : "", - cmdline.vcausal ? "vcausal" : "", - cmdline.pterm ? "pterm" : "", - cmdline.resetprob ? "resetprob" : "" + if (cmdline.compressionSpec) + sprintf(rateOpt, "rate=%1.9f", 1.0/cmdline.compression); + else { + /* No 'rate' option. This means there is no constraint on the image + size, so the encoder will compress losslessly. Note that the + image may get larger, because of metadata. + */ + rateOpt[0] = '\0'; + } + pm_asprintf(&options, + "imgareatlx=%u " + "imgareatly=%u " + "tilegrdtlx=%u " + "tilegrdtly=%u " + "tilewidth=%u " + "tileheight=%u " + "prcwidth=%u " + "prcheight=%u " + "cblkwidth=%u " + "cblkheight=%u " + "mode=%s " + "%s " /* rate */ + "%s " /* ilyrrates */ + "prg=%s " + "numrlvls=%u " + "numgbits=%u " + "%s %s %s %s %s %s %s %s %s", + + cmdline.imgareatlx, + cmdline.imgareatly, + cmdline.tilegrdtlx, + cmdline.tilegrdtlx, + cmdline.tilewidth, + cmdline.tileheight, + cmdline.prcwidth, + cmdline.prcheight, + cmdline.cblkwidth, + cmdline.cblkheight, + cmdline.compmode == COMPMODE_INTEGER ? "int" : "real", + rateOpt, + ilyrratesOpt, + prgValue, + cmdline.numrlvls, + cmdline.numgbits, + cmdline.nomct ? "nomct" : "", + cmdline.sop ? "sop" : "", + cmdline.eph ? "eph" : "", + cmdline.lazy ? "lazy" : "", + cmdline.termall ? "termall" : "", + cmdline.segsym ? "segsym" : "", + cmdline.vcausal ? "vcausal" : "", + cmdline.pterm ? "pterm" : "", + cmdline.resetprob ? "resetprob" : "" ); - strfree(ilyrratesOpt); + pm_strfree(ilyrratesOpt); /* Open the output image file (Standard Output) */ outStreamP = jas_stream_fdopen(fileno(ofP), "w+b"); @@ -459,7 +472,7 @@ writeJpc(jas_image_t * const jasperP, rc = jas_image_encode(jasperP, outStreamP, jas_image_strtofmt((char*)"jpc"), - (char*)options); + (char *)options); if (rc != 0) pm_error("jas_image_encode() failed to encode the JPEG 2000 " "image. Rc=%d", rc); @@ -478,7 +491,7 @@ writeJpc(jas_image_t * const jasperP, jas_image_clearfmts(); - strfree(options); + pm_strfree(options); } @@ -487,7 +500,7 @@ int main(int argc, char **argv) { struct cmdlineInfo cmdline; - FILE *ifP; + FILE * ifP; struct pam inpam; jas_image_t * jasperP; diff --git a/converter/other/jpegtopnm.c b/converter/other/jpegtopnm.c index 07a7dfb0..ab3b18e5 100644 --- a/converter/other/jpegtopnm.c +++ b/converter/other/jpegtopnm.c @@ -22,7 +22,7 @@ Extend pamtoppm to convert this to ppm using the standard transformation. - See if additional decompressor options effects signficant speedup. + See if additional decompressor options effects significant speedup. grayscale output of color image, downscaling, color quantization, and dithering are possibilities. Djpeg's man page says they make it faster. @@ -173,7 +173,7 @@ parseCommandLine(int const argc, not change argv at all. -----------------------------------------------------------------------------*/ optEntry *option_def; - /* Instructions to optParseOptions3 on how to parse our options. + /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; @@ -216,12 +216,12 @@ parseCommandLine(int const argc, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We may have parms that are negative numbers */ - /* Make private copy of arguments for optParseOptions to corrupt */ + /* Make private copy of arguments for pm_optParseOptions to corrupt */ argc_parse = argc; for (i=0; i < argc; ++i) argv_parse[i] = argv[i]; - optParseOptions3( &argc_parse, argv_parse, opt, sizeof(opt), 0); + pm_optParseOptions3( &argc_parse, argv_parse, opt, sizeof(opt), 0); /* Uses and sets argc_parse, argv_parse, and some of *cmdlineP and others. */ @@ -582,7 +582,7 @@ print_verbose_info_about_header(struct jpeg_decompress_struct const cinfo){ colorspace_name(cinfo.jpeg_color_space)); /* Note that raw information about marker, including marker type code, - was already printed by the jpeg library, due to the jpeg library + was already printed by the jpeg library, because of the jpeg library trace level >= 1. Our job is to interpret it a little bit. */ if (cinfo.marker_list) @@ -652,19 +652,20 @@ print_exif_info(struct jpeg_marker_struct const marker) { Dump as informational messages the contents of the Jpeg miscellaneous marker 'marker', assuming it is an Exif header. -----------------------------------------------------------------------------*/ - ImageInfo_t imageInfo; + bool const wantTagTrace = false; + exif_ImageInfo imageInfo; const char * error; assert(marker.data_length >= 6); - process_EXIF(marker.data+6, marker.data_length-6, - &imageInfo, FALSE, &error); + exif_parse(marker.data+6, marker.data_length-6, + &imageInfo, wantTagTrace, &error); if (error) { pm_message("EXIF header is invalid. %s", error); - strfree(error); + pm_strfree(error); } else - ShowImageInfo(&imageInfo); + exif_showImageInfo(&imageInfo, stderr); } @@ -700,8 +701,7 @@ dump_exif(struct jpeg_decompress_struct const cinfo) { found_one = FALSE; /* initial value */ - for (markerP = cinfo.marker_list; - markerP; markerP = markerP->next) + for (markerP = cinfo.marker_list; markerP; markerP = markerP->next) if (is_exif(*markerP)) { pm_message("EXIF INFO:"); print_exif_info(*markerP); diff --git a/converter/other/pamrgbatopng.c b/converter/other/pamrgbatopng.c deleted file mode 100644 index 7babf9f9..00000000 --- a/converter/other/pamrgbatopng.c +++ /dev/null @@ -1,150 +0,0 @@ -#include -#include -#include -#include - -#include "pam.h" -#include "mallocvar.h" - -struct cmdlineInfo { - const char * inputFileName; -}; - - - -static void -processCommandLine(int const argc, - char * const argv[], - struct cmdlineInfo * const cmdlineP) { - - if (argc-1 < 1) - cmdlineP->inputFileName = "-"; - else { - cmdlineP->inputFileName = argv[1]; - - if (argc-1 > 1) - pm_error("Too many arguments. " - "The only argument is the input file name."); - } -} - - - -static void -convertPamToPng(const struct pam * const pamP, - const tuple * const tuplerow, - png_byte * const pngRow) { - - unsigned int col; - - for (col = 0; col < pamP->width; ++col) { - unsigned int plane; - - for (plane = 0; plane < 4; ++plane) - pngRow[4 * col + plane] = tuplerow[col][plane]; - } -} - - - -static void -writeRaster(const struct pam * const pamP, - png_struct * const pngP) { - - tuple * tupleRow; - png_byte * pngRow; - - tupleRow = pnm_allocpamrow(pamP); - MALLOCARRAY(pngRow, pamP->width * 4); - - if (pngRow == NULL) - pm_error("Unable to allocate space for PNG pixel row."); - else { - unsigned int row; - for (row = 0; row < pamP->height; ++row) { - pnm_readpamrow(pamP, tupleRow); - - convertPamToPng(pamP, tupleRow, pngRow); - - png_write_row(pngP, pngRow); - } - free(pngRow); - } - pnm_freepamrow(tupleRow); -} - - - -static void -pngErrorHandler(png_struct * const pngP, - const char * const message) { - - pm_error("Error generating PNG image. libpng says: %s", message); -} - - - -static void -writePng(const struct pam * const pamP, - FILE * const ofP) { - - png_struct * pngP; - png_info * infoP; - - pngP = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!pngP) - pm_error("Could not allocate png struct."); - - png_set_error_fn(pngP, NULL, &pngErrorHandler, NULL); - - infoP = png_create_info_struct(pngP); - if (!infoP) - pm_error("Could not allocate PNG info structure"); - else { - infoP->width = pamP->width; - infoP->height = pamP->height; - infoP->bit_depth = 8; - infoP->color_type = PNG_COLOR_TYPE_RGB_ALPHA; - - png_init_io(pngP, ofP); - - png_write_info(pngP, infoP); - - writeRaster(pamP, pngP); - - png_write_end(pngP, infoP); - - png_destroy_write_struct(&pngP, &infoP); - } -} - - - -int -main(int argc, char * argv[]) { - - FILE * ifP; - struct cmdlineInfo cmdline; - struct pam pam; - - pnm_init(&argc, argv); - - processCommandLine(argc, argv, &cmdline); - - ifP = pm_openr(cmdline.inputFileName); - - pnm_readpaminit(ifP, &pam, PAM_STRUCT_SIZE(tuple_type)); - - if (pam.depth < 4) - pm_error("PAM must have depth at least 4 (red, green, blue, alpha). " - "This one has depth %u", pam.depth); - - if (pam.maxval != 255) - pm_error("PAM must have maxval 255. This one has %lu", pam.maxval); - - writePng(&pam, stdout); - - pm_close(ifP); - - return 0; -} diff --git a/converter/other/pamtoavs.c b/converter/other/pamtoavs.c new file mode 100644 index 00000000..4764c9e8 --- /dev/null +++ b/converter/other/pamtoavs.c @@ -0,0 +1,150 @@ +/* ---------------------------------------------------------------------- + * + * Convert a PAM image to an AVS X image + * + * By Scott Pakin + * + * ---------------------------------------------------------------------- + * + * Copyright (C) 2010 Scott Pakin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + * ---------------------------------------------------------------------- + */ + +#include +#include "pm.h" +#include "pam.h" + + + +static char +sample2char(sample const s, + sample const maxval) { +/* Scale down a sample to a single byte. */ + + return maxval==255 ? s : s * 255 / maxval; +} + + +#define THIS_SAMPLE_CHAR(PLANE) \ + sample2char(tuplerow[col][PLANE], pamP->maxval) + +static void +produceAvs(struct pam * const pamP, + FILE * const avsFileP) { + + tuple * tuplerow; + + /* Write the AVS header (image width and height as 4-byte + big-endian integers). + */ + pm_writebiglong(avsFileP, pamP->width); + pm_writebiglong(avsFileP, pamP->height); + + /* Write the AVS data (alpha, red, green, blue -- one byte apiece. */ + tuplerow = pnm_allocpamrow(pamP); + switch (pamP->depth) { + case 1: { + /* Black-and-white or grayscale, no alpha */ + unsigned int row; + for (row = 0; row < pamP->height; ++row) { + unsigned int col; + pnm_readpamrow(pamP, tuplerow); + for (col = 0; col < pamP->width; ++col) { + pm_writechar(avsFileP, (char)255); + pm_writechar(avsFileP, THIS_SAMPLE_CHAR(0)); + pm_writechar(avsFileP, THIS_SAMPLE_CHAR(0)); + pm_writechar(avsFileP, THIS_SAMPLE_CHAR(0)); + } + } + } break; + + case 2: { + /* Black-and-white or grayscale plus alpha */ + unsigned int row; + for (row = 0; row < pamP->height; ++row) { + unsigned int col; + pnm_readpamrow(pamP, tuplerow); + for (col = 0; col < pamP->width; ++col) { + pm_writechar(avsFileP, THIS_SAMPLE_CHAR(1)); + pm_writechar(avsFileP, THIS_SAMPLE_CHAR(0)); + pm_writechar(avsFileP, THIS_SAMPLE_CHAR(0)); + pm_writechar(avsFileP, THIS_SAMPLE_CHAR(0)); + } + } + } break; + + case 3: { + /* RGB, no alpha */ + unsigned int row; + for (row = 0; row < pamP->height; ++row) { + unsigned int col; + pnm_readpamrow(pamP, tuplerow); + for (col = 0; col < pamP->width; ++col) { + pm_writechar(avsFileP, (char)255); + pm_writechar(avsFileP, THIS_SAMPLE_CHAR(0)); + pm_writechar(avsFileP, THIS_SAMPLE_CHAR(1)); + pm_writechar(avsFileP, THIS_SAMPLE_CHAR(2)); + } + } + } break; + + case 4: { + /* RGB plus alpha */ + unsigned int row; + for (row = 0; row < pamP->height; ++row) { + unsigned int col; + pnm_readpamrow( pamP, tuplerow ); + for (col = 0; col < pamP->width; ++col) { + pm_writechar(avsFileP, THIS_SAMPLE_CHAR(3)); + pm_writechar(avsFileP, THIS_SAMPLE_CHAR(0)); + pm_writechar(avsFileP, THIS_SAMPLE_CHAR(1)); + pm_writechar(avsFileP, THIS_SAMPLE_CHAR(2)); + } + } + } break; + + default: + pm_error("Unrecognized PAM depth %u. We understand only " + "1, 2, 3, and 4", pamP->depth); + break; + } + pnm_freepamrow(tuplerow); +} + + + +int +main(int argc, const char *argv[]) { + struct pam inPam; + const char * inputFilename; + FILE * inFileP; + + pm_proginit(&argc, argv); + + inputFilename = (argc > 1) ? argv[1] : "-"; + + inFileP = pm_openr(inputFilename); + + pnm_readpaminit(inFileP, &inPam, PAM_STRUCT_SIZE(tuple_type)); + + produceAvs(&inPam, stdout); + + pm_closer(inFileP); + + return 0; +} + diff --git a/converter/other/pamtodjvurle.c b/converter/other/pamtodjvurle.c index 2d26eeb0..cae9e026 100644 --- a/converter/other/pamtodjvurle.c +++ b/converter/other/pamtodjvurle.c @@ -45,7 +45,7 @@ parseCommandLine(int argc, was passed to us as the argv array. We also trash *argv. --------------------------------------------------------------------------*/ optEntry *option_def = malloc( 100*sizeof( optEntry ) ); - /* Instructions to optParseOptions3 on how to parse our options. */ + /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; unsigned int option_def_index; @@ -61,7 +61,7 @@ parseCommandLine(int argc, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3( &argc, argv, opt, sizeof(opt), 0 ); + pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0 ); /* Uses and sets argc, argv, and some of *cmdline_p and others. */ if (!transparentSpec) diff --git a/converter/other/pamtofits.c b/converter/other/pamtofits.c index 7a1c70de..92e29c7e 100644 --- a/converter/other/pamtofits.c +++ b/converter/other/pamtofits.c @@ -59,7 +59,7 @@ parseCommandLine(int argc, char ** argv, was passed to us as the argv array. We also trash *argv. --------------------------------------------------------------------------*/ optEntry * option_def; - /* Instructions to optParseOptions3 on how to parse our options. */ + /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; unsigned int minSpec; @@ -79,7 +79,7 @@ parseCommandLine(int argc, char ** argv, /* Set some defaults the lazy way (using multiple setting of variables) */ - optParseOptions3( &argc, argv, opt, sizeof(opt), 0 ); + pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0 ); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (!minSpec) @@ -111,11 +111,11 @@ writeHeaderCard(const char * const s) { -----------------------------------------------------------------------------*/ const char * card; - asprintfN(&card, "%-80.80s", s); + pm_asprintf(&card, "%-80.80s", s); fwrite(card, sizeof(card[0]), 80, stdout); - strfree(card); + pm_strfree(card); } diff --git a/converter/other/pamtogif.c b/converter/other/pamtogif.c index 0c8c0f9e..aabf7fc2 100644 --- a/converter/other/pamtogif.c +++ b/converter/other/pamtogif.c @@ -35,7 +35,7 @@ typedef int stringCode; changes throughout the image. A variable of this type sometimes has the value -1 instead of - a string code due to cheesy programming. + a string code because of cheesy programming. Ergo, this data structure must be signed and at least BITS bits wide plus sign bit. @@ -163,7 +163,7 @@ parseCommandLine(int argc, char ** argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (argc-1 == 0) @@ -220,7 +220,7 @@ closestColor(tuple const color, unsigned int i; unsigned int imin, dmin; - bool fits; + int fits; dmin = UINT_MAX; imin = 0; @@ -627,11 +627,11 @@ static void byteBuffer_out(byteBuffer * const byteBufferP, unsigned char const c) { /*---------------------------------------------------------------------------- - Add a byte to the end of the current data block, and if it is now 254 + Add a byte to the end of the current data block, and if it is now 255 characters, flush the data block to the output file. -----------------------------------------------------------------------------*/ byteBufferP->buffer[byteBufferP->count++] = c; - if (byteBufferP->count >= 254) + if (byteBufferP->count >= 255) byteBuffer_flush(byteBufferP); } @@ -893,7 +893,7 @@ lzw_create(FILE * const ofP, Above that we use a table with 4096 slots plus 20% extra. When this is not enough the clear code is emitted. - Due to the extra 20% the table itself never fills up. + Because of the extra 20% the table itself never fills up. lzw.hsize and lzw.hshift stay constant through the image. @@ -1544,7 +1544,7 @@ computeTransparent(char const colorarg[], const char * colorspec; bool exact; tuple transcolor; - bool found; + int found; int colorindex; if (colorarg[0] == '=') { diff --git a/converter/other/pamtohdiff.c b/converter/other/pamtohdiff.c index 2d5f6a61..8d785f5b 100644 --- a/converter/other/pamtohdiff.c +++ b/converter/other/pamtohdiff.c @@ -38,7 +38,7 @@ parseCommandLine(int argc, char ** argv, was passed to us as the argv array. -----------------------------------------------------------------------------*/ optEntry *option_def = malloc( 100*sizeof( optEntry ) ); - /* Instructions to optParseOptions3 on how to parse our options. + /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; @@ -51,7 +51,7 @@ parseCommandLine(int argc, char ** argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3( &argc, argv, opt, sizeof(opt), 0 ); + pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0 ); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (argc-1 < 1) diff --git a/converter/other/pamtohtmltbl.c b/converter/other/pamtohtmltbl.c index 5335ff9f..d1482073 100644 --- a/converter/other/pamtohtmltbl.c +++ b/converter/other/pamtohtmltbl.c @@ -33,7 +33,7 @@ parseCommandLine(int argc, char ** argv, was passed to us as the argv array. We also trash *argv. -----------------------------------------------------------------------------*/ optEntry * option_def; - /* Instructions to optParseOptions3 on how to parse our options. + /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; @@ -53,7 +53,7 @@ parseCommandLine(int argc, char ** argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3( &argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ diff --git a/converter/other/pamtompfont.c b/converter/other/pamtompfont.c index ba170fef..92f8de29 100644 --- a/converter/other/pamtompfont.c +++ b/converter/other/pamtompfont.c @@ -42,7 +42,7 @@ parseCommandLine(int argc, char ** argv, Note that the file spec array we return is stored in the storage that was passed to us as the argv array. -----------------------------------------------------------------------------*/ - optEntry *option_def; + optEntry * option_def; /* Instructions to OptParseOptions3 on how to parse our options. */ optStruct3 opt; @@ -59,7 +59,7 @@ parseCommandLine(int argc, char ** argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (argc-1 == 0) @@ -69,6 +69,8 @@ parseCommandLine(int argc, char ** argv, "specified %d", argc-1); else cmdlineP->inputFilename = argv[1]; + + free(option_def); } diff --git a/converter/other/pamtooctaveimg.c b/converter/other/pamtooctaveimg.c index b090281d..28bc4cd4 100644 --- a/converter/other/pamtooctaveimg.c +++ b/converter/other/pamtooctaveimg.c @@ -75,13 +75,13 @@ findOrAddColor(tuple const color, colormap *cmapP. If the color isn't in the map, give it a new colormap index, put it in the colormap, and return that. -----------------------------------------------------------------------------*/ - bool found; + int found; int colorIndex; pnm_lookuptuple(&cmapP->pam, cmapP->hash, color, &found, &colorIndex); if (!found) { - bool fits; + int fits; unsigned int plane; colorIndex = cmapP->nColors++; diff --git a/converter/other/pamtopam.c b/converter/other/pamtopam.c index cae54060..9cb82f7a 100644 --- a/converter/other/pamtopam.c +++ b/converter/other/pamtopam.c @@ -17,7 +17,7 @@ int main(int argc, const char * argv[]) { - bool eof; /* no more images in input stream */ + int eof; /* no more images in input stream */ struct pam inpam; /* Input PAM image */ struct pam outpam; /* Output PAM image */ diff --git a/converter/other/pamtopdbimg.c b/converter/other/pamtopdbimg.c new file mode 100644 index 00000000..6454292e --- /dev/null +++ b/converter/other/pamtopdbimg.c @@ -0,0 +1,810 @@ +/*============================================================================= + pamtopdbimg +=============================================================================== + + Convert Netpbm image to Palm Pilot PDB Image format (for viewing by + Pilot Image Viewer). + + Bryan Henderson derived this from Eric Howe's programs named + 'pgmtoimgv' and 'pbmtoimgv' in September 2010. +=============================================================================*/ +/* + * Copyright (C) 1997 Eric A. Howe + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors: Eric A. Howe (mu@trends.net) + * Bryan Henderson, September 2010. + */ + +#include +#include +#include +#include + +#include "pm_c_util.h" +#include "mallocvar.h" +#include "nstring.h" +#include "shhopt.h" +#include "pam.h" + +#include "ipdb.h" + +enum CompMode {COMPRESSED, MAYBE, UNCOMPRESSED}; + +struct cmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + const char * inputFileName; /* '-' if stdin */ + const char * title; + const char * notefile; /* NULL if not specified */ + enum CompMode compMode; + unsigned int depth4; +}; + + + +static void +parseCommandLine(int argc, const char ** argv, + struct cmdlineInfo * const cmdlineP) { +/*---------------------------------------------------------------------------- + parse program command line described in Unix standard form by argc + and argv. Return the information in the options as *cmdlineP. + + If command line is internally inconsistent (invalid options, etc.), + issue error message to stderr and abort program. + + Note that the strings we return are stored in the storage that + was passed to us as the argv array. We also trash *argv. +-----------------------------------------------------------------------------*/ + optEntry *option_def; + /* Instructions to pm_optParseOptions3 on how to parse our options. + */ + optStruct3 opt; + + unsigned int option_def_index; + + unsigned int titleSpec, notefileSpec; + unsigned int compressed, maybeCompressed, uncompressed; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENT3 */ + OPTENT3(0, "title", OPT_STRING, &cmdlineP->title, + &titleSpec, 0); + OPTENT3(0, "notefile", OPT_STRING, &cmdlineP->notefile, + ¬efileSpec, 0); + OPTENT3(0, "compressed", OPT_FLAG, NULL, + &compressed, 0); + OPTENT3(0, "maybecompressed", OPT_FLAG, NULL, + &maybeCompressed, 0); + OPTENT3(0, "uncompressed", OPT_FLAG, NULL, + &uncompressed, 0); + OPTENT3(0, "4depth", OPT_FLAG, NULL, + &cmdlineP->depth4, 0); + + opt.opt_table = option_def; + opt.short_allowed = false; /* We have no short (old-fashioned) options */ + opt.allowNegNum = false; /* We have no parms that are negative numbers */ + + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + + if (!titleSpec) + cmdlineP->title = "unnamed"; + + if (!notefileSpec) + cmdlineP->notefile = NULL; + + if (compressed + uncompressed + maybeCompressed > 1) + pm_error("You may specify only one of -compressed, -uncompressed, " + "-maybecompressed"); + if (compressed) + cmdlineP->compMode = COMPRESSED; + else if (uncompressed) + cmdlineP->compMode = UNCOMPRESSED; + else if (maybeCompressed) + cmdlineP->compMode = MAYBE; + else + cmdlineP->compMode = MAYBE; + + if (argc-1 < 1) + cmdlineP->inputFileName = "-"; + else if (argc-1 == 1) + cmdlineP->inputFileName = argv[1]; + else + pm_error("Program takes at most one argument: input file name"); +} + + + +/* + * Pixel setting macros. + */ +#define setg16pixel(b,v,o) ((b) |= ((v) << (4 - 4*(o)))) +#define setgpixel(b,v,o) ((b) |= ((v) << (6 - 2*(o)))) +#define setmpixelblack(b,o) ((b) |= (1 << (7 - (o)))) + + + +static int +pdbheadWrite(PDBHEAD * const pdbheadP, + FILE * const fileP) { + + fwrite(pdbheadP->name, 1, 32, fileP); + pm_writebigshort(fileP, pdbheadP->flags); + pm_writebigshort(fileP, pdbheadP->version); + pm_writebiglong(fileP, pdbheadP->ctime); + pm_writebiglong(fileP, pdbheadP->mtime); + pm_writebiglong(fileP, pdbheadP->btime); + pm_writebiglong(fileP, pdbheadP->mod_num); + pm_writebiglong(fileP, pdbheadP->app_info); + pm_writebiglong(fileP, pdbheadP->sort_info); + fwrite(pdbheadP->type, 1, 4, fileP); + fwrite(pdbheadP->id, 1, 4, fileP); + pm_writebiglong(fileP, pdbheadP->uniq_seed); + pm_writebiglong(fileP, pdbheadP->next_rec); + pm_writebigshort(fileP, pdbheadP->num_recs); + + return 0; +} + + + +static int +rechdrWrite(RECHDR * const rechdrP, + FILE * const fileP) { + + if (rechdrP) { + pm_writebiglong(fileP, rechdrP->offset); + fwrite(rechdrP->unknown, 1, 3, fileP); + fwrite(&rechdrP->rec_type, 1, 1, fileP); + + if (rechdrP->n_extra != 0) + fwrite(rechdrP->extra, 1, rechdrP->n_extra, fileP); + } + return 0; +} + + + +static void +imageWriteHeader(IMAGE * const imgP, + FILE * const fileP) { + + fwrite(imgP->name, 1, 32, fileP); + fwrite(&imgP->version, 1, 1, fileP); + fwrite(&imgP->type, 1, 1, fileP); + fwrite(imgP->reserved1, 1, 4, fileP); + fwrite(imgP->note, 1, 4, fileP); + pm_writebigshort(fileP, imgP->x_last); + pm_writebigshort(fileP, imgP->y_last); + fwrite(imgP->reserved2, 1, 4, fileP); + pm_writebigshort(fileP, imgP->x_anchor); + pm_writebigshort(fileP, imgP->y_anchor); + pm_writebigshort(fileP, imgP->width); + pm_writebigshort(fileP, imgP->height); +} + + + +static void +imageWriteData(IMAGE * const imgP, + const uint8_t * const data, + size_t const dataSize, + FILE * const fileP) { + + fwrite(data, 1, dataSize, fileP); +} + + + +static void +imageWrite(IMAGE * const imgP, + uint8_t * const data, + size_t const dataSize, + FILE * const fileP) { + + imageWriteHeader(imgP, fileP); + + imageWriteData(imgP, data, dataSize, fileP); +} + + + +static int +textWrite(TEXT * const textP, + FILE * const fileP) { + + if (textP) + fwrite(textP->data, 1, strlen(textP->data), fileP); + + return 0; +} + + + +typedef struct { + unsigned int match; + uint8_t buf[128]; + int mode; + size_t len; + size_t used; + uint8_t * p; +} RLE; +#define MODE_MATCH 0 +#define MODE_LIT 1 +#define MODE_NONE 2 + +#define reset(r) { \ + (r)->match = 0xffff; \ + (r)->mode = MODE_NONE; \ + (r)->len = 0; \ + } + + + +static void +putMatch(RLE * const rleP, + size_t const n) { + + *rleP->p++ = 0x80 + n - 1; + *rleP->p++ = rleP->match; + rleP->used += 2; + reset(rleP); +} + + + +static void +putLit(RLE * const rleP, + size_t const n) { + + *rleP->p++ = n - 1; + rleP->p = (uint8_t *)memcpy(rleP->p, rleP->buf, n) + n; + rleP->used += n + 1; + reset(rleP); +} + + + +static size_t +compress(const uint8_t * const inData, + size_t const n_in, + uint8_t * const out) { + + static void (*put[])(RLE *, size_t) = {putMatch, putLit}; + RLE rle; + size_t i; + const uint8_t * p; + + MEMSZERO(&rle); + rle.p = out; + reset(&rle); + + for (i = 0, p = &inData[0]; i < n_in; ++i, ++p) { + if (*p == rle.match) { + if (rle.mode == MODE_LIT && rle.len > 1) { + putLit(&rle, rle.len - 1); + ++rle.len; + rle.match = *p; + } + rle.mode = MODE_MATCH; + ++rle.len; + } else { + if (rle.mode == MODE_MATCH) + putMatch(&rle, rle.len); + rle.mode = MODE_LIT; + rle.match = *p; + rle.buf[rle.len++] = *p; + } + if (rle.len == 128) + put[rle.mode](&rle, rle.len); + } + if (rle.len != 0) + put[rle.mode](&rle, rle.len); + + return rle.used; +} + + + +static void +compressIfRequired(IPDB * const pdbP, + int const comp, + uint8_t ** const compressedDataP, + size_t * const compressedSizeP) { + + if (comp == IPDB_NOCOMPRESS) { + *compressedDataP = pdbP->i->data; + *compressedSizeP = ipdb_img_size(pdbP->i); + } else { + int const uncompressedSz = ipdb_img_size(pdbP->i); + + /* Allocate for the worst case. */ + size_t const allocSz = (3 * uncompressedSz + 2)/2; + + uint8_t * data; + + data = pdbP->i->data; + + MALLOCARRAY(data, allocSz); + + if (data == NULL) + pm_error("Could not get %lu bytes of memory to decompress", + (unsigned long)allocSz); + else { + size_t compressedSz; + compressedSz = compress(pdbP->i->data, uncompressedSz, data); + if (comp == IPDB_COMPMAYBE && compressedSz >= uncompressedSz) { + /* Return the uncompressed data */ + free(data); + *compressedDataP = pdbP->i->data; + *compressedSizeP = uncompressedSz; + } else { + pdbP->i->compressed = TRUE; + if (pdbP->i->type == IMG_GRAY16) + pdbP->i->version = 9; + else + pdbP->i->version = 1; + if (pdbP->t != NULL) + pdbP->t->r->offset -= uncompressedSz - compressedSz; + *compressedDataP = data; + *compressedSizeP = compressedSz; + } + } + } +} + + + +static void +ipdbWrite(IPDB * const pdbP, + int const comp, + FILE * const fileP) { + + RECHDR * const trP = pdbP->t == NULL ? NULL : pdbP->t->r; + RECHDR * const irP = pdbP->i->r; + + int rc; + uint8_t * compressedData; + /* This is the image raster, compressed as required. + (I.e. if it doesn't have to be compressed, it isn't). + */ + size_t compressedSize; + + assert(pdbP->i); + + compressIfRequired(pdbP, comp, &compressedData, &compressedSize); + + rc = pdbheadWrite(pdbP->p, fileP); + if (rc != 0) + pm_error("Failed to write PDB header. %s", ipdb_err(rc)); + + rc = rechdrWrite(irP, fileP); + if (rc != 0) + pm_error("Failed to write image record header. %s", ipdb_err(rc)); + + rc = rechdrWrite(trP, fileP); + if (rc != 0) + pm_error("Failed to write text record header. %s", ipdb_err(rc)); + + imageWrite(pdbP->i, compressedData, compressedSize, fileP); + + rc = textWrite(pdbP->t, fileP); + if (rc != 0) + pm_error("Failed to write text. %s", ipdb_err(rc)); + + /* Oh, gross. compressIfRequired() might have returned a pointer to + storage that was already allocated, or it might have returned a + pointer to newly malloc'ed storage. In the latter case, we have + to free the storage. + */ + if (compressedData != pdbP->i->data) + free(compressedData); +} + + + +static void +g16pack(tuple * const tupleRow, + struct pam * const pamP, + uint8_t * const outData, + unsigned int const paddedWidth) { +/*---------------------------------------------------------------------------- + Pack a row of 16-level graysacle pixels 'tupleRow', described by *pamP into + 'outData', padding it to 'paddedWidth' with white. + + We pack 2 input pixels into one output byte. +-----------------------------------------------------------------------------*/ + unsigned int col; + unsigned int off; + uint8_t * seg; + + for (col = 0, off = 0, seg = &outData[0]; col < paddedWidth; ++col) { + if (col < pamP->width) + setg16pixel(*seg, 15 - tupleRow[col][0] * 15 / pamP->maxval, off); + else + /* Pad on the right with white */ + setgpixel(*seg, 0, off); + + if (++off == 2) { + ++seg; + off = 0; + } + } +} + + + +static void +gpack(tuple * const tupleRow, + struct pam * const pamP, + uint8_t * const outData, + unsigned int const paddedWidth) { +/*---------------------------------------------------------------------------- + Pack a row of 4-level graysacle pixels 'tupleRow', described by *pamP into + 'outData', padding it to 'paddedWidth' with white. + + We pack 4 input pixels into one output byte. +-----------------------------------------------------------------------------*/ + unsigned int col; + unsigned int off; + uint8_t * seg; + + for (col = 0, off = 0, seg = &outData[0]; col < paddedWidth; ++col) { + if (col < pamP->width) + setgpixel(*seg, 3 - tupleRow[col][0] * 3 / pamP->maxval, off); + else + /* Pad on the right with white */ + setgpixel(*seg, 0, off); + + if (++off == 4) { + ++seg; + off = 0; + } + } +} + + + +static void +mpack(tuple * const tupleRow, + struct pam * const pamP, + uint8_t * const outData, + unsigned int const paddedWidth) { +/*---------------------------------------------------------------------------- + Pack a row of monochrome pixels 'tupleRow', described by *pamP into + 'outData', padding it to 'paddedWidth' with white. + + We pack 8 input pixels into one output byte. +-----------------------------------------------------------------------------*/ + unsigned int col; + unsigned int off; + uint8_t * seg; + + assert(paddedWidth % 8 == 0); + + /* Initialize row to white, then set necessary pixels black */ + memset(outData, 0, paddedWidth/8); + + for (col = 0, off = 0, seg = &outData[0]; col < paddedWidth; ++col) { + if (col < pamP->width && tupleRow[col][0] == PAM_BLACK) + setmpixelblack(*seg, off); + if (++off == 8) { + ++seg; + off = 0; + } + } +} + + + +static int +adjustDimensions(unsigned int const w, + unsigned int const h, + unsigned int * const awP, + unsigned int * const ahP) { + + unsigned int provW, provH; + + provW = w; + provH = h; + if (provW % 16 != 0) + provW += 16 - (provW % 16); + if (provW < 160) + provW = 160; + if (provH < 160) + provH = 160; + + *awP = provW; + *ahP = provH; + + return w == provW && h == provH; +} + + + +/* + * You can allocate only 64k chunks of memory on the pilot and that + * supplies an image size limit. + */ +#define MAX_SIZE(t) ((1 << 16)*((t) == IMG_GRAY ? 4 : 8)) + +static void +imageInsertInit(IPDB * const pdbP, + int const uw, + int const uh, + int const type) { + + char * const name = pdbP->p->name; + unsigned int adjustedWidth, adjustedHeight; + + if (pdbP->p->num_recs != 0) + pm_error("Image record already present, logic error."); + else { + adjustDimensions(uw, uh, &adjustedWidth, &adjustedHeight); + pm_message("Output dimensions: %uw x %uh", + adjustedWidth, adjustedHeight); + if (adjustedWidth * adjustedHeight > MAX_SIZE(type)) + pm_error("Image too large. Maximum number of pixels allowed " + "for a %s image is %u", + ipdb_typeName(type), MAX_SIZE(type)); + else { + pdbP->i = + ipdb_image_alloc(name, type, adjustedWidth, adjustedHeight); + if (pdbP->i == NULL) + pm_message("Could not get memory for %u x %u image", + adjustedWidth, adjustedHeight); + else + pdbP->p->num_recs = 1; + } + } +} + + + +static void +insertG16image(IPDB * const pdbP, + struct pam * const pamP, + tuple ** const tuples) { +/*---------------------------------------------------------------------------- + Insert into the PDB an image in 16-level grayscale format. + + The pixels of the image to insert are 'tuples', described by *pamP. + Note that the image inserted may be padded up to larger dimensions. +-----------------------------------------------------------------------------*/ + imageInsertInit(pdbP, pamP->width, pamP->height, IMG_GRAY16); + { + int const rowSize = ipdb_width(pdbP)/2; + /* The size in bytes of a packed, padded row */ + + uint8_t * outP; + unsigned int row; + + for (row = 0, outP = &pdbP->i->data[0]; + row < pamP->height; + ++row, outP += rowSize) + g16pack(tuples[row], pamP, outP, ipdb_width(pdbP)); + + /* Pad with white on the bottom */ + for (; row < ipdb_height(pdbP); ++row) + memset(outP, 0, rowSize); + } +} + + + +static void +insertGimage(IPDB * const pdbP, + struct pam * const pamP, + tuple ** const tuples) { +/*---------------------------------------------------------------------------- + Insert into the PDB an image in 4-level grayscale format. + + The pixels of the image to insert are 'tuples', described by *pamP. + Note that the image inserted may be padded up to larger dimensions. +-----------------------------------------------------------------------------*/ + imageInsertInit(pdbP, pamP->width, pamP->height, IMG_GRAY); + { + int const rowSize = ipdb_width(pdbP)/4; + /* The size in bytes of a packed, padded row */ + + uint8_t * outP; + unsigned int row; + + for (row = 0, outP = &pdbP->i->data[0]; + row < pamP->height; + ++row, outP += rowSize) + gpack(tuples[row], pamP, outP, ipdb_width(pdbP)); + + /* Pad with white on the bottom */ + for (; row < ipdb_height(pdbP); ++row) + memset(outP, 0, rowSize); + } +} + + + +static void +insertMimage(IPDB * const pdbP, + struct pam * const pamP, + tuple ** const tuples) { +/*---------------------------------------------------------------------------- + Insert into the PDB an image in monochrome format. + + The pixels of the image to insert are 'tuples', described by *pamP. + Note that the image inserted may be padded up to larger dimensions. +-----------------------------------------------------------------------------*/ + imageInsertInit(pdbP, pamP->width, pamP->height, IMG_MONO); + { + int const rowSize = ipdb_width(pdbP)/8; + /* The size in bytes of a packed, padded row */ + + uint8_t * outP; + unsigned int row; + + for (row = 0, outP = &pdbP->i->data[0]; + row < pamP->height; + ++row, outP += rowSize) + mpack(tuples[row], pamP, outP, ipdb_width(pdbP)); + + /* Pad with white on the bottom */ + for (; row < ipdb_height(pdbP); ++row) + memset(outP, 0, rowSize); + } +} + + + +static int +insertText(IPDB * const pdbP, + const char * const s) { + + int retval; + + if (pdbP->i == NULL) + retval = E_IMAGENOTTHERE; + else if (pdbP->p->num_recs == 2) + retval = E_TEXTTHERE; + else { + pdbP->t = ipdb_text_alloc(s); + if (pdbP->t == NULL) + retval = ENOMEM; + else { + pdbP->p->num_recs = 2; + + pdbP->i->r->offset += 8; + pdbP->t->r->offset = + pdbP->i->r->offset + IMAGESIZE + ipdb_img_size(pdbP->i); + + retval = 0; + } + } + return retval; +} + + + +static void +readimg(IPDB * const pdbP, + FILE * const ifP, + bool const depth4) { + + struct pam inpam; + tuple ** tuples; + + tuples = pnm_readpam(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type)); + + if (strneq(inpam.tuple_type, "RGB", 3)) + pm_error("Input image is color. Cannot make a Palm color image."); + + if (inpam.maxval == 1) + insertMimage(pdbP, &inpam, tuples); + else if (depth4) + insertG16image(pdbP, &inpam, tuples); + else + insertGimage(pdbP, &inpam, tuples); + + pnm_freepamarray(tuples, &inpam); +} + + + +static void +readtxt(IPDB * const pdbP, + const char * const noteFileName) { + + struct stat st; + char * fileContent; + FILE * fP; + int n; + int rc; + size_t bytesRead; + + rc = stat(noteFileName, &st); + + if (rc != 0) + pm_error("stat of '%s' failed, errno = %d (%s)", + noteFileName, errno, strerror(errno)); + + fP = pm_openr(noteFileName); + + MALLOCARRAY(fileContent, st.st_size + 1); + + if (fileContent == NULL) + pm_error("Couldn't get %lu bytes of storage to read in note file", + (unsigned long) st.st_size); + + bytesRead = fread(fileContent, 1, st.st_size, fP); + + if (bytesRead != st.st_size) + pm_error("Failed to read note file '%s'. Errno = %d (%s)", + noteFileName, errno, strerror(errno)); + + pm_close(fP); + + /* Chop of trailing newlines */ + for (n = strlen(fileContent) - 1; n >= 0 && fileContent[n] == '\n'; --n) + fileContent[n] = '\0'; + + insertText(pdbP, fileContent); +} + + + +int +main(int argc, const char **argv) { + + struct cmdlineInfo cmdline; + IPDB * pdbP; + FILE * ifP; + int comp; + + pm_proginit(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + ifP = pm_openr(cmdline.inputFileName); + + switch (cmdline.compMode) { + case COMPRESSED: comp = IPDB_COMPRESS; break; + case UNCOMPRESSED: comp = IPDB_NOCOMPRESS; break; + case MAYBE: comp = IPDB_COMPMAYBE; break; + } + + pdbP = ipdb_alloc(cmdline.title); + + if (pdbP == NULL) + pm_error("Failed to allocate IPDB structure"); + + readimg(pdbP, ifP, cmdline.depth4); + + if (cmdline.notefile) + readtxt(pdbP, cmdline.notefile); + + ipdbWrite(pdbP, comp, stdout); + + if (comp == IPDB_COMPMAYBE && !ipdb_compressed(pdbP)) + pm_message("Image too complex to be compressed."); + + ipdb_free(pdbP); + + pm_close(ifP); + + return EXIT_SUCCESS; +} diff --git a/converter/other/pamtopfm.c b/converter/other/pamtopfm.c index 129b8eee..25a8a0af 100644 --- a/converter/other/pamtopfm.c +++ b/converter/other/pamtopfm.c @@ -52,7 +52,7 @@ parseCommandLine(int argc, was passed to us as the argv array. We also trash *argv. --------------------------------------------------------------------------*/ optEntry *option_def = malloc( 100*sizeof( optEntry ) ); - /* Instructions to optParseOptions3 on how to parse our options. */ + /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; unsigned int option_def_index; @@ -67,7 +67,7 @@ parseCommandLine(int argc, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3( &argc, argv, opt, sizeof(opt), 0 ); + pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0 ); /* Uses and sets argc, argv, and some of *cmdline_p and others. */ if (endianSpec) { @@ -150,12 +150,12 @@ floatToPfmSample(float const input, Type converter -----------------------------------------------------------------------------*/ if (machineEndianness == pfmEndianness) { - *(float *)outputP->bytes = input; + MEMSCPY(&outputP->bytes, &input); } else { unsigned char reversed[sizeof(pfmSample)]; unsigned int i, j; - *(float *)reversed = input; + MEMSCPY(&reversed, &input); for (i = 0, j = sizeof(pfmSample)-1; i < sizeof(pfmSample); diff --git a/converter/other/pamtopng.c b/converter/other/pamtopng.c new file mode 100644 index 00000000..528184b2 --- /dev/null +++ b/converter/other/pamtopng.c @@ -0,0 +1,768 @@ +/* +** read a PNM/PAM image and produce a Portable Network Graphics (PNG) file +** +** derived from pnmtorast.c by Jef Poskanzer and pamrgbatopng.c by Bryan +** Henderson and probably some other sources +** +** Copyright (C) 1995-1998 by Alexander Lehmann +** and Willem van Schaik +** Copyright (C) 1999,2001 by Greg Roelofs +** Copyright (C) 2015 by Willem van Schaik +** +** Permission to use, copy, modify, and distribute this software and its +** documentation for any purpose and without fee is hereby granted, provided +** that the above copyright notice appear in all copies and that both that +** copyright notice and this permission notice appear in supporting +** documentation. This software is provided "as is" without express or +** implied warranty. +*/ + +/* + This Netpbm program pamtopng was derived in 2015 from the Netpbm program + Pnmtopng. This was a nearly complete rewrite with the following goals: + + - Add ability to create a PNG alpha channel from the alpha channel in a + PAM (format P7) file. + + - Simplify the 20 year old pnmtopng code. Because of the many, many features + that program implements and its need for backward compatibility, the code + had become rather complex. This program is roughly 1/3 the size of + pnmtopng.c that it replaces. + + - In 1995 bandwith was limited and therefore filesize had to be kept + small. The original program tried to optimize for that by applying + many "clever tricks". Today that isn't an issue anymore, so gone + are filters, palettes, etc. Also, image conversions were removed, + because those should be done with other NetPBM tools. + + - Add ability to create iTXt (international language) chunks. +*/ + + +#include +#include +#include +/* setjmp.h needs to be included after png.h */ +#include + +#include "pm_c_util.h" +#include "mallocvar.h" +#include "nstring.h" +#include "shhopt.h" +#include "pam.h" +#include "pngx.h" +#include "pngtxt.h" + + +/* global variable */ +static bool verbose; + + +struct CmdlineInfo { + const char * inputFileName; + unsigned int verbose; + unsigned int transparencySpec; + const char * transparency; + unsigned int chromaSpec; + struct pngx_chroma chroma; + unsigned int gammaSpec; + float gamma; + unsigned int srgbintentSpec; + pngx_srgbIntent srgbintent; + unsigned int textSpec; + const char * text; + unsigned int ztxtSpec; + const char * ztxt; + unsigned int itxtSpec; + const char * itxt; + unsigned int backgroundSpec; + const char * background; + unsigned int timeSpec; + time_t time; +}; + + + +static void +parseChromaOpt(const char * const chromaOpt, + struct pngx_chroma * const chromaP) { + + int count; + + count = sscanf(chromaOpt, "%f %f %f %f %f %f %f %f", + &chromaP->wx, &chromaP->wy, + &chromaP->rx, &chromaP->ry, + &chromaP->gx, &chromaP->gy, + &chromaP->bx, &chromaP->by); + + if (count != 6) + pm_error("Invalid syntax for the -rgb option value '%s'. " + "Should be 6 floating point number: " + "x and y for each of white, red, green, and blue", + chromaOpt); +} + + + +static void +parseSrgbintentOpt(const char * const srgbintentOpt, + pngx_srgbIntent * const srgbintentP) { + + if (streq(srgbintentOpt, "perceptual")) + *srgbintentP = PNGX_PERCEPTUAL; + else if (streq(srgbintentOpt, "relativecolorimetric")) + *srgbintentP = PNGX_RELATIVE_COLORIMETRIC; + else if (streq(srgbintentOpt, "saturation")) + *srgbintentP = PNGX_SATURATION; + else if (streq(srgbintentOpt, "absolutecolorimetric")) + *srgbintentP = PNGX_ABSOLUTE_COLORIMETRIC; + else + pm_error("Unrecognized sRGB intent value '%s'. We understand " + "only 'perceptual', 'relativecolorimetric', " + "'saturation', and 'absolutecolorimetric'", + srgbintentOpt); +} + + + +static void +parseTimeOpt(const char * const timeOpt, + time_t * const timeP) { + + struct tm brokenTime; + int year; + int month; + int count; + + count = sscanf(timeOpt, "%d-%d-%d %d:%d:%d", + &year, + &month, + &brokenTime.tm_mday, + &brokenTime.tm_hour, + &brokenTime.tm_min, + &brokenTime.tm_sec); + + if (count != 6) + pm_error("Invalid value for -time '%s'. It should have " + "the form [yy]yy-mm-dd hh:mm:ss.", timeOpt); + + if (year < 0) + pm_error("Year is negative in -time value '%s'", timeOpt); + if (year > 9999) + pm_error("Year is more than 4 digits in -time value '%s'", + timeOpt); + if (month < 0) + pm_error("Month is negative in -time value '%s'", timeOpt); + if (month > 12) + pm_error("Month is >12 in -time value '%s'", timeOpt); + if (brokenTime.tm_mday < 0) + pm_error("Day of month is negative in -time value '%s'", + timeOpt); + if (brokenTime.tm_mday > 31) + pm_error("Day of month is >31 in -time value '%s'", timeOpt); + if (brokenTime.tm_hour < 0) + pm_error("Hour is negative in -time value '%s'", timeOpt); + if (brokenTime.tm_hour > 23) + pm_error("Hour is >23 in -time value '%s'", timeOpt); + if (brokenTime.tm_min < 0) + pm_error("Minute is negative in -time value '%s'", timeOpt); + if (brokenTime.tm_min > 59) + pm_error("Minute is >59 in -time value '%s'", timeOpt); + if (brokenTime.tm_sec < 0) + pm_error("Second is negative in -time value '%s'", timeOpt); + if (brokenTime.tm_sec > 59) + pm_error("Second is >59 in -time value '%s'", timeOpt); + + brokenTime.tm_mon = month - 1; + if (year >= 1900) + brokenTime.tm_year = year - 1900; + else + brokenTime.tm_year = year; + + /* Note that mktime() considers brokeTime to be in local time. + This is what we want, since we got it from a user. User should + set his local time zone to UTC if he wants absolute time. + */ + *timeP = mktime(&brokenTime); +} + + + +static void +parseCommandLine (int argc, + const char ** argv, + struct CmdlineInfo * const cmdlineP) { + + optEntry * option_def; + optStruct3 opt; + unsigned int option_def_index = 0; /* incremented by OPTENT3 */ + + const char * srgbintent; + const char * chroma; + const char * time; + + MALLOCARRAY(option_def, 100); + + OPTENT3(0, "verbose", OPT_FLAG, NULL, + &cmdlineP->verbose, 0); + OPTENT3(0, "transparency", OPT_STRING, &cmdlineP->transparency, + &cmdlineP->transparencySpec, 0); + OPTENT3(0, "chroma", OPT_STRING, &chroma, + &cmdlineP->chromaSpec, 0); + OPTENT3(0, "gamma", OPT_FLOAT, &cmdlineP->gamma, + &cmdlineP->gammaSpec, 0); + OPTENT3(0, "srgbintent", OPT_STRING, &srgbintent, + &cmdlineP->srgbintentSpec, 0); + OPTENT3(0, "text", OPT_STRING, &cmdlineP->text, + &cmdlineP->textSpec, 0); + OPTENT3(0, "ztxt", OPT_STRING, &cmdlineP->ztxt, + &cmdlineP->ztxtSpec, 0); + OPTENT3(0, "itxt", OPT_STRING, &cmdlineP->itxt, + &cmdlineP->itxtSpec, 0); + OPTENT3(0, "background", OPT_STRING, &cmdlineP->background, + &cmdlineP->backgroundSpec, 0); + OPTENT3(0, "time", OPT_STRING, &time, + &cmdlineP->timeSpec, 0); + + opt.opt_table = option_def; + opt.short_allowed = false; /* we have no short (old-fashioned) options */ + opt.allowNegNum = false; /* we have no parms that are negative numbers */ + + /* uses and sets argc, argv, and some of *cmdlineP and others */ + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); + + if (cmdlineP->chromaSpec) + parseChromaOpt(chroma, &cmdlineP->chroma); + + if (cmdlineP->srgbintentSpec) + parseSrgbintentOpt(srgbintent, &cmdlineP->srgbintent); + + if (cmdlineP->timeSpec) + parseTimeOpt(time, &cmdlineP->time); + + /* get the input-file or stdin pipe */ + if (argc-1 < 1) + cmdlineP->inputFileName = "-"; + else if (argc-1 == 1) + cmdlineP->inputFileName = argv[1]; + else + pm_error("Program takes at most one argument: input file name."); + + free(option_def); +} + + + +static png_byte +colorTypeFromInputType(const struct pam * const pamP) { +/*---------------------------------------------------------------------------- + Analyse the Netpbm image for color-type and bit-depth +-----------------------------------------------------------------------------*/ + png_byte retval; + + if (pamP->depth < 1 && pamP->depth > 4) + pm_error ("Number of color planes must be between 1 and 4 inclusive"); + + if (pamP->maxval != 1 && pamP->maxval != 3 && pamP->maxval != 15 && + pamP->maxval != 255 && pamP->maxval != 65535) + pm_error("The maxval of the input image is %u; " + "it must be 1, 3, 15, 255 or 65535", (unsigned)pamP->maxval); + + if (strneq(pamP->tuple_type, "RGB_ALPHA", 9)) { + if (pamP->depth == 4) + retval = PNG_COLOR_TYPE_RGB_ALPHA; + else + pm_error("Input tuple type is RGB_ALPHA, " + "but number of planes is %u instead of 4", + pamP->depth); + } else if (strneq(pamP->tuple_type, "RGB", 3)) { + if (pamP->depth == 3) + retval = PNG_COLOR_TYPE_RGB; + else + pm_error("Input tuple type is RGB, " + "but number of planes is %u instead of 3", + pamP->depth); + } else if (strneq(pamP->tuple_type, "GRAYSCALE_ALPHA", 15)) { + if (pamP->depth == 2) + retval = PNG_COLOR_TYPE_GRAY_ALPHA; + else + pm_error("Input tupel type is GRAYSCALE_ALPHA, " + "but number of planes is %u instread of 2", + pamP->depth); + } else if (strneq(pamP->tuple_type, "GRAYSCALE", 9)) { + if (pamP->depth == 1) + retval = PNG_COLOR_TYPE_GRAY; + else + pm_error("Input tuple type is GRAYSCALE, " + "but number of planes is %u instead of 1", + pamP->depth); + } else if (strneq(pamP->tuple_type, "BLACKANDWHITE", 3)) { + if (pamP->depth != 1) + pm_error("Input tuple type is BLACKANDWHITE, " + "but number of planes is %u instead of 1", + pamP->depth); + if (pamP->maxval != 1) + pm_error("Input tuple type is BLACKANDWHITE, " + "but maxval is %u instead of 1", (unsigned)pamP->maxval); + + retval = PNG_COLOR_TYPE_GRAY; + } else + pm_error("Unrecognized tuple type: '%s'", pamP->tuple_type); + + return retval; +} + + + +/***************************************************************************** +* Subroutines that create all the (ancillary) chunks +*****************************************************************************/ + + + +static png_color_16 +parseAndScaleColor(const char * const colorString, + xelval const pngMaxval) { + + png_color_16 pngColor; + + if (colorString) { + xel const inputColor = ppm_parsecolor(colorString, PNM_OVERALLMAXVAL); + + xel scaledColor; + + /* Scale the color down to the PNG bit depth */ + PPM_DEPTH(scaledColor, inputColor, PNM_OVERALLMAXVAL, pngMaxval); + + pngColor.red = PPM_GETR(scaledColor); + pngColor.green = PPM_GETG(scaledColor); + pngColor.blue = PPM_GETB(scaledColor); + pngColor.gray = PNM_GET1(scaledColor); + } + + return pngColor; +} + + + +static void +doTrnsChunk(const struct pam * const pamP, + struct pngx * const pngxP, + const char * const trans) { + + if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_GRAY_ALPHA || + pngx_colorType(pngxP) == PNG_COLOR_TYPE_RGB_ALPHA) + pm_error("Both alpha channel and transparency chunk not allowed."); + else { + xelval const pngMaxval = pm_bitstomaxval(pngx_bitDepth(pngxP)); + png_color_16 const pngColor = parseAndScaleColor(trans, pngMaxval); + /* Transparency color from text format scaled from 16-bit to + maxval. + */ + + pngx_setTrnsValue(pngxP, pngColor); + + if (verbose) { + if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_GRAY) { + pm_message("writing tRNS chunk with color {gray} = {%u}", + pngColor.gray ); + } else if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_RGB) { + pm_message("writing tRNS chunk with color " + "{red, green, blue} = {%u, %u, %u}", + pngColor.red, pngColor.green, pngColor.blue); + } + } + } +} + + + +static void +doChrmChunk(struct pngx * const pngxP, + struct pngx_chroma const chroma) { + + pngx_setChrm(pngxP, chroma); + + if (verbose) { + pm_message("writing cHRM chunk { wx, wy, rx, ry, gx, gy, bx, by } = " + "{ %4.2f, %4.2f, %4.2f, %4.2f, " + "%4.2f, %4.2f, %4.2f, %4.2f }", + chroma.wx, chroma.wy, + chroma.rx, chroma.ry, + chroma.gx, chroma.gy, + chroma.bx, chroma.by); + } +} + + + +static void +doGamaChunk(struct pngx * const pngxP, + float const gamma) { + + pngx_setGama(pngxP, gamma); + + if (verbose) { + pm_message("writing gAMA chunk with image gamma value %4.2f", gamma); + } +} + + + +static void +doSbitChunk(const struct pam * const pamP, + struct pngx * const pngxP) { + + unsigned int const pnmBitDepth = pm_maxvaltobits(pamP->maxval); + + /* create SBIT chunk in case of 1,2,4 bit deep images stored in 8 bit + format PNG files + */ + if (pngx_colorType(pngxP) != PNG_COLOR_TYPE_GRAY && pnmBitDepth < 8) { + png_color_8 sBit; + + if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_RGB || + pngx_colorType(pngxP) == PNG_COLOR_TYPE_RGB_ALPHA) { + sBit.red = sBit.green = sBit.blue = pnmBitDepth; + } else { + sBit.gray = pnmBitDepth; + } + if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_RGB_ALPHA || + pngx_colorType(pngxP) == PNG_COLOR_TYPE_GRAY_ALPHA) { + sBit.alpha = pnmBitDepth; + } + pngx_setSbit(pngxP, sBit); + } +} + + + +static void +doSrgbChunk(struct pngx * const pngxP, + pngx_srgbIntent const srgbIntent) { + + pngx_setSrgb(pngxP, srgbIntent); + + if (verbose) { + pm_message("writing sRGB chunk with intent value %s", + pngx_srgbIntentDesc(srgbIntent)); + } +} + + + +static void +doTextChunkSet(struct pngx * const pngxP, + const char * const textFileName) { + + bool const ztxt = true; + bool const itxt = false; + + FILE * tfP; + + tfP = pm_openr(textFileName); + + pngtxt_addChunk(pngxP, tfP, ztxt, itxt, verbose); + + pm_close(tfP); +} + + + +static void +doZtxtChunkSet(struct pngx * const pngxP, + const char * const textFileName) { + + bool const ztxt = true; + bool const itxt = false; + + FILE * tfP; + + tfP = pm_openr(textFileName); + + pngtxt_addChunk(pngxP, tfP, ztxt, itxt, verbose); + + pm_close(tfP); +} + + + + +static void +doItxtChunkSet(struct pngx * const pngxP, + const char * const textFileName) { + + bool const ztxt = true; + bool const itxt = true; + + FILE * tfP; + + tfP = pm_openr(textFileName); + + pngtxt_addChunk(pngxP, tfP, ztxt, itxt, verbose); +} + + + +static void +doBkgdChunk (const struct pam * const pamP, + struct pngx * const pngxP, + const char * const colorName) +{ + xelval const pngMaxval = pm_bitstomaxval(pngx_bitDepth(pngxP)); + + png_color_16 const pngColor = parseAndScaleColor(colorName, pngMaxval); + /* Background color from text format, scaled from 16-bit to maxval */ + + pngx_setBkgdRgb(pngxP, pngColor); + + if (verbose) { + if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_GRAY || + pngx_colorType(pngxP) == PNG_COLOR_TYPE_GRAY_ALPHA) { + pm_message("writing bKGD chunk with gray level = %u", + pngColor.gray); + } else if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_RGB || + pngx_colorType(pngxP) == PNG_COLOR_TYPE_RGB_ALPHA) { + pm_message("writing bKGD chunk with color {red, green, blue} = " + "{%u, %u, %u}", + pngColor.red, pngColor.green, pngColor.blue); + } + } +} + + + +static void +doTimeChunk(struct pngx * const pngxP, + time_t const time) { + + pngx_setTime(pngxP, time); + + if (verbose) { + struct tm * const brokenTimeP = gmtime(&time); + + char buffer[100]; + + strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", brokenTimeP); + + pm_message("Writing tIME chunk specifying datetime %s", buffer); + } +} + + + +static void +convertRaster(const struct pam * const pamP, + const tuple * const tuplerow, + png_byte * const pngRow, + unsigned int const bitDepth) { + + unsigned int col; + + /* An image row consists of columns x planes like gray or rgb(a) x 8 or 16 + bits. + */ + for (col = 0; col < pamP->width; ++col) { + unsigned int plane; + for (plane = 0; plane < pamP->depth; ++plane) { + if (bitDepth > 8) { + /* Copy 2 bytes = 16 bits for one pixel */ + pngRow[2 * (pamP->depth * col + plane)] = + (tuplerow[col][plane] >> 8) & 0xff ; + pngRow[2 * (pamP->depth * col + plane) + 1] = + tuplerow[col][plane] & 0xff ; + } else { + /* Copy 1 byte for one pixel. Later, a packing of 2, 4 or 8 + pixels into a single byte can still happen. + */ + pngRow[pamP->depth * col + plane] = tuplerow[col][plane]; + } + } + } +} + + + +static void +writeRaster(const struct pam * const pamP, + struct pngx * const pngxP, + int const bitDepth) { + + tuple * tupleRow; + png_byte * pngRow; + unsigned int row; + + /* We process row-by-row and do not read the complete image into memory */ + + tupleRow = pnm_allocpamrow(pamP); + + MALLOCARRAY(pngRow, pamP->width * 8); + /* sufficient to store a 16-bit RGB+A row */ + + if (pngRow == NULL) + pm_error("Unable to allocate space for PNG pixel row for " + "%u columns", pamP->width); + else { + for (row = 0; row < pamP->height; ++row) { + pnm_readpamrow(pamP, tupleRow); + + convertRaster(pamP, tupleRow, pngRow, bitDepth); + + png_write_row(pngxP->png_ptr, pngRow); + } + free(pngRow); + } + pnm_freepamrow(tupleRow); +} + + + +static void +writePng(const struct pam * const pamP, + FILE * const ofP, + struct CmdlineInfo const cmdline) { + + unsigned int const pnmBitDepth = pm_maxvaltobits(pamP->maxval); + int const pngColorType = colorTypeFromInputType(pamP); + + struct pngx * pngxP; + unsigned int pngBitDepth; + png_color_8 sBit; + + pngx_create(&pngxP, PNGX_WRITE, NULL); + + + + if ((pngColorType == PNG_COLOR_TYPE_RGB || + pngColorType == PNG_COLOR_TYPE_RGB_ALPHA) && + pnmBitDepth < 8) { + + pngBitDepth = 8; + } else + pngBitDepth = pnmBitDepth; + + png_init_io(pngxP->png_ptr, ofP); + + pngx_setIhdr(pngxP, pamP->width, pamP->height, + pngBitDepth, pngColorType, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, + PNG_FILTER_TYPE_BASE); + + /* Where requested, add ancillary chunks */ + if (cmdline.transparencySpec) + doTrnsChunk(pamP, pngxP,cmdline.transparency); + + if (cmdline.chromaSpec) + doChrmChunk(pngxP, cmdline.chroma); + + if (cmdline.gammaSpec) + doGamaChunk(pngxP, cmdline.gamma); + + /* no iccp */ + + doSbitChunk(pamP, pngxP); + + if (cmdline.srgbintentSpec) + doSrgbChunk(pngxP, cmdline.srgbintent); + + if (cmdline.textSpec) + doTextChunkSet(pngxP, cmdline.text); + + if (cmdline.ztxtSpec) + doZtxtChunkSet(pngxP, cmdline.ztxt); + + if (cmdline.itxtSpec) + doItxtChunkSet(pngxP, cmdline.itxt); + + if (cmdline.backgroundSpec) + doBkgdChunk(pamP, pngxP, cmdline.background); + + /* no hist */ + + /* no phys */ + + /* no splt */ + + if (cmdline.timeSpec) + doTimeChunk(pngxP, cmdline.time); + + /* Write the ancillary chunks to PNG file */ + pngx_writeInfo(pngxP); + + if (pngColorType != PNG_COLOR_TYPE_GRAY && pnmBitDepth < 8) { + /* Move the 1, 2, 4 bits to most significant bits */ + pngx_setShift(pngxP, sBit); + } + if ((pngColorType == PNG_COLOR_TYPE_GRAY) && (pnmBitDepth < 8)) { + /* Pack multiple pixels in a byte */ + pngx_setPacking(pngxP); + } + + writeRaster(pamP, pngxP, pnmBitDepth); + + pngx_writeEnd(pngxP); + pngx_destroy(pngxP); +} + + + + +static void +reportInputFormat(const struct pam * const pamP) { + + const char * formatDesc; + + if (pamP->format == PBM_FORMAT || pamP->format == RPBM_FORMAT) + formatDesc = "PBM"; + else if (pamP->format == PGM_FORMAT || pamP->format == RPGM_FORMAT) + formatDesc = "PGM"; + else if (pamP->format == PPM_FORMAT || pamP->format == RPPM_FORMAT) + formatDesc = "PPM"; + else if (pamP->format == PAM_FORMAT) + formatDesc = "PAM"; + else + formatDesc = NULL; + + if (formatDesc) + pm_message("Input format = %s", formatDesc); + else + pm_message("Unrecognized input format, format code = 0x%x", + pamP->format); + + pm_message("Input tuple type = '%s'", pamP->tuple_type); + pm_message("Input depth = %u", pamP->depth); + pm_message("Input maxval = %u", (unsigned int) pamP->maxval); +} + + + +int +main(int argc, + const char ** argv) { + + FILE * ifP; + struct CmdlineInfo cmdline; + struct pam pam; + + pm_proginit(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + verbose = cmdline.verbose; + + ifP = pm_openr(cmdline.inputFileName); + + pnm_readpaminit(ifP, &pam, PAM_STRUCT_SIZE(tuple_type)); + + if (verbose) + reportInputFormat(&pam); + + writePng(&pam, stdout, cmdline); + + pm_close(ifP); + + return 0; +} + + + diff --git a/converter/other/pamtopnm.c b/converter/other/pamtopnm.c index 86f6514c..f043d721 100644 --- a/converter/other/pamtopnm.c +++ b/converter/other/pamtopnm.c @@ -17,23 +17,23 @@ #include "shhopt.h" #include "mallocvar.h" -struct cmdlineInfo { +struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ - const char *inputFilespec; /* Filespecs of input files */ - unsigned int assume; /* -assume option */ + const char * inputFileName; /* Name of input file */ + unsigned int assume; }; static void -parseCommandLine(int argc, char ** argv, - struct cmdlineInfo *cmdlineP) { +parseCommandLine(int argc, const char ** argv, + struct CmdlineInfo *cmdlineP) { /*---------------------------------------------------------------------------- Note that the file spec array we return is stored in the storage that was passed to us as the argv array. -----------------------------------------------------------------------------*/ - optEntry *option_def; + optEntry * option_def; /* Instructions to OptParseOptions3 on how to parse our options. */ optStruct3 opt; @@ -49,16 +49,18 @@ parseCommandLine(int argc, char ** argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (argc-1 == 0) - cmdlineP->inputFilespec = "-"; + cmdlineP->inputFileName = "-"; else if (argc-1 != 1) pm_error("Program takes zero or one argument (filename). You " "specified %d", argc-1); else - cmdlineP->inputFilespec = argv[1]; + cmdlineP->inputFileName = argv[1]; + + free(option_def); } @@ -69,11 +71,11 @@ validateTupleType(struct pam const inpam, /*---------------------------------------------------------------------------- Make sure the image has a tuple type we know how to convert to PNM. - We're quite liberal, trying to accomodate all sorts of future + We're quite liberal, trying to accommodate all sorts of future twists on the formats. If the tuple type _starts with_ BLACKANDWHITE, GRAYSCALE, or RGB, and has at least as many planes as we'd need to convert to PBM, PGM, or PPM, respectively, we - accept it. We thus accomodate variations on these formats that add + accept it. We thus accommodate variations on these formats that add planes and add to the right end of the tuple type to explain them. If Callers specified 'assumeTupleType', we're even more liberal. @@ -105,19 +107,19 @@ validateTupleType(struct pam const inpam, int -main(int argc, char *argv[]) { +main(int argc, const char **argv) { - struct cmdlineInfo cmdline; - FILE* ifP; - bool eof; /* no more images in input stream */ + struct CmdlineInfo cmdline; + FILE * ifP; + int eof; /* no more images in input stream */ struct pam inpam; /* Input PAM image */ struct pam outpam; /* Output PNM image */ - pnm_init(&argc, argv); + pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); - ifP = pm_openr(cmdline.inputFilespec); + ifP = pm_openr(cmdline.inputFileName); eof = FALSE; while (!eof) { diff --git a/converter/other/pamtosrf.c b/converter/other/pamtosrf.c new file mode 100644 index 00000000..3800d77c --- /dev/null +++ b/converter/other/pamtosrf.c @@ -0,0 +1,217 @@ +/* + * Convert a Netpbm image to SRF (Garmin vehicle) + * + * Copyright (C) 2011 by Mike Frysinger + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. This software is provided "as is" without express or + * implied warranty. + */ + +#include + +#include "pm_c_util.h" +#include "shhopt.h" +#include "mallocvar.h" +#include "nstring.h" +#include "pam.h" +#include "srf.h" + +struct cmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + const char * inputFileName; /* '-' if stdin */ + unsigned int verbose; +}; + +static bool verbose; + + + +static void +parseCommandLine(int argc, const char ** argv, + struct cmdlineInfo * const cmdlineP) { +/*---------------------------------------------------------------------------- + parse program command line described in Unix standard form by argc + and argv. Return the information in the options as *cmdlineP. + + If command line is internally inconsistent (invalid options, etc.), + issue error message to stderr and abort program. + + Note that the strings we return are stored in the storage that + was passed to us as the argv array. We also trash *argv. +-----------------------------------------------------------------------------*/ + optEntry *option_def; + /* Instructions to pm_optParseOptions3 on how to parse our options. + */ + optStruct3 opt; + + unsigned int option_def_index; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENT3 */ + OPTENT3(0, "verbose", OPT_FLAG, NULL, + &cmdlineP->verbose, 0); + + opt.opt_table = option_def; + opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ + opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ + + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + if (argc-1 < 1) + cmdlineP->inputFileName = "-"; + else if (argc-1 == 1) + cmdlineP->inputFileName = argv[1]; + else + pm_error("Program takes at most one argument: input file name"); +} + + + +static uint8_t +srfScale(sample const unscaled, + const struct pam * const pamP) { + + return pnm_scalesample(unscaled, pamP->maxval, 255); +} + + + +static uint16_t +srfColorFromTuple(tuple const t, + const struct pam * const pamP) { + + unsigned int redPlane, grnPlane, bluPlane; + + if (pamP->depth >= 3) { + redPlane = PAM_RED_PLANE; + grnPlane = PAM_GRN_PLANE; + bluPlane = PAM_BLU_PLANE; + } else { + redPlane = 0; + grnPlane = 0; + bluPlane = 0; + } + return + (((srfScale(t[redPlane], pamP) >> 3) & 0x1f) << 11) | + (((srfScale(t[grnPlane], pamP) >> 3) & 0x1f) << 6) | + (((srfScale(t[bluPlane], pamP) >> 3) & 0x1f) << 0); +} + + + +static uint8_t +srfAlphaFromTuple(tuple const t, + const struct pam * const pamP) { + + uint8_t retval; + int haveOpacity; + unsigned int opacityPlane; + + pnm_getopacity(pamP, &haveOpacity, &opacityPlane); + + if (haveOpacity) { + uint8_t const scaled = srfScale(t[opacityPlane], pamP); + + retval = scaled == 0xff ? SRF_ALPHA_OPAQUE : 128 - (scaled >> 1); + } else + retval = SRF_ALPHA_OPAQUE; + + return retval; +} + + + +static void +convertRaster(struct pam * const pamP, + struct srf_img * const imgP) { + + tuple * tuplerow; + unsigned int row; + + tuplerow = pnm_allocpamrow(pamP); + + for (row = 0; row < pamP->height; ++row) { + uint32_t const off = row * pamP->width; + uint16_t * const data = &imgP->data.data[off]; + unsigned char * const alpha = &imgP->alpha.data[off]; + + unsigned int col; + + pnm_readpamrow(pamP, tuplerow); + + for (col = 0; col < pamP->width; ++col) { + alpha[col] = srfAlphaFromTuple(tuplerow[col], pamP); + data[col] = srfColorFromTuple(tuplerow[col], pamP); + } + } + pnm_freepamrow(tuplerow); +} + + + +static void +convertImage(FILE * const ifP, + struct srf * const srfP) { + + struct pam inpam; + + pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type)); + + if (verbose) + pm_message("reading %ux%u image", inpam.width, inpam.height); + + srf_create_img(srfP, inpam.width, inpam.height); + + convertRaster(&inpam, &srfP->imgs[srfP->header.img_cnt-1]); +} + + + +int +main(int argc, const char * argv[]) { + + struct cmdlineInfo cmdline; + FILE * ifP; + struct srf srf; + int eof; /* No more images in input */ + unsigned int imageSeq; + /* Sequence of current image in input file. First = 0 */ + + pm_proginit(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + verbose = cmdline.verbose; + + ifP = pm_openr(cmdline.inputFileName); + + srf_init(&srf); + + eof = FALSE; + for (imageSeq = 0; !eof; ++imageSeq) { + if (verbose) + pm_message("Converting Image %u", imageSeq); + + convertImage(ifP, &srf); + + pnm_nextimage(ifP, &eof); + } + + srf_write(stdout, &srf); + + srf_term(&srf); + pm_closer(ifP); + + return 0; +} + + + diff --git a/converter/other/pamtosvg/Makefile b/converter/other/pamtosvg/Makefile index 8b033020..83f150d0 100644 --- a/converter/other/pamtosvg/Makefile +++ b/converter/other/pamtosvg/Makefile @@ -7,26 +7,13 @@ VPATH=.:$(SRCDIR)/$(SUBDIR) include $(BUILDDIR)/config.mk -BINARIES = pamtosvg +PORTBINARIES = pamtosvg -PAMTOSVG_OBJECTS = \ - pamtosvg.o \ - output-svg.o \ - fit.o \ - spline.o \ - curve.o \ - vector.o \ - epsilon-equal.o \ - autotrace.o \ - pxl-outline.o \ - bitmap.o \ - thin-image.o \ - logreport.o \ - exception.o \ - image-proc.o \ +BINARIES = $(PORTBINARIES) + +MERGEBINARIES = $(BINARIES) -MERGE_OBJECTS = \ - pamtosvg.o2 \ +ADDL_OBJECTS = \ output-svg.o \ fit.o \ spline.o \ @@ -41,15 +28,12 @@ MERGE_OBJECTS = \ exception.o \ image-proc.o \ -OBJECTS = $(PAMTOSVG_OBJECTS) +OBJECTS = pamtosvg.o $(ADDL_OBJECTS) -MERGEBINARIES = $(BINARIES) +MERGE_OBJECTS = pamtosvg.o2 $(ADDL_OBJECTS) all: $(BINARIES) include $(SRCDIR)/common.mk -pamtosvg: $(PAMTOSVG_OBJECTS) $(NETPBMLIB) $(LIBOPT) - $(LD) -o $@ $(PAMTOSVG_OBJECTS) \ - $(shell $(LIBOPT) $(NETPBMLIB)) \ - $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD) +pamtosvg: $(ADDL_OBJECTS) diff --git a/converter/other/pamtosvg/bitmap.c b/converter/other/pamtosvg/bitmap.c index 1a00e748..84a8a8ae 100644 --- a/converter/other/pamtosvg/bitmap.c +++ b/converter/other/pamtosvg/bitmap.c @@ -59,8 +59,8 @@ at_bitmap_init(unsigned char * area, if (bitmap.bitmap == NULL) pm_error("Unable to allocate %u x %u x %u bitmap array", width, height, planes); - bzero(bitmap.bitmap, - width * height * planes * sizeof(unsigned char)); + memset(bitmap.bitmap, + 0, width * height * planes * sizeof(unsigned char)); } } diff --git a/converter/other/pamtosvg/bitmap.h b/converter/other/pamtosvg/bitmap.h index 7334f138..b979e0c0 100644 --- a/converter/other/pamtosvg/bitmap.h +++ b/converter/other/pamtosvg/bitmap.h @@ -36,7 +36,7 @@ at_bitmap_type * at_bitmap_new(unsigned short width, unsigned int planes); at_bitmap_type * at_bitmap_copy(at_bitmap_type * src); -/* We have to export functions that supports internal datum +/* We have to export functions that allows internal datum access. Such functions might be useful for at_bitmap_new user. */ unsigned short at_bitmap_get_width (at_bitmap_type * bitmap); diff --git a/converter/other/pamtosvg/image-proc.c b/converter/other/pamtosvg/image-proc.c index 287e6384..d025ee1e 100644 --- a/converter/other/pamtosvg/image-proc.c +++ b/converter/other/pamtosvg/image-proc.c @@ -52,7 +52,7 @@ new_distance_map(bitmap_type bitmap, unsigned char target_value, bool padded, at MALLOCARRAY(dist.d[y], w); if (dist.d[y] == NULL) pm_error("Unable to get memory for distance map"); - bzero(dist.d[y], w * sizeof(float)); + memset(dist.d[y], 0, w * sizeof(float)); MALLOCARRAY(dist.weight[y], w); if (dist.weight[y] == NULL) @@ -330,7 +330,7 @@ binarize(bitmap_type *bitmap) } else { - WARNING1("binarize: %u-plane images are not supported", spp); + WARNING1("binarize: don't know how to interpret %u-plane images", spp); } } diff --git a/converter/other/pamtosvg/message.h b/converter/other/pamtosvg/message.h index 0a226206..0d0b9db5 100644 --- a/converter/other/pamtosvg/message.h +++ b/converter/other/pamtosvg/message.h @@ -10,10 +10,6 @@ /* Define common sorts of messages. */ -/* This should be called only after a system call fails. */ -#define FATAL_PERROR(s) do { perror (s); exit (errno); } while (0) - - #define START_FATAL() do { fputs ("fatal: ", stderr); LOG("fatal: ") #define END_FATAL() fputs (".\n", stderr); exit (1); } while (0) @@ -21,12 +17,6 @@ START_FATAL (); fprintf (stderr, "%s", s); LOG (s); END_FATAL () #define FATAL1(s, e1) \ START_FATAL (); fprintf (stderr, s, e1); LOG1 (s, e1); END_FATAL () -#define FATAL2(s, e1, e2) \ - START_FATAL (); fprintf (stderr, s, e1, e2); LOG2 (s, e1, e2); END_FATAL () -#define FATAL3(s, e1, e2, e3) \ - START_FATAL (); fprintf (stderr, s, e1, e2, e3); LOG3 (s, e1, e2, e3); END_FATAL () -#define FATAL4(s, e1, e2, e3, e4) \ - START_FATAL (); fprintf (stderr, s, e1, e2, e3, e4); LOG4 (s, e1, e2, e3, e4); END_FATAL () #define START_WARNING() do { fputs ("warning: ", stderr); LOG ("warning: ") @@ -36,12 +26,6 @@ START_WARNING (); fprintf (stderr, "%s", s); LOG (s); END_WARNING () #define WARNING1(s, e1) \ START_WARNING (); fprintf (stderr, s, e1); LOG1 (s, e1); END_WARNING () -#define WARNING2(s, e1, e2) \ - START_WARNING (); fprintf (stderr, s, e1, e2); LOG2 (s, e1, e2); END_WARNING () -#define WARNING3(s, e1, e2, e3) \ - START_WARNING (); fprintf (stderr, s, e1, e2, e3); LOG3 (s, e1, e2, e3); END_WARNING () -#define WARNING4(s, e1, e2, e3, e4) \ - START_WARNING (); fprintf (stderr, s, e1, e2, e3, e4); LOG4 (s, e1, e2, e3, e4); END_WARNING () #endif /* not MESSAGE_H */ diff --git a/converter/other/pamtosvg/pamtosvg.c b/converter/other/pamtosvg/pamtosvg.c index dbe67c74..adf76801 100644 --- a/converter/other/pamtosvg/pamtosvg.c +++ b/converter/other/pamtosvg/pamtosvg.c @@ -134,8 +134,8 @@ parseCommandLine(int argc, Note that the strings we return are stored in the storage that was passed to us as the argv array. We also trash *argv. --------------------------------------------------------------------------*/ - optEntry *option_def; - /* Instructions to optParseOptions3 on how to parse our options. */ + optEntry * option_def; + /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; const char * background_colorOpt; @@ -197,7 +197,7 @@ parseCommandLine(int argc, cmdlineP->tangent_surround = 3; cmdlineP->width_weight_factor = 6.0; - optParseOptions3( &argc, argv, opt, sizeof(opt), 0 ); + pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0 ); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (cmdlineP->backgroundSpec) @@ -334,7 +334,7 @@ openLogFile(FILE ** const logFileP, const char * logfileName; if (streq(inputFileArg, "-")) - asprintfN(&logfileName, "pamtosvg.log"); + pm_asprintf(&logfileName, "pamtosvg.log"); else { const char * inputRootName; @@ -343,14 +343,14 @@ openLogFile(FILE ** const logFileP, pm_error("Can't find the root portion of file name '%s'", inputFileArg); - asprintfN(&logfileName, "%s.log", inputRootName); + pm_asprintf(&logfileName, "%s.log", inputRootName); - strfree(inputRootName); + pm_strfree(inputRootName); } *logFileP = pm_openw(logfileName); - strfree(logfileName); + pm_strfree(logfileName); } diff --git a/converter/other/pamtosvg/pxl-outline.c b/converter/other/pamtosvg/pxl-outline.c index a1fa5299..456f41e1 100644 --- a/converter/other/pamtosvg/pxl-outline.c +++ b/converter/other/pamtosvg/pxl-outline.c @@ -9,7 +9,6 @@ #include "message.h" #include "bitmap.h" -#include "bitmap.h" #include "logreport.h" #include "pxl-outline.h" diff --git a/converter/other/pamtosvg/thin-image.c b/converter/other/pamtosvg/thin-image.c index 40ced794..364f67cc 100644 --- a/converter/other/pamtosvg/thin-image.c +++ b/converter/other/pamtosvg/thin-image.c @@ -171,7 +171,7 @@ thin_image(bitmap_type *image, bool bgSpec, pixel bg, if (PPM_ISGRAY(background)) bg_color = PPM_GETR(background); else - bg_color = PPM_LUMIN(background); + bg_color = ppm_luminosity(background); for (n = num_pixels - 1; n >= 0L; --n) { @@ -189,7 +189,7 @@ thin_image(bitmap_type *image, bool bgSpec, pixel bg, default: { - LOG1 ("thin_image: %u-plane images are not supported", spp); + LOG1 ("thin_image: Don't know how to interpret %u-plane images", spp); at_exception_fatal(exp, "thin_image: wrong plane images are passed"); goto cleanup; } @@ -306,7 +306,7 @@ void thin1(bitmap_type *image, unsigned char colour) if (PPM_ISGRAY(background)) bg_color = PPM_GETR(background); else - bg_color = PPM_LUMIN(background); + bg_color = ppm_luminosity(background); LOG (" Thinning image.....\n "); xsize = image->width; diff --git a/converter/other/pamtosvg/vector.c b/converter/other/pamtosvg/vector.c index 7678f73a..0a5ef3a9 100644 --- a/converter/other/pamtosvg/vector.c +++ b/converter/other/pamtosvg/vector.c @@ -1,5 +1,6 @@ /* vector.c: vector/point operations. */ +#define _XOPEN_SOURCE /* Make sure M_PI is in */ #include #include #include diff --git a/converter/other/pamtotga.c b/converter/other/pamtotga.c index c23b92b1..aca93015 100644 --- a/converter/other/pamtotga.c +++ b/converter/other/pamtotga.c @@ -74,7 +74,7 @@ parseCommandLine(int argc, char ** argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdline_p and others. */ if (cmap + mono + rgb > 1) @@ -463,7 +463,7 @@ static void releaseTgaHeader(struct ImageHeader const tgaHeader) { if (tgaHeader.IdLength > 0) - strfree(tgaHeader.Id); + pm_strfree(tgaHeader.Id); } @@ -567,7 +567,7 @@ main(int argc, char *argv[]) { pnm_freetupletable(&pam, chv); releaseTgaHeader(tgaHeader); - strfree(outName); + pm_strfree(outName); pnm_freepamarray(tuples, &pam); return 0; diff --git a/converter/other/pamtotiff.c b/converter/other/pamtotiff.c index 1b31c65b..7b645b23 100644 --- a/converter/other/pamtotiff.c +++ b/converter/other/pamtotiff.c @@ -27,12 +27,6 @@ #include #include #include -#ifdef VMS -#ifdef SYSV -#undef SYSV -#endif -#include -#endif /* tiffio.h has a weird problem on AIX. tiffio.h wrongly typedefs "int32". That's wrong because such a name is likely to be used in other parts of the program that includes tiffio.h. And in fact, on @@ -59,16 +53,19 @@ #define COMPRESSION_ADOBE_DEFLATE 8 #endif -struct sizeset { +typedef struct { bool b1, b2, b4, b8; -}; +} SizeSet; + +typedef enum { TMPFILE, DIRECT_CREATE, DIRECT_APPEND } WriteMethod; +typedef enum { MUST_EXIST, MAY_CREATE } CreatePolicy; -struct cmdlineInfo { +typedef struct { /* All the information the user supplied in the command line, in a form easy for the program to use. */ - const char *input_filespec; /* Filespecs of input files */ + const char * inputFileName; int compression; /* COMPRESSION Tiff tag value, that corresponds to the compression option the user specified, or -1 if he didn't specify any. @@ -84,14 +81,15 @@ struct cmdlineInfo { unsigned int color; /* logical: assume not grayscale */ float xresolution; /* XRESOLUTION Tiff tag value or -1 for none */ float yresolution; /* YRESOLUTION Tiff tag value or -1 for none */ - int resolutionUnit; /* RESOLUTIONUNIT Tiff tag value */ - struct sizeset indexsizeAllowed; + int resolutionunit; /* RESOLUTIONUNIT Tiff tag value */ + SizeSet indexsizeAllowed; /* Which bit widths are allowable in a raster of palette indices */ unsigned int verbose; - unsigned int append; + WriteMethod writeMethod; /* Output mode */ + const char * output; /* -output option value. NULL if none. */ float resolution; /* X and Y resolution */ struct optNameValue * taglist; -}; +} CmdlineInfo; @@ -102,7 +100,7 @@ validateTagList(struct optNameValue const taglist[]) { for (i = 0; taglist[i].name; ++i) { const char * const tagName = taglist[i].name; const tagDefinition * tagDefP = tagDefFind(tagName); - + if (!tagDefP) pm_error("Unknown tag name '%s'", tagName); else { @@ -137,9 +135,9 @@ validateTagList(struct optNameValue const taglist[]) { static void -parseCommandLine(int argc, - char ** const argv, - struct cmdlineInfo * const cmdlineP) { +parseCommandLine(int argc, + const char ** const argv, + CmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- Note that the file spec array we return is stored in the storage that was passed to us as the argv array. @@ -151,10 +149,11 @@ parseCommandLine(int argc, unsigned int none, packbits, lzw, g3, g4, msb2lsb, lsb2msb, opt_2d, fill; unsigned int flate, adobeflate; char * indexbits; - char * resolutionUnit; + char * resolutionunit; - unsigned int predictorSpec, rowsperstripSpec, xresolutionSpec, - yresolutionSpec, indexbitsSpec, resolutionUnitSpec, tagSpec; + unsigned int appendSpec, outputSpec, predictorSpec, rowsperstripSpec, + xresolutionSpec, yresolutionSpec, indexbitsSpec, + resolutionunitSpec, tagSpec; unsigned int option_def_index; @@ -162,7 +161,6 @@ parseCommandLine(int argc, option_def_index = 0; /* incremented by OPTENT3 */ OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); - OPTENT3(0, "append", OPT_FLAG, NULL, &cmdlineP->append, 0); OPTENT3(0, "none", OPT_FLAG, NULL, &none, 0); OPTENT3(0, "packbits", OPT_FLAG, NULL, &packbits, 0); OPTENT3(0, "lzw", OPT_FLAG, NULL, &lzw, 0); @@ -180,17 +178,20 @@ parseCommandLine(int argc, OPTENT3(0, "mw", OPT_FLAG, NULL, &cmdlineP->miniswhite, 0); OPTENT3(0, "truecolor", OPT_FLAG, NULL, &cmdlineP->truecolor, 0); OPTENT3(0, "color", OPT_FLAG, NULL, &cmdlineP->color, 0); - OPTENT3(0, "predictor", OPT_UINT, &cmdlineP->predictor, + OPTENT3(0, "append", OPT_FLAG, NULL, &appendSpec, 0); + OPTENT3(0, "output", OPT_STRING, &cmdlineP->output, + &outputSpec, 0); + OPTENT3(0, "predictor", OPT_UINT, &cmdlineP->predictor, &predictorSpec, 0); - OPTENT3(0, "rowsperstrip", OPT_UINT, &cmdlineP->rowsperstrip, + OPTENT3(0, "rowsperstrip", OPT_UINT, &cmdlineP->rowsperstrip, &rowsperstripSpec, 0); - OPTENT3(0, "xresolution", OPT_FLOAT, &cmdlineP->xresolution, + OPTENT3(0, "xresolution", OPT_FLOAT, &cmdlineP->xresolution, &xresolutionSpec, 0); - OPTENT3(0, "yresolution", OPT_FLOAT, &cmdlineP->yresolution, + OPTENT3(0, "yresolution", OPT_FLOAT, &cmdlineP->yresolution, &yresolutionSpec, 0); - OPTENT3(0, "resolutionunit", OPT_STRING, &resolutionUnit, - &resolutionUnitSpec, 0); - OPTENT3(0, "indexbits", OPT_STRING, &indexbits, + OPTENT3(0, "resolutionunit", OPT_STRING, &resolutionunit, + &resolutionunitSpec, 0); + OPTENT3(0, "indexbits", OPT_STRING, &indexbits, &indexbitsSpec, 0); OPTENT3(0, "tag", OPT_NAMELIST, &cmdlineP->taglist, &tagSpec, 0); @@ -198,14 +199,14 @@ parseCommandLine(int argc, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, (char**)argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (none + packbits + lzw + g3 + g4 + flate + adobeflate > 1) pm_error("You specified more than one compression option. " "Only one of -none, -packbits, -lze, -g3, and -g4 " "is allowed."); - + if (none) cmdlineP->compression = COMPRESSION_NONE; else if (packbits) @@ -222,7 +223,7 @@ parseCommandLine(int argc, cmdlineP->compression = COMPRESSION_DEFLATE; else cmdlineP->compression = COMPRESSION_NONE; - + if (msb2lsb + lsb2msb > 1) pm_error("You specified both -msb2lsb and -lsb2msb. " "These are conflicting options."); @@ -231,9 +232,9 @@ parseCommandLine(int argc, cmdlineP->fillorder = FILLORDER_MSB2LSB; else if (lsb2msb) cmdlineP->fillorder = FILLORDER_LSB2MSB; - else + else cmdlineP->fillorder = FILLORDER_MSB2LSB; - + if (cmdlineP->miniswhite && cmdlineP->minisblack) pm_error("You cannot specify both -miniswhite and -minisblack"); @@ -244,9 +245,17 @@ parseCommandLine(int argc, if (fill) cmdlineP->g3options |= GROUP3OPT_FILLBITS; + if (outputSpec) { + if (appendSpec) + cmdlineP->writeMethod = DIRECT_APPEND; + else + cmdlineP->writeMethod = DIRECT_CREATE; + } else + cmdlineP->writeMethod = TMPFILE; + if (predictorSpec) { if (cmdlineP->predictor != 1 && cmdlineP->predictor != 2) - pm_error("-predictor may be only 1 or 2. You specified %d.", + pm_error("-predictor may be only 1 or 2. You specified %d.", cmdlineP->predictor); } else cmdlineP->predictor = -1; @@ -272,25 +281,25 @@ parseCommandLine(int argc, } else cmdlineP->yresolution = -1; - if (resolutionUnitSpec) { - if (streq(resolutionUnit, "inch")) - cmdlineP->resolutionUnit = RESUNIT_INCH; - else if (streq(resolutionUnit, "in")) - cmdlineP->resolutionUnit = RESUNIT_INCH; - else if (streq(resolutionUnit, "centimeter")) - cmdlineP->resolutionUnit = RESUNIT_CENTIMETER; - else if (streq(resolutionUnit, "cm")) - cmdlineP->resolutionUnit = RESUNIT_CENTIMETER; - else if (streq(resolutionUnit, "none")) - cmdlineP->resolutionUnit = RESUNIT_NONE; - else if (streq(resolutionUnit, "no")) - cmdlineP->resolutionUnit = RESUNIT_NONE; + if (resolutionunitSpec) { + if (streq(resolutionunit, "inch")) + cmdlineP->resolutionunit = RESUNIT_INCH; + else if (streq(resolutionunit, "in")) + cmdlineP->resolutionunit = RESUNIT_INCH; + else if (streq(resolutionunit, "centimeter")) + cmdlineP->resolutionunit = RESUNIT_CENTIMETER; + else if (streq(resolutionunit, "cm")) + cmdlineP->resolutionunit = RESUNIT_CENTIMETER; + else if (streq(resolutionunit, "none")) + cmdlineP->resolutionunit = RESUNIT_NONE; + else if (streq(resolutionunit, "no")) + cmdlineP->resolutionunit = RESUNIT_NONE; else pm_error("The only acceptable values for -resolutionunit are " "inch, centimeter, none, in, cm, and no. " - "You specified '%s'.", resolutionUnit); + "You specified '%s'.", resolutionunit); } else - cmdlineP->resolutionUnit = RESUNIT_INCH; + cmdlineP->resolutionunit = RESUNIT_INCH; if (indexbitsSpec) { if (strstr(indexbits, "1")) @@ -324,45 +333,17 @@ parseCommandLine(int argc, cmdlineP->taglist[0].value = NULL; } - if (argc-1 == 0) - cmdlineP->input_filespec = "-"; + if (argc-1 == 0) + cmdlineP->inputFileName = "-"; else if (argc-1 != 1) pm_error("Program takes zero or one argument (filename). You " "specified %d", argc-1); else - cmdlineP->input_filespec = argv[1]; + cmdlineP->inputFileName = argv[1]; } -static void -putSample(sample const s, - sample const maxval, - sample const tiff_maxval, - unsigned int const bitspersample, - unsigned char ** const tPP) { - - xelval s2; - - s2 = s; - if (maxval != tiff_maxval) - s2 = s * tiff_maxval / maxval; - if (bitspersample > 8) { - *((unsigned short *)(*tPP)) = s2; - (*tPP) += sizeof(short); - } else - *(*tPP)++ = s2 & 0xff; -} - - - - -/* Note: PUTSAMPLE doesn't work if bitspersample is 1-4. */ - -#define PUTSAMPLE putSample(s, maxval, tiff_maxval, bitspersample, &tP); - - - static void fillRowOfSubBytePixels(struct pam * const pamP, const tuple * const tuplerow, @@ -380,9 +361,9 @@ fillRowOfSubBytePixels(struct pam * const pamP, int bitshift; /* The number of bits we have to shift a pixel value left to line it up with where the current pixel goes in the current byte of - the output buffer. + the output buffer. */ - int const firstbitshift = + int const firstbitshift = (fillorder == FILLORDER_MSB2LSB) ? 8 - bitspersample : 0; /* The value of 'bitshift' for the first pixel into a byte of the output buffer. (MSB2LSB is normal). @@ -397,7 +378,7 @@ fillRowOfSubBytePixels(struct pam * const pamP, /* The under-construction value of the byte pointed to by tP, above. */ - + bitshift = firstbitshift; byte = 0; for (col = 0, tP = buf; col < pamP->width; ++col) { @@ -406,7 +387,7 @@ fillRowOfSubBytePixels(struct pam * const pamP, s = tuplerow[col][0]; if (pamP->maxval != tiff_maxval ) s = (long) s * tiff_maxval / pamP->maxval; - + if (photometric == PHOTOMETRIC_MINISWHITE) s = tiff_maxval - s; } else { @@ -439,6 +420,36 @@ fillRowOfSubBytePixels(struct pam * const pamP, +static void +putSample(sample const s, + sample const maxval, + sample const tiffMaxval, + unsigned int const bitspersample, + bool const minIsWhite, + unsigned char ** const tPP) { + + /* Until release 10.48 (September 2009), we ignored the min-is-white + photometric (i.e. treated it like min-is-black). Nobody has ever + complained, but it seems clear to me that that was wrong, so I + changed it. We have always respected it for sub-byte samples, + and have always respected it going the other direction, in + Tifftopnm. + - Bryan. + */ + + xelval const s2 = maxval == tiffMaxval ? s : s * tiffMaxval / maxval; + + xelval const s3 = minIsWhite ? tiffMaxval - s2 : s2; + + if (bitspersample > 8) { + *((unsigned short *)(*tPP)) = s3; + (*tPP) += sizeof(short); + } else + *(*tPP)++ = s3 & 0xff; +} + + + static void fillRowOfWholeBytePixels(struct pam * const pamP, tuple * const tuplerow, @@ -447,10 +458,12 @@ fillRowOfWholeBytePixels(struct pam * const pamP, unsigned short const tiffMaxval, unsigned int const bitsPerSample) { + bool const minIsWhite = (photometric == PHOTOMETRIC_MINISWHITE); + unsigned int col; unsigned char * tP; unsigned int planes; - + if (photometric == PHOTOMETRIC_RGB) planes = pamP->depth; else @@ -463,22 +476,22 @@ fillRowOfWholeBytePixels(struct pam * const pamP, unsigned int plane; for (plane = 0; plane < planes; ++plane) { putSample(tuplerow[col][plane], pamP->maxval, - tiffMaxval, bitsPerSample, &tP); + tiffMaxval, bitsPerSample, minIsWhite, &tP); /* Advances tP */ } } -} +} static void writeScanLines(struct pam * const pamP, - TIFF * const tif, + TIFF * const tif, tuplehash const cht, unsigned short const tiffMaxval, - unsigned short const bitspersample, + unsigned short const bitspersample, unsigned short const photometric, - int const bytesperrow, + int const bytesperrow, int const fillorder) { /*---------------------------------------------------------------------------- Write out the raster for the input image described by 'pamP', whose @@ -492,15 +505,19 @@ writeScanLines(struct pam * const pamP, it's 'buf' parameter, but here it is: Its format depends on the bits per pixel of the TIFF image. If it's 16, 'buf' is an array of short (16 bit) integers, one per raster column. If - it's 8, 'buf' is an array of characters (8 bit integers), one - per image column. If it's less than 8, it's an array of characters, - each of which represents 1-8 raster columns, packed + it's 8, 'buf' is an array of 8 bit unsigned integers, one + per pixel sample. If it's less than 8, it's an array of bytes, + each of which represents 1-8 pixel samples, packed into it in the order specified by the TIFF image's fill order, with don't-care bits on the right such that each byte contains only - whole pixels. + whole samples. In all cases, the array elements are in order left to right going from low array indices to high array indices. + + The samples form pixel values according to the pixel format indicated + by the TIFF photometric. E.g. if it is MINISWHITE, then a pixel is + one sample and a value of 0 for that sample means white. */ MALLOCARRAY(buf, bytesperrow); @@ -508,7 +525,7 @@ writeScanLines(struct pam * const pamP, pm_error("can't allocate memory for row buffer"); tuplerow = pnm_allocpamrow(pamP); - + for (row = 0; row < pamP->height; ++row) { int col; @@ -530,9 +547,9 @@ writeScanLines(struct pam * const pamP, for (col = 0; col < pamP->width; ++col) { int si; int found; - + pnm_lookuptuple(pamP, cht, tuplerow[col], &found, &si); - + if (!found) pm_error("INTERNAL ERROR. We made a color map, and a " "color map we need is not in it! " @@ -556,12 +573,12 @@ writeScanLines(struct pam * const pamP, static void -analyzeColorsInRgbInput(struct pam * const pamP, - struct cmdlineInfo const cmdline, - int const maxcolors, - tupletable * const chvP, - unsigned int * const colorsP, - bool * const grayscaleP) { +analyzeColorsInRgbInput(struct pam * const pamP, + CmdlineInfo const cmdline, + int const maxcolors, + tupletable * const chvP, + unsigned int * const colorsP, + bool * const grayscaleP) { /*---------------------------------------------------------------------------- Same as analyzeColors(), except assuming input image has R/G/B tuples. -----------------------------------------------------------------------------*/ @@ -580,7 +597,7 @@ analyzeColorsInRgbInput(struct pam * const pamP, grayscale = FALSE; } else { unsigned int i; - pm_message("%u color%s found", + pm_message("%u color%s found", *colorsP, *colorsP == 1 ? "" : "s"); grayscale = TRUE; /* initial assumption */ for (i = 0; i < *colorsP && grayscale; ++i) { @@ -613,15 +630,15 @@ analyzeColorsInRgbInput(struct pam * const pamP, static void -analyzeColors(struct pam * const pamP, - struct cmdlineInfo const cmdline, - int const maxcolors, - tupletable * const chvP, - unsigned int * const colorsP, - bool * const grayscaleP) { +analyzeColors(struct pam * const pamP, + CmdlineInfo const cmdline, + int const maxcolors, + tupletable * const chvP, + unsigned int * const colorsP, + bool * const grayscaleP) { /*---------------------------------------------------------------------------- Analyze the colors in the input image described by 'pamP', whose file - is positioned to the raster. + is positioned to the raster. If the colors, combined with command line options 'cmdline', indicate a colormapped TIFF should be generated, return as *chvP the address @@ -650,13 +667,13 @@ analyzeColors(struct pam * const pamP, static void computeRasterParm(struct pam * const pamP, - tupletable const chv, - int const colors, + tupletable const chv, + int const colors, bool const grayscale, int const compression, bool const minisblack, bool const miniswhite, - struct sizeset const indexsizeAllowed, + SizeSet const indexsizeAllowed, unsigned short * const samplesperpixelP, unsigned short * const bitspersampleP, unsigned short * const photometricP, @@ -677,7 +694,7 @@ computeRasterParm(struct pam * const pamP, option. It is not clear why we don't use bits per pixel < 8 for RGB images. Note that code to handle maxvals <= 255 was written long before maxval > 255 was possible and there are - backward compatibility requirements. + backward compatibility requirements. */ if (pamP->depth == 1 && pamP->maxval == 1) { @@ -691,7 +708,7 @@ computeRasterParm(struct pam * const pamP, } else { if (chv) { *samplesperpixelP = 1; /* Pixel is just the one index value */ - *bitspersampleP = + *bitspersampleP = colors <= 2 && indexsizeAllowed.b1 ? 1 : colors <= 4 && indexsizeAllowed.b2 ? 2 : colors <= 16 && indexsizeAllowed.b4 ? 4 : @@ -744,18 +761,53 @@ computeRasterParm(struct pam * const pamP, -static void -validateSeekableOutputFile(int const ofd, - const char * const outFileName) { /*---------------------------------------------------------------------------- - Validate that the file attached to file descriptor 'ofd' is capable - of seeking. If not, fail the program. + WRITE MODES + ----------- + + The Tiff library does all output. There are several issues: + + 1) The manner of output is opaque to the library client. I.e. we cannot + see or control it. + + 2) The output file must be random-access. + + 3) The output file must be writable and readable for multiple-image + streams. (This includes append operations.) + + 4) The Tiff library produces unhelpful error messages when the above + conditions are not met. + + We provide two modes for output: + + 1. Tmpfile mode (default) + + We have the Tiff library direct output to an unnamed temporary file we + create which is seekable and readable. When output is complete, we copy + the file's contents to Standard Output. + + 2. Direct mode (specified with -output) + + We have the Tiff library write output to the specified file. As the Tiff + library requires taht it be be seekable and readable, we fail the program + rather than ask the Tiff library to use the file if it does not meet + these requirements. + + Direct mode is further divided into append and create. They are the same + except that in append mode, we insist that the file already exist, + whereas with create mode, we create it if necessary. In either case, if + the file already exists, he Tiff library appends the output to it. +-----------------------------------------------------------------------------*/ + - This is useful because the TIFF library requires seekable output and - fails with an unhelpful error message about a file I/O error if it is - not. We, on the other hand, give a helpful error message. - We leave the file positioned to the beginning. +static bool +fileIsSeekable(int const ofd, + const char * const outFileName) { +/*---------------------------------------------------------------------------- + The file represented by 'ofd' iscapable of seeking. + + As a side effect, we position the file to the beginning. -----------------------------------------------------------------------------*/ int rc; @@ -769,44 +821,170 @@ validateSeekableOutputFile(int const ofd, */ lseek(ofd, 1, SEEK_SET); rc = lseek(ofd, 0, SEEK_SET); - - if (rc < 0) - pm_error("Output file (%s) is not seekable. lseek() returned " - "errno %d (%s). " - "The TIFF library can write only to " - "a seekable file.", - outFileName, errno, strerror(errno)); + + return rc >= 0; + +} + + + +static void +validateReadableOutputFile(int const ofd) { +/*---------------------------------------------------------------------------- + Validate that file 'ofd' is readable and fail the program if it isn't. + + This is useful because there are situations in which the TIFF library must + read the output file and if it can't, it fails with an unhelpful error + message about a file I/O error. We, on the other hand, produce a helpful + error message. +-----------------------------------------------------------------------------*/ +#if !MSVCRT + + int flags; + + flags = fcntl(ofd, F_GETFL); + + if (flags < 0) { + /* We couldn't get the flags. So just assume the file's OK */ + } else { + if ((flags & O_RDONLY) || (flags & O_RDWR)) { + /* File is readable. All is well. */ + } else + pm_error("Output is not opened for reading. " + "In order to create a multi-image TIFF stream, " + "output must be both readable and writable."); + } +#endif } static void -createTiffGenerator(int const ofd, - const char * const outFileName, - bool const append, - TIFF ** const tifPP) { +createTiffGeneratorDirect(const char * const outputFileName, + CreatePolicy const createPolicy, + TIFF ** const tifPP, + int * const ofdP) { +/*---------------------------------------------------------------------------- + Create a TIFF generator that writes its output to the specified file. - const char * option; + If the file doesn't already exist and 'createPolicy' is MayCreate, + create the file; otherwise fail the program. - validateSeekableOutputFile(ofd, outFileName); + Fail the program if the specified file is not seekable and readable. - if (append) - option = "a"; + Return the handle of the TIFF generator as *tifPP. Also return the + file descriptor for the output file as *ofdP. +-----------------------------------------------------------------------------*/ + int fd; + + if (createPolicy == MUST_EXIST) + fd = open(outputFileName, O_RDWR); else - option = "w"; + fd = open(outputFileName, (O_RDWR | O_CREAT), 00644); + + if (fd == -1) { + if (errno == ENOENT) /* Possible only if MustExist */ + pm_error ("Cannot open file : '%s'. File does not exist.", + outputFileName); + else + pm_error ("Cannot open file : '%s'. open() failed with " + "errno %d (%s). ", + outputFileName, errno, strerror(errno)); + } - *tifPP = TIFFFdOpen(ofd, outFileName, option); + if (!fileIsSeekable(fd, outputFileName)) + pm_error("Output file (%s) is not seekable. " + "lseek() returned errno %d (%s). " + "The TIFF library can write only to " + "a seekable file.", + outputFileName, errno, strerror(errno)); + + *tifPP = TIFFFdOpen(fd, outputFileName, "a"); if (*tifPP == NULL) - pm_error("error opening standard output as TIFF file. " + pm_error("error opening file %s as TIFF file. " + "TIFFFdOpen() failed.", outputFileName); + + *ofdP = fd; +} + + + +static void +createTiffGeneratorTmpfile(TIFF ** const tifPP, + int * const ofdP) { +/*---------------------------------------------------------------------------- + Create a TIFF generator that writes its output to an unnnamed temporary file + we create. + + Return the handle of the TIFF generator as *tifPP. Also return the file + descriptor for the temporary file as *ofdP. + + The TIFF generator has a file name attribute, but it is just for messages; + it is not the name of a file. We use "Internal Temporary File". +-----------------------------------------------------------------------------*/ + int fd; + + fd = pm_tmpfile_fd(); + + *tifPP = TIFFFdOpen(fd, "Internal Temporary File", "w"); + + if (*tifPP == NULL) + pm_error("error opening temporary file as TIFF file. " "TIFFFdOpen() failed."); + + *ofdP = fd; +} + + + +static void +copyBufferToStdout(int const tmpfileFd) { + + FILE * tmpfileP; + + tmpfileP = fdopen(tmpfileFd, "rb"); + + fseek(tmpfileP, 0, SEEK_SET); + + while (!feof(tmpfileP) && !ferror(tmpfileP) && !ferror(stdout)) { + char buffer[4096]; + size_t bytesReadCt; + + bytesReadCt = fread(buffer, 1, sizeof(buffer), tmpfileP); + + if (ferror(tmpfileP)) + pm_error("Error reading from temporary file. " + "Incomplete output. " + "Errno = %s (%d)", strerror(errno), errno); + else + fwrite(buffer, 1, bytesReadCt, stdout); + } + + /* POSIX lets us create a FILE from an existing file descriptor, but + does not provide a way to destroy the FILE and keep the file + descriptor. The following fclose() closes the file. Caller + must not access the file again, and if he attempts to close it, + must ignore the failure of close + */ + fclose(tmpfileP); } static void -destroyTiffGenerator(TIFF * const tifP) { +destroyTiffGenerator(WriteMethod const writeMethod, + TIFF * const tifP, + int const ofd) { TIFFFlushData(tifP); + + if (writeMethod == TMPFILE) + copyBufferToStdout(ofd); + + /* If we copied the buffer above, the buffer file is already closed + (copyBufferToStdout closes it), TIFFClose appears to tolerate that - + all it does is a close() and doesn't mind that it fails. + */ TIFFClose(tifP); } @@ -823,11 +1001,11 @@ createTiffColorMap(struct pam * const pamP, unsigned short ** tiffColorMap; unsigned int plane; unsigned int i; - + MALLOCARRAY_NOFAIL(tiffColorMap, pamP->depth); for (plane = 0; plane < pamP->depth; ++plane) MALLOCARRAY_NOFAIL(tiffColorMap[plane], colorMapSize); - + for (i = 0; i < colorMapSize; ++i) { unsigned int plane; for (plane = 0; plane < pamP->depth; ++plane) { @@ -840,7 +1018,7 @@ createTiffColorMap(struct pam * const pamP, } *tiffColorMapP = tiffColorMap; } - + static void @@ -865,7 +1043,7 @@ setTagListFields(const struct optNameValue * const taglist, for (i = 0; taglist[i].name; ++i) { const tagDefinition * const tagDefP = tagDefFind(taglist[i].name); - + if (tagDefP->put) tagDefP->put(tifP, tagDefP->tagnum, taglist[i].value, tagDefP->choices); @@ -876,7 +1054,7 @@ setTagListFields(const struct optNameValue * const taglist, static void setTiffFields(TIFF * const tifP, - struct cmdlineInfo const cmdline, + CmdlineInfo const cmdline, struct pam * const pamP, unsigned short const bitspersample, unsigned short const photometric, @@ -911,12 +1089,17 @@ setTiffFields(TIFF * const tifP, else TIFFSetField(tifP, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tifP, 0)); + /* Since Netpbm 10.31, we prefer that the user use -tags to specify + RESOLUTIONUNIT, XRESOLUTION, and YRESOLUTION, but retain + -xresolution, -yresolution, and -resolutionunit for backward + compatibility + */ if (cmdline.xresolution != -1 || cmdline.yresolution != -1 || - cmdline.resolutionUnit != -1) { + cmdline.resolutionunit != -1) { TIFFSetField(tifP, TIFFTAG_RESOLUTIONUNIT, - cmdline.resolutionUnit != -1 ? - cmdline.resolutionUnit : RESUNIT_NONE); + cmdline.resolutionunit != -1 ? + cmdline.resolutionunit : RESUNIT_NONE); } if (cmdline.xresolution > 0) TIFFSetField(tifP, TIFFTAG_XRESOLUTION, cmdline.xresolution); @@ -933,7 +1116,7 @@ setTiffFields(TIFF * const tifP, TIFFSetField(tifP, TIFFTAG_DOCUMENTNAME, inputFileDescription); TIFFSetField(tifP, TIFFTAG_IMAGEDESCRIPTION, "converted PNM file"); - + /* Some of taglist[] overrides defaults we set above. But taglist[] is defined not to specify any tag types that are not purely user choice. @@ -944,10 +1127,10 @@ setTiffFields(TIFF * const tifP, static void -convertImage(FILE * const ifP, - TIFF * const tifP, - const char * const inputFileDescription, - struct cmdlineInfo const cmdline) { +convertImage(FILE * const ifP, + TIFF * const tifP, + const char * const inputFileDescription, + CmdlineInfo const cmdline) { tupletable chv; tuplehash cht; @@ -959,7 +1142,7 @@ convertImage(FILE * const ifP, unsigned short samplesperpixel; unsigned short bitspersample; unsigned short tiff_maxval; - /* This is the maxval of the samples in the tiff file. It is + /* This is the maxval of the samples in the tiff file. It is determined solely by the bits per sample ('bitspersample'). */ int bytesperrow; @@ -972,11 +1155,11 @@ convertImage(FILE * const ifP, analyzeColors(&pam, cmdline, MAXCOLORS, &chv, &colors, &grayscale); /* Go back to beginning of raster */ - pm_seek2(ifP, &rasterPos, sizeof(rasterPos)); + pm_seek2(ifP, &rasterPos, sizeof(rasterPos)); /* Figure out TIFF parameters. */ - computeRasterParm(&pam, chv, colors, grayscale, + computeRasterParm(&pam, chv, colors, grayscale, cmdline.compression, cmdline.minisblack, cmdline.miniswhite, cmdline.indexsizeAllowed, @@ -1001,7 +1184,7 @@ convertImage(FILE * const ifP, cmdline.taglist); writeScanLines(&pam, tifP, cht, - tiff_maxval, bitspersample, photometric, bytesperrow, + tiff_maxval, bitspersample, photometric, bytesperrow, cmdline.fillorder); if (tiffColorMap) @@ -1010,63 +1193,41 @@ convertImage(FILE * const ifP, -static void -validateReadableStdout(void) { -/*---------------------------------------------------------------------------- - We validate that Standard Output is readable and fail the program if - it isn't. - - This is useful because there are situations in which the TIFF library - must read the output file and if it can't, it fails with an unhelpful - error message about a file I/O error. We, on the other hand, produce - a helpful error message. ------------------------------------------------------------------------------*/ -#if !defined(WIN32) || defined(__CYGWIN__) - - int flags; - - flags = fcntl(STDOUT_FILENO, F_GETFL); - - if (flags < 0) { - /* We couldn't get the flags. So just assume the file's OK */ - } else { - if ((flags & O_RDONLY) || (flags & O_RDWR)) { - /* File is readable. All is well. */ - } else - pm_error("Standard Output is not opened for reading. " - "In order to create a multi-image TIFF stream, " - "Standard Output must be both readable and writable."); - } -#endif -} int -main(int argc, char *argv[]) { - struct cmdlineInfo cmdline; +main(int argc, const char *argv[]) { + CmdlineInfo cmdline; const char * inputFileDescription; - FILE* ifP; - TIFF* tifP; - bool eof; + FILE * ifP; + TIFF * tifP; + int ofd; + int eof; unsigned int imageSeq; - - pnm_init(&argc, argv); - - parseCommandLine(argc, argv, &cmdline); - ifP = pm_openr_seekable(cmdline.input_filespec); + pm_proginit(&argc, argv); - if (streq(cmdline.input_filespec, "-")) - inputFileDescription = "Standard Input"; - else - inputFileDescription = cmdline.input_filespec; + parseCommandLine(argc, argv, &cmdline); - if (cmdline.append) - validateReadableStdout(); + ifP = pm_openr_seekable(cmdline.inputFileName); - createTiffGenerator(STDOUT_FILENO, "Standard Output", cmdline.append, - &tifP); + if (streq(cmdline.inputFileName, "-")) + inputFileDescription = "Standard Input"; + else + inputFileDescription = cmdline.inputFileName; + + switch (cmdline.writeMethod) { + case DIRECT_APPEND: + createTiffGeneratorDirect(cmdline.output, MUST_EXIST, &tifP, &ofd); + break; + case DIRECT_CREATE: + createTiffGeneratorDirect(cmdline.output, MAY_CREATE, &tifP, &ofd); + break; + case TMPFILE: + createTiffGeneratorTmpfile(&tifP, &ofd); + break; + } eof = FALSE; /* initial assumption */ imageSeq = 0; @@ -1074,17 +1235,17 @@ main(int argc, char *argv[]) { while (!eof) { bool success; - if (cmdline.verbose) - pm_message("Converting Image %u", imageSeq); - pnm_nextimage(ifP, &eof); if (!eof) { if (imageSeq > 0) - validateReadableStdout(); + validateReadableOutputFile(ofd); + + if (cmdline.verbose) + pm_message("Converting Image %u", imageSeq); convertImage(ifP, tifP, inputFileDescription, cmdline); - + success = TIFFWriteDirectory(tifP); if (!success) pm_error("Unable to write TIFF image %u to file. " @@ -1093,8 +1254,10 @@ main(int argc, char *argv[]) { } } - destroyTiffGenerator(tifP); + destroyTiffGenerator(cmdline.writeMethod, tifP, ofd); pm_close(ifP); return 0; } + + diff --git a/converter/other/pamtouil.c b/converter/other/pamtouil.c index 1a53be0f..ee7f5ae6 100644 --- a/converter/other/pamtouil.c +++ b/converter/other/pamtouil.c @@ -61,7 +61,7 @@ parseCommandLine(int argc, char ** argv, malloc'ed storage. -----------------------------------------------------------------------------*/ optEntry *option_def = malloc( 100*sizeof( optEntry ) ); - /* Instructions to optParseOptions3 on how to parse our options. + /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; @@ -79,7 +79,7 @@ parseCommandLine(int argc, char ** argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We may have parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (argc-1 == 0) @@ -374,9 +374,9 @@ freeCmap(cixel_map const cmap[], for (i = 0; i < ncolors; ++i) { cixel_map const cmapEntry = cmap[i]; if (cmapEntry.uilname) - strfree(cmapEntry.uilname); + pm_strfree(cmapEntry.uilname); if (cmapEntry.rgbname) - strfree(cmapEntry.rgbname); + pm_strfree(cmapEntry.rgbname); } } diff --git a/converter/other/pamtowinicon.c b/converter/other/pamtowinicon.c new file mode 100644 index 00000000..7e2c9e86 --- /dev/null +++ b/converter/other/pamtowinicon.c @@ -0,0 +1,1177 @@ +#define _POSIX_SOURCE /* Make sure fdopen() is in */ +#include +#include +#include + +#include "netpbm/pm_config.h" +#include "netpbm/pm_c_util.h" +#include "netpbm/mallocvar.h" +#include "netpbm/nstring.h" +#include "netpbm/shhopt.h" +#include "netpbm/pm_system.h" +#include "netpbm/pam.h" +#include "winicon.h" + + + +struct CmdlineInfo { + const char * inputFileName; + unsigned int verbose; + int pngthreshold; + unsigned int truetransparent; +}; + + + +static void +parseCommandLine(int argc, const char **argv, + struct CmdlineInfo * const cmdlineP) { + + optEntry * option_def; + unsigned int option_def_index; + optStruct3 opt3; + unsigned int pngthresholdSpec; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; + + OPTENT3(0, "verbose", OPT_FLAG, NULL, + &cmdlineP->verbose, 0); + OPTENT3(0, "pngthreshold", OPT_UINT, &cmdlineP->pngthreshold, + &pngthresholdSpec, 0); + OPTENT3(0, "truetransparent", OPT_FLAG, NULL, + &cmdlineP->truetransparent, 0); + + opt3.opt_table = option_def; + opt3.short_allowed = false; + opt3.allowNegNum = false; + + pm_optParseOptions3(&argc, (char **)argv, opt3, sizeof(opt3), 0); + + if (pngthresholdSpec) { + if (UINT_MAX / cmdlineP->pngthreshold < cmdlineP->pngthreshold) + pm_error("-pngthreshold is too large: %u", cmdlineP->pngthreshold); + } else + cmdlineP->pngthreshold = 128; + + if (argc-1 > 0) { + cmdlineP->inputFileName = argv[1]; + + if (argc-1 > 1) + pm_error("Too many arguments: %u. The only non-option " + "argument is the optional input file name", argc-1); + } else + cmdlineP->inputFileName = "-"; + + free(option_def); +} + + + +static bool verbose; + +static unsigned char const pngHeader[] = PNG_HEADER; + + + +struct Palette { + sample color[256][3]; + unsigned int colorCt; + /* Number of colors in color[][] */ + bool tooManyColors; + /* There are too many colors for a BMP palette (more than 256); only + the first 256 are in color[][] + */ +}; + + + +static struct IconDir * +newIconDir() { + + struct IconDir * dirP; + + MALLOCVAR_NOFAIL(dirP); + + dirP->zero = 0; + dirP->type = ICONDIR_TYPE_ICO; + dirP->count = 0; + + dirP->entriesAllocCt = 0; + dirP->entries = NULL; + + return dirP; +} + + + +static void +freeIconDir(struct IconDir * const dirP) { + if (dirP->entries) + free(dirP->entries); + + free(dirP); +} + + + +static void +addToDirectory(struct IconDirEntry * const dirEntryP, + struct IconDir * const dirP) { +/*---------------------------------------------------------------------------- + Add an icon to the icon directory. +-----------------------------------------------------------------------------*/ + if (dirP->count + 1 > dirP->entriesAllocCt) { + /* Out of space in dirP->entries[]. Expand. */ + + dirP->entriesAllocCt += 8; + + REALLOCARRAY(dirP->entries, dirP->entriesAllocCt); + + if (!dirP->entries) + pm_error("Unable to get memory for %u entries " + "in the Icon directory.", dirP->entriesAllocCt); + } + + dirP->entries[dirP->count++] = *dirEntryP; +} + + + +typedef void (GetPixelFn) (tuple ** const tuples, + unsigned int const col, + unsigned int const row, + sample * const pixel); + + + +static GetPixelFn get_grayscalePixel; + +static void +get_grayscalePixel(tuple ** const tuples, + unsigned int const col, + unsigned int const row, + sample * const pixel) { +/*---------------------------------------------------------------------------- + Get a pixel from a grayscale PAM +-----------------------------------------------------------------------------*/ + pixel[0] = tuples[row][col][0]; + pixel[1] = tuples[row][col][0]; + pixel[2] = tuples[row][col][0]; +} + + + +static GetPixelFn get_rgbPixel; + +static void +get_rgbPixel(tuple ** const tuples, + unsigned int const col, + unsigned int const row, + sample * const pixel) { +/*---------------------------------------------------------------------------- + Get a pixel from an RGB PAM +-----------------------------------------------------------------------------*/ + pixel [0] = tuples [row][col][0]; + pixel [1] = tuples [row][col][1]; + pixel [2] = tuples [row][col][2]; +} + + +static bool +andMakesOpaque(const struct pam * const pamP, + tuple ** const tuples, + unsigned int const row, + unsigned int const col, + bool const haveAlpha, + unsigned int const alphaPlane, + bool const haveAnd, + unsigned int const andPlane) { +/*---------------------------------------------------------------------------- + The AND mask makes a pixel opaque +-----------------------------------------------------------------------------*/ + if (haveAnd) + return (pamP->maxval <= tuples[row][col][andPlane]); + else if (haveAlpha) + return (pamP->maxval <= tuples[row][col][alphaPlane]); + else + /* neither alpha channel nor AND mask: full opacity */ + return true; +} + + + +static void +getPalette(struct pam * const pamP, + tuple ** const tuples, + GetPixelFn * const getPixel, + struct Palette * const paletteP) { +/*---------------------------------------------------------------------------- + Create the palette for all the colors in 'tuples'. +-----------------------------------------------------------------------------*/ + unsigned int row; + + paletteP->colorCt = 0; /* initial value */ + paletteP->tooManyColors = false; /* initial value */ + + for (row = 0; pamP->height > row && !paletteP->tooManyColors; ++row) { + unsigned int col; + for (col = 0; pamP->width > col && !paletteP->tooManyColors; ++col) { + sample pixel[3]; + unsigned int i; + + getPixel(tuples, col, row, pixel); + + for (i = 0; i < paletteP->colorCt; ++i) { + if ((paletteP->color[i][0] == pixel[0]) + && (paletteP->color[i][1] == pixel[1]) + && (paletteP->color[i][2] == pixel[2])) + break; + } + if (i == paletteP->colorCt) { + /* We didn't find the color. */ + if (paletteP->colorCt >= 256) { + /* Image exceeds the palette capacity */ + paletteP->tooManyColors = true; + } else { + /* Add the color to the palette */ + paletteP->color[paletteP->colorCt][0] = pixel[0]; + paletteP->color[paletteP->colorCt][1] = pixel[1]; + paletteP->color[paletteP->colorCt][2] = pixel[2]; + + ++paletteP->colorCt; + } + } + } + } +} + + + +static bool +realAlphaNeeded(const struct pam * const pamP, + tuple ** const tuples, + unsigned int const alphaPlane) { +/*---------------------------------------------------------------------------- + A real alpha channel (in contrast to an AND mask) is needed to represent the + image in 'tuples', given that 'alphaPlane' is the alpha plane. + + A real alpha channel is needed if any pixel is translucent (neither opaque + nor transparent). +-----------------------------------------------------------------------------*/ + unsigned int row; + + for (row = 0; row < pamP->height; ++row) { + unsigned int col; + for (col = 0; col < pamP->width; ++col) { + sample const opacity = tuples[row][col][alphaPlane]; + + if (opacity != 0 && opacity != pamP->maxval) + return true; + } + } + return false; +} + + + +static void +writeBmpImageHeader(unsigned int const width, + unsigned int const height, + unsigned int const bpp, + unsigned int const rasterSize, + FILE * const ofP) { +/*---------------------------------------------------------------------------- + + Write BMP image header + + Note: bm_height is sum of rows in XOR mask and AND mask, while + image_size is the size of the AND mask only. + + image_size does not include the sizes of the (optional) palette + and the (mandatory) AND mask. +-----------------------------------------------------------------------------*/ + pm_writelittlelongu (ofP, 40); /* header_size */ + pm_writelittlelongu (ofP, width); /* bm_width */ + pm_writelittlelongu (ofP, height *2); /* bm_height */ + pm_writelittleshortu (ofP, 1); /* color_planes */ + pm_writelittleshortu (ofP, bpp); /* bits_per_pixel */ + pm_writelittlelongu (ofP, BI_RGB); /* compression_method */ + pm_writelittlelongu (ofP, rasterSize); /* image_size */ + pm_writelittlelongu (ofP, 0); /* horizontal_resolution*/ + pm_writelittlelongu (ofP, 0); /* vertical_resolution */ + pm_writelittlelongu (ofP, 0); /* colors_in_palette */ + pm_writelittlelongu (ofP, 0); /* important_colors */ +} + + + +static void +write32BitBmp(const struct pam * const pamP, + tuple ** const tuples, + GetPixelFn * const getPixel, + bool const haveAlpha, + unsigned int const alphaPlane, + FILE * const ofP, + uint32_t * const sizeP) { +/*---------------------------------------------------------------------------- + Write a 32-bit BMP encoded image to file *ofP. +-----------------------------------------------------------------------------*/ + int row; + + writeBmpImageHeader(pamP->width, pamP->height, 32, + pamP->width * 4 * pamP->height, ofP); + + /* write "XOR mask" */ + for (row = pamP->height - 1; row >= 0; --row) { + unsigned int col; + for (col = 0; col < pamP->width; ++col) { + sample pixel[3]; + uint32_t val; + + getPixel(tuples, col, row, pixel); + + val = ((uint32_t) pixel[PAM_RED_PLANE] << 16) + + ((uint32_t) pixel[PAM_GRN_PLANE] << 8) + + ((uint32_t) pixel[PAM_BLU_PLANE] << 0) + ; + + if (haveAlpha) + val += (uint32_t) tuples[row][col][alphaPlane] << 24; + + pm_writelittlelongu(ofP, val); + } + } + *sizeP = 40 + pamP->height * pamP->width * 4; +} + + + +static void +writeBmpPalette(const struct Palette * const paletteP, + unsigned int const maxColors, + FILE * const ofP) { +/*---------------------------------------------------------------------------- + Write the palette of a BMP image. +-----------------------------------------------------------------------------*/ + unsigned int i; + + for (i = 0; i < paletteP->colorCt; ++i) + pm_writelittlelongu(ofP, 0 + +(paletteP->color[i][PAM_RED_PLANE] << 16) + +(paletteP->color[i][PAM_GRN_PLANE] << 8) + +(paletteP->color[i][PAM_BLU_PLANE] << 0)); + + for (; i < maxColors; ++i) + pm_writelittlelongu(ofP, 0); +} + + + +static void +writeXorMask(const struct pam * const pamP, + tuple ** const tuples, + GetPixelFn * const getPixel, + const struct Palette * const paletteP, + unsigned int const bpp, + FILE * const ofP) { +/*---------------------------------------------------------------------------- + Write the "XOR mask" part of a BMP image. + + This is what one normally thinks of as the foreground image raster. +-----------------------------------------------------------------------------*/ + unsigned int const maxCol = ((pamP->width * bpp + 31) & ~31) / bpp; + + int row; + + for (row = pamP->height - 1; row >= 0; --row) { + uint8_t val; + uint16_t mask; + unsigned int col; + + mask = 0x1; + val = 0x0; + + for (col = 0; col < pamP->width; ++col) { + sample pixel[3]; + unsigned int i; + + mask <<= bpp; + val <<= bpp; + + getPixel(tuples, col, row, pixel); + + for (i = 0; i < paletteP->colorCt; ++i) + if (true + && (pixel[0] == paletteP->color[i][0]) + && (pixel[1] == paletteP->color[i][1]) + && (pixel[2] == paletteP->color[i][2])) + break; + + assert(i < paletteP->colorCt); + + val |= i; + + if (mask > 0xFF) { + pm_writecharu(ofP, val); + mask = 0x1; + val = 0x0; + } + } + for (; col < maxCol; ++col) { + mask <<= bpp; + val <<= bpp; + + if (mask > 0xFF) { + pm_writecharu(ofP, val); + mask = 0x1; + } + } + } +} + + + +static void +writePaletteBmp(unsigned int const bpp, + const struct pam * const pamP, + tuple ** const tuples, + GetPixelFn * const getPixel, + const struct Palette * const paletteP, + FILE * const ofP, + uint32_t * const sizeP) { +/*---------------------------------------------------------------------------- + Write a `BMP with palette' encoded image to file *ofP. + + Unless it would be smaller as a 32-bit direct image, in which case + write that instead. +-----------------------------------------------------------------------------*/ + unsigned int const maxColors = 1 << bpp; + + unsigned int const rasterSize = + pamP->height *((pamP->width * bpp + 31) & ~31) / 8; + + if (pamP->height * pamP->width * 4 <= maxColors * 4 + rasterSize) + write32BitBmp(pamP, tuples, getPixel, false /*haveAlpha*/, 0, + ofP, sizeP); + else { + unsigned int const headerSize = 40; + unsigned int const paletteSize = maxColors * 4; + + writeBmpImageHeader(pamP->width, pamP->height, bpp, rasterSize, ofP); + + writeBmpPalette(paletteP, maxColors, ofP); + + writeXorMask(pamP, tuples, getPixel, paletteP, bpp, ofP); + + *sizeP = headerSize + paletteSize + rasterSize; + } +} + + + +static void +writeAndMask(const struct pam * const pamP, + tuple ** const tuples, + bool const haveAlpha, + unsigned int const alphaPlane, + bool const haveAnd, + unsigned int const andPlane, + FILE * const ofP, + uint32_t * const sizeP) { +/*---------------------------------------------------------------------------- + Write the AND mask to file *ofP. +-----------------------------------------------------------------------------*/ + unsigned int const maxCol =((pamP->width * 1 + 31) & ~31) / 1; + + int row; + unsigned int sizeSoFar; + + sizeSoFar = 0; + + for (row = pamP->height - 1; row >= 0; --row) { + uint8_t val; + uint16_t mask; + unsigned int col; + + mask = 0x1; + val = 0x0; + + for (col = 0; col < pamP->width; ++col) { + mask <<= 1; + val <<= 1; + + if (!andMakesOpaque(pamP, tuples, row, col, + haveAlpha, alphaPlane, haveAnd, andPlane)) + val |= 0x1; + + if (mask > 0xFF) { + pm_writecharu(ofP, val); + sizeSoFar += 1; + mask = 0x1; + val = 0x0; + } + } + for (; col < maxCol; ++col) { + mask <<= 1; + val <<= 1; + + if (mask > 0xFF){ + pm_writecharu(ofP, val); + sizeSoFar += 1; + mask = 0x1; + } + } + } + *sizeP = sizeSoFar; +} + + + +static void +makeAlphaFile(const struct pam * const imagePamP, + tuple ** const imageTuples, + unsigned int const alphaPlane, + const char ** const alphaFileNameP) { + + FILE * alphaFileP; + struct pam alphaPam; + tuple ** alphaTuples; + unsigned int row; + + pm_make_tmpfile(&alphaFileP, alphaFileNameP); + + alphaPam.size = sizeof(alphaPam); + alphaPam.len = PAM_STRUCT_SIZE(tuple_type); + alphaPam.file = alphaFileP; + alphaPam.format = PAM_FORMAT; + alphaPam.width = imagePamP->width; + alphaPam.height = imagePamP->height; + alphaPam.depth = 1; + alphaPam.maxval = imagePamP->maxval; + strcpy(alphaPam.tuple_type, PAM_PGM_TUPLETYPE); + + alphaTuples = pnm_allocpamarray(&alphaPam); + + assert(alphaPlane < imagePamP->depth); + + for (row = 0; row < alphaPam.height; ++row) { + unsigned int col; + for (col = 0; col < alphaPam.width; ++col) + alphaTuples[row][col][0] = imageTuples[row][col][alphaPlane]; + } + + pnm_writepam(&alphaPam, alphaTuples); + + pnm_freepamarray(alphaTuples, &alphaPam); + + pm_close(alphaFileP); +} + + + +struct AcceptToFileParm { + FILE * ofP; + size_t * writeCtP; +}; + +static void +acceptToFile(int const pipeToSuckFd, + void * const accepterParm) { + + struct AcceptToFileParm * const parmP = accepterParm; + + FILE * const inFileP = fdopen(pipeToSuckFd, "r"); + + bool eof; + size_t copyCt; + + for (eof = false, copyCt = 0; !eof; ) { + size_t readCt; + unsigned char buffer[1024]; + + readCt = fread(buffer, 1, sizeof(buffer), inFileP); + + if (readCt == 0) + eof = true; + else { + size_t writeCt; + + writeCt = fwrite(buffer, 1, readCt, parmP->ofP); + + if (writeCt != readCt) + pm_error("Write to images file failed. errno=%d (%s)", + errno, strerror(errno)); + + copyCt += writeCt; + } + } + *parmP->writeCtP = copyCt; +} + + + +static void +writePng(const struct pam * const pamP, + tuple ** const tuples, + bool const haveAlpha, + unsigned int const alphaPlane, + bool const haveAnd, + unsigned int const andPlane, + uint32_t * const sizeP, + FILE * const ofP) { + + struct pamtuples pamTuples; + size_t pngSize; + struct AcceptToFileParm acceptParm; + struct pam pam; + + pam = *pamP; + pam.depth = pamP->depth - (haveAlpha ? 1 : 0) - (haveAnd ? 1 : 0); + + pamTuples.pamP = &pam; + pamTuples.tuplesP = (tuple ***)&tuples; + + /* We're going to fork a process to add stuff to *ofP, so we flush + out this process' previous writes to that file first: + */ + fflush(ofP); + + acceptParm.ofP = ofP; + acceptParm.writeCtP = &pngSize; + + if (haveAlpha || haveAnd) { + const char * alphaFileName; + const char * command; + + if (haveAlpha) + makeAlphaFile(pamP, tuples, alphaPlane, &alphaFileName); + else + makeAlphaFile(pamP, tuples, andPlane, &alphaFileName); + + strcpy (pam.tuple_type, + pam.depth == 3 ? PAM_PPM_TUPLETYPE: PAM_PGM_TUPLETYPE); + + pm_asprintf(&command, "pnmtopng -alpha=\"%s\"", alphaFileName); + + pm_system(pm_feed_from_pamtuples, &pamTuples, + acceptToFile, &acceptParm, + command); + + pm_strfree(command); + + unlink(alphaFileName); + } else { + pm_system(pm_feed_from_pamtuples, &pamTuples, + acceptToFile, &acceptParm, + "pnmtopng"); + } + + *sizeP = pngSize; +} + + + +static void +blackenXor(const struct pam * const pamP, + tuple ** const tuples, + bool const haveAlpha, + unsigned int const alphaPlane, + bool const haveAnd, + unsigned int const andPlane) { +/*---------------------------------------------------------------------------- + Set all pixels marked as transparent in AND mask to black. +-----------------------------------------------------------------------------*/ + unsigned int row; + + for (row = 0; row < pamP->height; ++row) { + unsigned int col; + for (col = 0; col < pamP->width; ++col) { + if (!andMakesOpaque(pamP, tuples, row, col, + haveAlpha, alphaPlane, haveAnd, andPlane)) { + tuples[row][col][0] = PAM_BLACK; + + if (pamP->depth >= 3) { + tuples[row][col][1] = PAM_BLACK; + tuples[row][col][2] = PAM_BLACK; + } + } + } + } +} + + + + +static void +readAndScalePam(struct pam * const pamP, + bool const doingPng, + tuple ** const tuples) { + + if (doingPng) { + /* Read the image with its native maxval */ + unsigned int row; + for (row = 0; row < pamP->height; ++row) + pnm_readpamrow(pamP, tuples[row]); + } else { + /* Read the image and scale to maxval 255 */ + tuple * tuplerow; + unsigned int row; + tuplerow = pnm_allocpamrow(pamP); + + for (row = 0; row < pamP->height; ++row) { + pnm_readpamrow(pamP, tuplerow); + pnm_scaletuplerow(pamP, tuples[row], tuplerow, 255); + } + pnm_freepamrow(tuplerow); + pamP->maxval = 255; + } +} + + + +static void +determineImageType(const struct pam * const pamP, + tuple ** const tuples, + GetPixelFn ** const getPixelP, + bool * const haveAlphaP, + unsigned int * const alphaPlaneP, + bool * const haveAndP, + unsigned int * const andPlaneP) { + + /* PAM input channels: + * + * 1-channel PAM: Grayscale + * 2-channel PAM: Grayscale +Alpha + * 3-channel PAM: RGB + * 4-channel PAM: RGB +Alpha + * 5-channel PAM: RGB +Alpha +AND mask + */ + switch (pamP->depth) { + case 1: + *getPixelP = get_grayscalePixel; + *haveAlphaP = false; + *haveAndP = false; + break; + + case 2: + *getPixelP = get_grayscalePixel; + if (realAlphaNeeded(pamP, tuples, 1)) { + *haveAlphaP = true; + *alphaPlaneP = 1; + *haveAndP = false; + } else { + *haveAlphaP = false; + *haveAndP = true; + *andPlaneP = 1; + } + break; + + case 3: + *getPixelP = get_rgbPixel; + *haveAlphaP = false; + *haveAndP = false; + break; + + case 4: + *getPixelP = get_rgbPixel; + if (realAlphaNeeded(pamP, tuples, 3)) { + *haveAlphaP = true; + *alphaPlaneP = 3; + *haveAndP = false; + } else { + *haveAlphaP = false; + *haveAndP = true; + *andPlaneP = 3; + } + break; + + case 5: + *getPixelP = get_rgbPixel; + *haveAlphaP = true; + *alphaPlaneP = 3; + *haveAndP = true; + *andPlaneP = 4; + break; + + default: + pm_error("unexpected PAM depth %u. " + "We understand depths 1-5", pamP->depth); + break; + } +} + + + +static void +reportImageInfo(unsigned int const imageNum, + const struct pam * const pamP, + const struct Palette * const paletteP, + bool const haveAlpha, + bool const haveAnd) { + + const char * colorCt; + + if (paletteP->tooManyColors) + pm_asprintf(&colorCt, "> 256"); + else + pm_asprintf(&colorCt, "%u", paletteP->colorCt); + + pm_message("Image %2u:" + " %3u x %3u x %u, %s colors%s%s", + imageNum, + pamP->width, pamP->height, pamP->depth, + colorCt, + haveAlpha ? ", alpha channel": "", + haveAnd ? ", AND mask": ""); + + pm_strfree(colorCt); +} + + + +static void +writeIconAndCreateDirEntry(const struct pam * const pamP, + tuple ** const tuples, + GetPixelFn * const getPixel, + bool const doingPng, + bool const haveAlpha, + unsigned int const alphaPlane, + bool const haveAnd, + unsigned int const andPlane, + bool const mustBlackenXor, + const struct Palette * const paletteP, + FILE * const ofP, + struct IconDirEntry * const dirEntryP) { +/*---------------------------------------------------------------------------- + Write to *ofP the icon image for the image represented by *pamP and + 'tuples'. + + Generate the information for an icon directory entry for this image + and return it as *dirEntryP. ==>BUT: the 'offset' member of this + structure will not be meaningful. <== + + Make a PNG image if 'doingPng' is true; BMP otherwise. + + 'haveAlpha' means that there is an alpha plane in 'tuples' and it is + Plane 'alphaPlane'. + + 'haveAnd' means that there is an AND plane in 'tuples' and it is Plane + 'andPlane'. + + *paletteP is the color palette for the icon; it contains an entry for each + color in 'tuples'. Except: it may simply indicate that there are too many + colors in 'tuples' to have a palette. + + The 'bits_per_pixel' member of the directory entry is supposed to tell the + color resolution of the image so the user can decide which of many versions + of the icon in the file to use. But we just call it 32 bits in every case + except paletted BMP, where it actually relates to how many colors are in + the image. +-----------------------------------------------------------------------------*/ + dirEntryP->width = pamP->width; + dirEntryP->height = pamP->height; + dirEntryP->color_planes = 1; + dirEntryP->zero = 0; + + if (doingPng) { + dirEntryP->color_count = 0; + dirEntryP->bits_per_pixel = 32; + + writePng(pamP, tuples, haveAlpha, alphaPlane, haveAnd, andPlane, + &dirEntryP->size, ofP); + } else { + uint32_t bmpSize; + uint32_t andMaskSize; + + if (mustBlackenXor) + blackenXor(pamP, tuples, + haveAlpha, alphaPlane, haveAnd, andPlane); + + if (haveAlpha) { + dirEntryP->color_count = 0; + dirEntryP->bits_per_pixel = 32; + + write32BitBmp(pamP, tuples, getPixel, haveAlpha, alphaPlane, + ofP, &bmpSize); + } else if (paletteP->tooManyColors) { + /* Do a truecolor image */ + dirEntryP->color_count = 0; + dirEntryP->bits_per_pixel = 32; + + write32BitBmp(pamP, tuples, getPixel, false /*haveAlpha*/, 0, + ofP, &bmpSize); + } else { + /* Do a paletted image */ + + if (paletteP->colorCt <= 2) { + dirEntryP->color_count = paletteP->colorCt; + dirEntryP->bits_per_pixel = 1; + + writePaletteBmp(1, pamP, tuples, getPixel, paletteP, + ofP, &bmpSize); + } else if (paletteP->colorCt <= 16) { + dirEntryP->color_count = paletteP->colorCt; + dirEntryP->bits_per_pixel = 4; + + writePaletteBmp(4, pamP, tuples, getPixel,paletteP, + ofP, &bmpSize); + } else { + dirEntryP->color_count = 0; + dirEntryP->bits_per_pixel = 8; + + writePaletteBmp(8, pamP, tuples, getPixel, paletteP, + ofP, &bmpSize); + } + } + writeAndMask(pamP, tuples, haveAlpha, alphaPlane, haveAnd, andPlane, + ofP, &andMaskSize); + + dirEntryP->size = bmpSize + andMaskSize; + } +} + + + +static void +convertOneImage(unsigned int const imageNum, + FILE * const ifP, + unsigned int const pngThreshold, + bool const mustBlackenXor, + FILE * const ofP, + struct IconDir * const dirP) { + + struct IconDirEntry dirEntry; + struct pam pam; + tuple ** tuples; + bool haveAlpha; + unsigned int alphaPlane; + bool haveAnd; + unsigned int andPlane; + GetPixelFn * getPixel; + struct Palette palette; + bool doingPng; + + /* Output: + * + * threshold^2 pixels or more: + * no alpha channel: PNG (RGB) + * alpha channel: PNG (RGBA) + * alpha channel +AND mask: PNG (RGBA), AND mask dropped + * alpha values other than 0 and maxval: 32bit +alpha BMP + * no more than 2 colors: 1bit or 32bit BMP + * no more than 16 colors: 4bit or 32bit BMP + * no more than 256 colors: 8bit or 32bit BMP + * more than 256 colors: 32bit BMP + */ + pnm_readpaminit(ifP, &pam, PAM_STRUCT_SIZE(tuple_type)); + + if (pam.width > 256 || pam.height > 256) + pm_error("Image %u: too large as a windows icon (%u x %u). " + "Maximum allowed dimension is 256", + imageNum, pam.width, pam.height); + + tuples = pnm_allocpamarray(&pam); + + doingPng = pam.width * pam.height >= pngThreshold; + + readAndScalePam(&pam, doingPng, tuples); + + determineImageType(&pam, tuples, &getPixel, + &haveAlpha, &alphaPlane, &haveAnd, &andPlane); + + getPalette(&pam, tuples, getPixel, &palette); + + if (verbose) + reportImageInfo(imageNum, &pam, &palette, haveAlpha, haveAnd); + + writeIconAndCreateDirEntry(&pam, tuples, getPixel, doingPng, + haveAlpha, alphaPlane, + haveAnd, andPlane, + mustBlackenXor, + &palette, + ofP, &dirEntry); + + if (verbose) + pm_message("Image %2u: %u bytes", imageNum, dirEntry.size); + + pnm_freepamarray(tuples, &pam); + + addToDirectory(&dirEntry, dirP); +} + + + +static void +convert(FILE * const ifP, + unsigned int const pngThreshold, + bool const mustBlackenXor, + struct IconDir * const dirP, + FILE * const ofP) { +/*---------------------------------------------------------------------------- + Read a (multi-image) PAM file from *ifP and convert the individual images + to the proper format for a Windows icon file and write those to *ofP. + + Where the number of pixels in an image is at least 'pngThreshold', use + a PNG image. Otherwise, use a BMP. +-----------------------------------------------------------------------------*/ + unsigned int imageNum; + int eof; + + for (imageNum = 0, eof = false; !eof; ++imageNum) { + convertOneImage(imageNum, ifP, pngThreshold, mustBlackenXor, + ofP, dirP); + + pnm_nextimage(ifP, &eof); + } +} + + + +static void +writeIconDirEntry(const struct IconDirEntry * const dirEntryP, + FILE * const ofP) { + + pm_writecharu (ofP, dirEntryP->width); + pm_writecharu (ofP, dirEntryP->height); + pm_writecharu (ofP, dirEntryP->color_count); + pm_writecharu (ofP, dirEntryP->zero); + pm_writelittleshortu (ofP, dirEntryP->color_planes); + pm_writelittleshortu (ofP, dirEntryP->bits_per_pixel); + pm_writelittlelongu (ofP, dirEntryP->size); + pm_writelittlelongu (ofP, dirEntryP->offset); +} + + + +static void +writeIconDirectory(const struct IconDir * const dirP, + FILE * const ofP) { +/*---------------------------------------------------------------------------- + Write to file *ofP the icon directory described by *dirP. + + *dirP's image offset members are meaningless as input. We fill them in. +-----------------------------------------------------------------------------*/ + uint32_t const hsize = 6 + dirP->count * 16; + + unsigned int imageNum; + unsigned int imageOffset; + + pm_writelittleshortu(ofP, dirP->zero); + pm_writelittleshortu(ofP, dirP->type); + pm_writelittleshortu(ofP, dirP->count); + + for (imageNum = 0, imageOffset = hsize; + imageNum < dirP->count; + ++imageNum) { + + struct IconDirEntry * const dirEntryP = &dirP->entries[imageNum]; + + pm_message("image %2u: %3u x %3u x %2u", + imageNum, + dirEntryP->width, + dirEntryP->height, + dirEntryP->bits_per_pixel); + + dirEntryP->offset = imageOffset; + + writeIconDirEntry(dirEntryP, ofP); + + imageOffset += dirEntryP->size; + } +} + + + +static void +copyFile(FILE * const ifP, + FILE * const ofP) { + + bool eof; + + for (eof = false; !eof; ) { + unsigned char buffer[1024]; + size_t bytesRead; + + bytesRead = fread(buffer, 1, sizeof(buffer), ifP); + + if (bytesRead == 0) + eof = true; + else { + size_t bytesWritten; + + bytesWritten = fwrite(buffer, 1, bytesRead, ofP); + + if (bytesWritten < bytesRead) + pm_error("Error writing to output file."); + } + } +} + + + +static void +writeIconFile(const struct IconDir * const dirP, + FILE * const imagesFileP, + FILE * const ofP) { +/*---------------------------------------------------------------------------- + Write a windows icon file. + + *dirP is the icon directory to put in it. + + *imagesFileP contains all the text of the icon images. The contents of + this file go verbatim into the output. +-----------------------------------------------------------------------------*/ + writeIconDirectory(dirP, ofP); + + copyFile(imagesFileP, ofP); +} + + + +int +main(int argc, const char *argv []) { + + struct CmdlineInfo cmdline; + FILE * ifP; + FILE * imagesFileP; + /* This is the file in which we collect the individual icon + images to be copied later to the output. + */ + struct IconDir * dirP; + + pm_proginit(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + verbose = cmdline.verbose; + + /* The output icon file has directory information at the top that we + can't know until we have looked at the input images. So as we pass + through the input, we collect the directory information and generate + the individual icon images and store them in *imageFileP. When we've + been through all of the input, we write out the directory and then + copy the images from *imageFileP to the output. + */ + + dirP = newIconDir(); + + imagesFileP = pm_tmpfile(); + + ifP = pm_openr(cmdline.inputFileName); + + convert(ifP, SQR(cmdline.pngthreshold), cmdline.truetransparent, + dirP, imagesFileP); + + rewind(imagesFileP); + + writeIconFile(dirP, imagesFileP, stdout); + + freeIconDir(dirP); + + return 0; +} + + + diff --git a/converter/other/pamtoxvmini.c b/converter/other/pamtoxvmini.c index e1aa9b52..b57bcc74 100644 --- a/converter/other/pamtoxvmini.c +++ b/converter/other/pamtoxvmini.c @@ -152,14 +152,14 @@ getPaletteIndexThroughCache(struct pam * const pamP, If the tuple-index association is in *paletteIndexP, use it. If not, find it the hard way and add it to *palettedIndexP for the next guy. -----------------------------------------------------------------------------*/ - bool found; + int found; int paletteIndex; pnm_lookuptuple(pamP, paletteHash, tuple, &found, &paletteIndex); if (found) *paletteIndexP = paletteIndex; else { - bool fits; + int fits; findClosestColor(pamP, tuple, xvPaletteP, paletteIndexP); pnm_addtotuplehash(pamP, paletteHash, tuple, *paletteIndexP, &fits); diff --git a/converter/other/pdbimgtopam.c b/converter/other/pdbimgtopam.c new file mode 100644 index 00000000..3cb4129a --- /dev/null +++ b/converter/other/pdbimgtopam.c @@ -0,0 +1,774 @@ +/*============================================================================= + pamtopdbimg +=============================================================================== + + Convert Palm Pilot PDB Image format (for viewing by + Pilot Image Viewer) to Netpbm image. + + Bryan Henderson derived this from Eric Howe's program named + 'imgvtopnm', in September 2010. +=============================================================================*/ +/* + * Copyright (C) 1997 Eric A. Howe + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors: Eric A. Howe (mu@trends.net) + * Bryan Henderson + */ +#include +#include + +#include "pm_c_util.h" +#include "mallocvar.h" +#include "nstring.h" +#include "shhopt.h" +#include "pam.h" + +#include "ipdb.h" + + +struct cmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + const char * inputFileName; /* '-' if stdin */ + const char * notefile; /* NULL if not specified */ + unsigned int verbose; +}; + + + +static void +parseCommandLine(int argc, const char ** argv, + struct cmdlineInfo * const cmdlineP) { +/*---------------------------------------------------------------------------- + parse program command line described in Unix standard form by argc + and argv. Return the information in the options as *cmdlineP. + + If command line is internally inconsistent (invalid options, etc.), + issue error message to stderr and abort program. + + Note that the strings we return are stored in the storage that + was passed to us as the argv array. We also trash *argv. +-----------------------------------------------------------------------------*/ + optEntry *option_def; + /* Instructions to pm_optParseOptions3 on how to parse our options. + */ + optStruct3 opt; + + unsigned int option_def_index; + + unsigned int notefileSpec; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENT3 */ + OPTENT3(0, "notefile", OPT_STRING, &cmdlineP->notefile, + ¬efileSpec, 0); + OPTENT3(0, "verbose", OPT_FLAG, NULL, + &cmdlineP->verbose, 0); + + opt.opt_table = option_def; + opt.short_allowed = false; /* We have no short (old-fashioned) options */ + opt.allowNegNum = false; /* We have no parms that are negative numbers */ + + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + if (!notefileSpec) + cmdlineP->notefile = NULL; + + if (argc-1 < 1) + cmdlineP->inputFileName = "-"; + else if (argc-1 == 1) + cmdlineP->inputFileName = argv[1]; + else + pm_error("Program takes at most one argument: input file name"); +} + + + +#define getg16pixel(b,o) (((b) >> (4 - 4*(o))) & 0x0f) +#define getgpixel(b,o) (((b) >> (6 - 2*(o))) & 0x03) +#define getmpixel(b,o) (((b) >> (7 - (o))) & 0x01) + + +static void +abortShort() { + pm_error("Invalid image. Compression algorithm runs out of " + "compressed data before generating the expected " + "amount of image data"); +} + + + +static void +abortOverrun() { + pm_error("Invalid image. Compression algorithm finds the end of " + "the image in the middle of a run"); +} + + + +static void +decompress(const uint8_t * const compressed, + size_t const compressedSize, + size_t const imageSize, + uint8_t ** const uncompressedP) { +/*---------------------------------------------------------------------------- + Decompress the data 'compressed', which is 'compressedSize' bytes long. + Return the decompressed data in newly malloced storage as + *decompressedP. Decompression should yield exactly 'imageSize' bytes. +-----------------------------------------------------------------------------*/ + /* + * The compression scheme used is a simple RLE; the control codes, + * CODE, are one byte and have the following meanings: + * + * CODE > 0x80 Insert (CODE + 1 - 0x80) copies of the next byte. + * CODE <= 0x80 Insert the next (CODE + 1) literal bytes. + * + * Compressed pieces can (and do) cross row boundaries. + */ + uint8_t * uncompressed; + + MALLOCARRAY(uncompressed, imageSize); + + if (uncompressed) { + const uint8_t * inP; + uint8_t * outP; + size_t bytesLeft; + + for (bytesLeft = imageSize, + inP = &compressed[0], outP = &uncompressed[0]; + bytesLeft > 0; + ) { + + int got, put; + + if (inP > compressed + compressedSize) + abortShort(); + + if (*inP > 0x80) { + put = *inP++ + 1 - 0x80; + if (outP + put > uncompressed + imageSize) + abortOverrun(); + memset(outP, *inP, put); + got = 1; + } else { + put = *inP++ + 1; + if (inP + put > compressed + compressedSize) + abortShort(); + if (outP + put > uncompressed + imageSize) + abortOverrun(); + memcpy(outP, inP, put); + got = put; + } + inP += got; + outP += put; + assert(bytesLeft >= put); + bytesLeft -= put; + } + } + *uncompressedP = uncompressed; +} + + + +#define UNKNOWN_OFFSET (uint32_t)-1 + +static void +readCompressed(IMAGE * const imgP, + uint32_t const end_offset, + FILE * const fP, + size_t * const dataSizeP, + uint8_t ** const dataP, + int * const retvalP) { +/*---------------------------------------------------------------------------- + Read the compressed data from file *fP (actually, if the image isn't + compressed, then it's just the regular data). + + Return the data in newly malloced storage as *dataP, which is + *dataSizeP bytes long. +-----------------------------------------------------------------------------*/ + int retval; + uint8_t * buffer; + size_t dataSize; + + dataSize = 0; /* initial value */ + + if (end_offset == UNKNOWN_OFFSET) { + /* + * Read until EOF. Some of them have an extra zero byte + * dangling off the end. I originally thought this was + * an empty note record (even though there was no record + * header for it); however, the release notes for Image + * Compression Manager 1.1 on http://www.pilotgear.com + * note this extra byte as a bug in Image Compression + * Manager 1.0 which 1.1 fixes. We'll just blindly read + * this extra byte and ignore it by paying attention to + * the image dimensions. + */ + MALLOCARRAY(buffer, ipdb_img_size(imgP)); + + if (buffer == NULL) + retval = ENOMEM; + else { + dataSize = fread(buffer, 1, ipdb_img_size(imgP), fP); + if (dataSize <= 0) + retval = EIO; + else + retval = 0; + + if (retval != 0) + free(buffer); + } + } else { + /* + * Read to the indicated offset. + */ + dataSize = end_offset - ftell(fP) + 1; + + MALLOCARRAY(buffer, dataSize); + + if (buffer == NULL) + retval = ENOMEM; + else { + ssize_t rc; + rc = fread(buffer, 1, dataSize, fP); + if (rc != dataSize) + retval = EIO; + else + retval = 0; + + if (retval != 0) + free(buffer); + } + } + *dataSizeP = dataSize; + *dataP = buffer; + *retvalP = retval; +} + + + +static void +imageReadHeader(FILE * const fileP, + IMAGE * const imgP, + bool const dump) { + + fread(&imgP->name, 1, 32, fileP); + pm_readcharu(fileP, &imgP->version); + pm_readcharu(fileP, &imgP->type); + fread(&imgP->reserved1, 1, 4, fileP); + fread(&imgP->note, 1, 4, fileP); + pm_readbigshortu(fileP, &imgP->x_last); + pm_readbigshortu(fileP, &imgP->y_last); + fread(&imgP->reserved2, 1, 4, fileP); + pm_readbigshortu(fileP, &imgP->x_anchor); + pm_readbigshortu(fileP, &imgP->y_anchor); + pm_readbigshortu(fileP, &imgP->width); + pm_readbigshortu(fileP, &imgP->height); + + if (dump) { + pm_message("PDB IMAGE header:"); + pm_message(" Name: '%.*s'", (int)sizeof(imgP->name), imgP->name); + pm_message(" Version: %02x", imgP->version); + pm_message(" Type: %s", ipdb_typeName(imgP->type)); + pm_message(" Note: %02x %02x %02x %02x", + imgP->note[0], imgP->note[1], imgP->note[2], imgP->note[3]); + pm_message(" X_last: %u", imgP->x_last); + pm_message(" Y_last: %u", imgP->y_last); + pm_message(" X_anchor: %u", imgP->x_anchor); + pm_message(" Y_anchor: %u", imgP->y_anchor); + pm_message(" Width: %u", imgP->width); + pm_message(" Height: %u", imgP->height); + pm_message("Pixels per byte: %u", ipdb_img_ppb(imgP)); + pm_message("Image size: %lu bytes", + (unsigned long)ipdb_img_size(imgP)); + } +} + + +static int +imageReadData(FILE * const fileP, + IMAGE * const imgP, + uint32_t const end_offset) { + + int retval; + size_t dataSize; + uint8_t * buffer; + + readCompressed(imgP, end_offset, fileP, &dataSize, &buffer, &retval); + + if (retval == 0) { + /* + * Compressed data can cross row boundaries so we decompress + * the data here to avoid messiness in the row access functions. + */ + if (dataSize != ipdb_img_size(imgP)) { + decompress(buffer, dataSize, ipdb_img_size(imgP), &imgP->data); + if (imgP->data == NULL) + retval = ENOMEM; + else + imgP->compressed = true; + free(buffer); + } else { + imgP->compressed = false; + imgP->data = buffer; + /* Storage at 'buffer' now belongs to *imgP */ + } + } + return retval; +} + + + +static int +imageRead(IMAGE * const imgP, + uint32_t const end_offset, + FILE * const fileP, + bool const verbose) { + + if (imgP) { + imgP->r->offset = (uint32_t)ftell(fileP); + + imageReadHeader(fileP, imgP, verbose); + + imageReadData(fileP, imgP, end_offset); + } + return 0; +} + + + +static int +textRead(TEXT * const textP, + FILE * const fileP) { + + int retval; + char * s; + char buf[128]; + int used, alloced, len; + + if (textP == NULL) + return 0; + + textP->r->offset = (uint32_t)ftell(fileP); + + /* + * What a pain in the ass! Why the hell isn't there a length + * attached to the text record? I suppose the designer wasn't + * concerned about non-seekable (i.e. pipes) input streams. + * Perhaps I'm being a little harsh, the lack of a length probably + * isn't much of an issue on the Pilot. + */ + used = 0; + alloced = 0; + s = NULL; + retval = 0; /* initial value */ + while ((len = fread(buf, 1, sizeof(buf), fileP)) != 0 && retval == 0) { + if (buf[len - 1] == '\0') + --len; + if (used + len > alloced) { + alloced += 2 * sizeof(buf); + REALLOCARRAY(s, alloced); + + if (s == NULL) + retval = ENOMEM; + } + if (retval == 0) { + memcpy(s + used, buf, len); + used += len; + } + } + if (retval == 0) { + textP->data = calloc(1, used + 1); + if (textP->data == NULL) + retval = ENOMEM; + else + memcpy(textP->data, s, used); + } + if (s) + free(s); + + return retval; +} + + + +static int +pdbheadRead(PDBHEAD * const pdbHeadP, + FILE * const fileP) { + + int retval; + + fread(pdbHeadP->name, 1, 32, fileP); + pm_readbigshortu(fileP, &pdbHeadP->flags); + pm_readbigshortu(fileP, &pdbHeadP->version); + pm_readbiglongu2(fileP, &pdbHeadP->ctime); + pm_readbiglongu2(fileP, &pdbHeadP->mtime); + pm_readbiglongu2(fileP, &pdbHeadP->btime); + pm_readbiglongu2(fileP, &pdbHeadP->mod_num); + pm_readbiglongu2(fileP, &pdbHeadP->app_info); + pm_readbiglongu2(fileP, &pdbHeadP->sort_info); + fread(pdbHeadP->type, 1, 4, fileP); + fread(pdbHeadP->id, 1, 4, fileP); + pm_readbiglongu2(fileP, &pdbHeadP->uniq_seed); + pm_readbiglongu2(fileP, &pdbHeadP->next_rec); + pm_readbigshortu(fileP, &pdbHeadP->num_recs); + + if (!memeq(pdbHeadP->type, IPDB_vIMG, 4) + || !memeq(pdbHeadP->id, IPDB_View, 4)) + retval = E_NOTIMAGE; + else + retval = 0; + + return retval; +} + + + +static int +rechdrRead(RECHDR * const rechdrP, + FILE * const fileP) { + + int retval; + off_t len; + + pm_readbiglongu2(fileP, &rechdrP->offset); + + len = (off_t)rechdrP->offset - ftell(fileP); + switch(len) { + case 4: + case 12: + /* + * Version zero (eight bytes of record header) or version + * two with a note (two chunks of eight record header bytes). + */ + fread(&rechdrP->unknown[0], 1, 3, fileP); + fread(&rechdrP->rec_type, 1, 1, fileP); + rechdrP->n_extra = 0; + rechdrP->extra = NULL; + retval = 0; + break; + case 6: + /* + * Version one (ten bytes of record header). + */ + fread(&rechdrP->unknown[0], 1, 3, fileP); + fread(&rechdrP->rec_type, 1, 1, fileP); + rechdrP->n_extra = 2; + MALLOCARRAY(rechdrP->extra, rechdrP->n_extra); + if (rechdrP->extra == NULL) + retval = ENOMEM; + else { + fread(rechdrP->extra, 1, rechdrP->n_extra, fileP); + retval = 0; + } + break; + default: + /* + * hmmm.... I'll assume this is the record header + * for a text record. + */ + fread(&rechdrP->unknown[0], 1, 3, fileP); + fread(&rechdrP->rec_type, 1, 1, fileP); + rechdrP->n_extra = 0; + rechdrP->extra = NULL; + retval = 0; + break; + } + if (retval == 0) { + if ((rechdrP->rec_type != IMG_REC && rechdrP->rec_type != TEXT_REC) + || !memeq(rechdrP->unknown, IPDB_MYST, 3)) + retval = E_NOTRECHDR; + } + return retval; +} + + + +static int +ipdbRead(IPDB * const pdbP, + FILE * const fileP, + bool const verbose) { + + int retval; + + ipdb_clear(pdbP); + + pdbP->p = ipdb_pdbhead_alloc(NULL); + + if (pdbP->p == NULL) + retval = ENOMEM; + else { + int status; + + status = pdbheadRead(pdbP->p, fileP); + + if (status != 0) + retval = status; + else { + pdbP->i = ipdb_image_alloc(pdbP->p->name, IMG_GRAY, 0, 0); + if (pdbP->i == NULL) + retval = ENOMEM; + else { + int status; + status = rechdrRead(pdbP->i->r, fileP); + if (status != 0) + retval = status; + else { + if (pdbP->p->num_recs > 1) { + pdbP->t = ipdb_text_alloc(NULL); + if (pdbP->t == NULL) + retval = ENOMEM; + else { + int status; + status = rechdrRead(pdbP->t->r, fileP); + if (status != 0) + retval = status; + else + retval = 0; + } + } else + retval = 0; + + if (retval == 0) { + uint32_t const offset = + pdbP->t == NULL ? + UNKNOWN_OFFSET : pdbP->t->r->offset - 1; + + int status; + + status = imageRead(pdbP->i, offset, fileP, verbose); + if (status != 0) + retval = status; + else { + if (pdbP->t != NULL) { + int status; + + status = textRead(pdbP->t, fileP); + if (status != 0) + retval = status; + } + } + } + } + } + } + } + return retval; +} + + + +static void +g16unpack(const uint8_t * const p, + uint8_t * const g, + int const w) { + + static const uint8_t pal[] = + {0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, + 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00}; + const uint8_t * seg; + unsigned int i; + + for (i = 0, seg = p; i < w; i += 2, ++seg) { + g[i + 0] = pal[getg16pixel(*seg, 0)]; + g[i + 1] = pal[getg16pixel(*seg, 1)]; + } +} + + + +static void +gunpack(const uint8_t * const p, + uint8_t * const g, + int const w) { + + static const uint8_t pal[] = {0xff, 0xaa, 0x55, 0x00}; + const uint8_t * seg; + unsigned int i; + + for (i = 0, seg = p; i < w; i += 4, ++seg) { + g[i + 0] = pal[getgpixel(*seg, 0)]; + g[i + 1] = pal[getgpixel(*seg, 1)]; + g[i + 2] = pal[getgpixel(*seg, 2)]; + g[i + 3] = pal[getgpixel(*seg, 3)]; + } +} + + + +static void +munpack(const uint8_t * const p, + uint8_t * const b, + int const w) { + + static const uint8_t pal[] = {PAM_BW_WHITE, PAM_BLACK}; + const uint8_t * seg; + unsigned int i; + + for (i = 0, seg = p; i < w; i += 8, ++seg) { + b[i + 0] = pal[getmpixel(*seg, 0)]; + b[i + 1] = pal[getmpixel(*seg, 1)]; + b[i + 2] = pal[getmpixel(*seg, 2)]; + b[i + 3] = pal[getmpixel(*seg, 3)]; + b[i + 4] = pal[getmpixel(*seg, 4)]; + b[i + 5] = pal[getmpixel(*seg, 5)]; + b[i + 6] = pal[getmpixel(*seg, 6)]; + b[i + 7] = pal[getmpixel(*seg, 7)]; + } +} + + + +static void +g16row(IPDB * const pdbP, + unsigned int const row, + uint8_t * const buffer) { + + g16unpack(ipdb_img_row(pdbP->i, row), buffer, ipdb_width(pdbP)); +} + + + +static void +grow(IPDB * const pdbP, + unsigned int const row, + uint8_t * const buffer) { + + gunpack(ipdb_img_row(pdbP->i, row), buffer, ipdb_width(pdbP)); +} + + + +static void +mrow(IPDB * const pdbP, + unsigned int const row, + uint8_t * const buffer) { + + munpack(ipdb_img_row(pdbP->i, row), buffer, ipdb_width(pdbP)); +} + + + +static void +writeImgPam(IPDB * const pdbP, + FILE * const ofP) { + + struct pam pam; + tuple * tupleRow; + unsigned int row; + uint8_t * imgRow; + + MALLOCARRAY(imgRow, ipdb_width(pdbP)); + + pam.size = sizeof(pam); + pam.len = PAM_STRUCT_SIZE(tuple_type); + pam.file = ofP; + pam.plainformat = 0; + pam.width = ipdb_width(pdbP); + pam.height = ipdb_height(pdbP); + pam.depth = 1; + pam.maxval = ipdb_type(pdbP) == IMG_MONO ? 1 : 255; + pam.bytes_per_sample = pnm_bytespersample(pam.maxval); + pam.format = PAM_FORMAT; + strcpy(pam.tuple_type, + ipdb_type(pdbP) == IMG_MONO ? + PAM_PBM_TUPLETYPE : PAM_PGM_TUPLETYPE); + + pnm_writepaminit(&pam); + + tupleRow = pnm_allocpamrow(&pam); + + for (row = 0; row < pam.height; ++row) { + unsigned int col; + + + if (ipdb_type(pdbP) == IMG_MONO) + mrow(pdbP, row, imgRow); + else if (ipdb_type(pdbP) == IMG_GRAY) + grow(pdbP, row, imgRow); + else + g16row(pdbP, row, imgRow); + + for (col = 0; col < pam.width; ++col) + tupleRow[col][0] = imgRow[col]; + + pnm_writepamrow(&pam, tupleRow); + } + pnm_freepamrow(tupleRow); + + free(imgRow); +} + + + +static void +writeText(IPDB * const pdbP, + const char * const name) { + + const char * const note = ipdb_text(pdbP); + + FILE * fP; + + if (name == NULL || note == NULL) { + } else { + fP = pm_openw(name); + if (fP == NULL) + pm_error("Could not open note file '%s' for output", name); + + fprintf(fP, "%s\n", note); + + pm_close(fP); + } +} + + + +int +main(int argc, const char ** argv) { + + struct cmdlineInfo cmdline; + FILE * ifP; + IPDB * pdbP; + int status; + + pm_proginit(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + ifP = pm_openr(cmdline.inputFileName); + + pdbP = ipdb_alloc(NULL); + if (pdbP == NULL) + pm_error("Could not allocate IPDB structure."); + + status = ipdbRead(pdbP, ifP, cmdline.verbose); + if (status != 0) + pm_error("Image header read error: %s.", ipdb_err(status)); + + writeImgPam(pdbP, stdout); + + writeText(pdbP, cmdline.notefile); + + ipdb_free(pdbP); + + pm_close(ifP); + + return EXIT_SUCCESS; +} diff --git a/converter/other/pfmtopam.c b/converter/other/pfmtopam.c index 1617ed31..080ec7ff 100644 --- a/converter/other/pfmtopam.c +++ b/converter/other/pfmtopam.c @@ -45,7 +45,7 @@ parseCommandLine(int argc, was passed to us as the argv array. We also trash *argv. --------------------------------------------------------------------------*/ optEntry *option_def = malloc( 100*sizeof( optEntry ) ); - /* Instructions to optParseOptions3 on how to parse our options. */ + /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; unsigned int option_def_index; @@ -59,7 +59,7 @@ parseCommandLine(int argc, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3( &argc, argv, opt, sizeof(opt), 0 ); + pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0 ); /* Uses and sets argc, argv, and some of *cmdline_p and others. */ if (!maxvalSpec) diff --git a/converter/other/pgmtopbm.c b/converter/other/pgmtopbm.c index f828b716..67cac468 100644 --- a/converter/other/pgmtopbm.c +++ b/converter/other/pgmtopbm.c @@ -44,7 +44,7 @@ parseCommandLine(int argc, char ** argv, was passed to us as the argv array. -----------------------------------------------------------------------------*/ optEntry *option_def; - /* Instructions to optParseOptions3 on how to parse our options. + /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; @@ -77,7 +77,7 @@ parseCommandLine(int argc, char ** argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We may have parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (floydOpt + thresholdOpt + hilbertOpt + dither8Opt + @@ -585,6 +585,7 @@ createDither8Converter(unsigned int const cols, converter.convertRow = &dither8ConvertRow; converter.destroy = dither8Destroy; converter.stateP = stateP; + converter.maxval = maxval; /* Scale dither matrix. */ for (row = 0; row < 16; ++row) { @@ -660,6 +661,7 @@ createClusterConverter(unsigned int const radius, unsigned int row; converter.cols = cols; + converter.maxval = maxval; converter.convertRow = &clusterConvertRow; converter.destroy = &clusterDestroy; diff --git a/converter/other/pgmtoppm.c b/converter/other/pgmtoppm.c index 7194db49..f8a69424 100644 --- a/converter/other/pgmtoppm.c +++ b/converter/other/pgmtoppm.c @@ -10,6 +10,7 @@ ** implied warranty. */ +#define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */ #define _BSD_SOURCE /* Make sure strdup() is in */ #include @@ -44,7 +45,7 @@ parseCommandLine(int argc, char ** argv, was passed to us as the argv array. We also trash *argv. -----------------------------------------------------------------------------*/ optEntry *option_def; - /* Instructions to optParseOptions3 on how to parse our options. + /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; @@ -62,7 +63,7 @@ parseCommandLine(int argc, char ** argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (!mapSpec) diff --git a/converter/other/pngtopam.c b/converter/other/pngtopam.c index 89ac100a..59b29f5f 100644 --- a/converter/other/pngtopam.c +++ b/converter/other/pngtopam.c @@ -21,65 +21,52 @@ #include #include #include -#include /* includes zlib.h and setjmp.h */ -#define VERSION "2.37.4 (5 December 1999) +netpbm" +#include +/* Becaues of a design error in png.h, you must not #include before + . If you do, png.h won't compile. +*/ +#include +#include + #include "pm_c_util.h" #include "mallocvar.h" #include "nstring.h" #include "shhopt.h" #include "pam.h" +#include "pngx.h" -/* A hack until we can remove direct access to png_info from the program */ -#if PNG_LIBPNG_VER >= 10400 -#define trans_values trans_color -#define TRANS_ALPHA trans_alpha -#else -#define TRANS_ALPHA trans -#endif - -typedef struct _jmpbuf_wrapper { - jmp_buf jmpbuf; -} jmpbuf_wrapper; +enum AlphaHandling {ALPHA_NONE, ALPHA_ONLY, ALPHA_MIX, ALPHA_IN}; -enum alpha_handling {ALPHA_NONE, ALPHA_ONLY, ALPHA_MIX, ALPHA_IN}; +typedef struct { + bool needCorrection; + double gamma; +} GammaCorrection; -struct cmdlineInfo { +struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ - const char *inputFilespec; /* '-' if stdin */ + const char * inputFileName; /* '-' if stdin */ unsigned int verbose; - enum alpha_handling alpha; + enum AlphaHandling alpha; const char * background; - float gamma; /* -1.0 means unspecified */ + unsigned int gammaSpec; + float gamma; const char * text; unsigned int time; + unsigned int byrow; }; -typedef struct { -/*---------------------------------------------------------------------------- - A color in a format compatible with the PNG library. - - Note that the PNG library declares types png_color and png_color_16 - which are similar. ------------------------------------------------------------------------------*/ - png_uint_16 r; - png_uint_16 g; - png_uint_16 b; -} pngcolor; - - -static png_uint_16 maxval; static bool verbose; -static jmpbuf_wrapper pngtopnm_jmpbuf_struct; + static void parseCommandLine(int argc, const char ** argv, - struct cmdlineInfo * cmdlineP ) { + struct CmdlineInfo * cmdlineP ) { /*---------------------------------------------------------------------------- Parse program command line described in Unix standard form by argc and argv. Return the information in the options as *cmdlineP. @@ -91,14 +78,14 @@ parseCommandLine(int argc, was passed to us as the argv array. We also trash *argv. -----------------------------------------------------------------------------*/ optEntry * option_def; - /* Instructions to optParseOptions3 on how to parse our options. + /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; unsigned int option_def_index; unsigned int alphaSpec, alphapamSpec, mixSpec, - backgroundSpec, gammaSpec, textSpec; + backgroundSpec, textSpec; MALLOCARRAY(option_def, 100); @@ -114,17 +101,19 @@ parseCommandLine(int argc, OPTENT3(0, "background", OPT_STRING, &cmdlineP->background, &backgroundSpec, 0); OPTENT3(0, "gamma", OPT_FLOAT, &cmdlineP->gamma, - &gammaSpec, 0); + &cmdlineP->gammaSpec, 0); OPTENT3(0, "text", OPT_STRING, &cmdlineP->text, &textSpec, 0); OPTENT3(0, "time", OPT_FLAG, NULL, &cmdlineP->time, 0); + OPTENT3(0, "byrow", OPT_FLAG, NULL, + &cmdlineP->byrow, 0); opt.opt_table = option_def; opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ @@ -145,16 +134,13 @@ parseCommandLine(int argc, if (!backgroundSpec) cmdlineP->background = NULL; - if (!gammaSpec) - cmdlineP->gamma = -1.0; - if (!textSpec) cmdlineP->text = NULL; if (argc-1 < 1) - cmdlineP->inputFilespec = "-"; + cmdlineP->inputFileName = "-"; else if (argc-1 == 1) - cmdlineP->inputFilespec = argv[1]; + cmdlineP->inputFileName = argv[1]; else pm_error("Program takes at most one argument: input file name. " "you specified %d", argc-1); @@ -162,18 +148,299 @@ parseCommandLine(int argc, +typedef struct { +/*---------------------------------------------------------------------------- + A color in a format compatible with the PNG library. + + Note that the PNG library declares types png_color and png_color_16 + which are similar. +-----------------------------------------------------------------------------*/ + png_uint_16 r; + png_uint_16 g; + png_uint_16 b; +} pngcolor; + + + +static pngcolor +pngcolorFrom16(png_color_16 const arg) { + + pngcolor retval; + + retval.r = arg.red; + retval.g = arg.green; + retval.b = arg.blue; + + return retval; +} + + + +static pngcolor +pngcolorFromByte(png_color const arg) { + + pngcolor retval; + + retval.r = arg.red; + retval.g = arg.green; + retval.b = arg.blue; + + return retval; +} + + + +static bool +pngColorEqual(pngcolor const comparand, + pngcolor const comparator) { + + return (comparand.r == comparator.r + && comparand.g == comparator.g + && comparand.b == comparator.b); +} + + + +static png_uint_16 +gammaCorrect(png_uint_16 const uncorrected, + GammaCorrection const gamma, + png_uint_16 const maxval) { + + if (gamma.needCorrection) { + double const uncorrectedN = (double) uncorrected / maxval; + return (png_uint_16) + ROUNDU(pow(uncorrectedN, (1.0 / gamma.gamma)) * maxval); + } else + return uncorrected; +} + + + +static pngcolor +gammaCorrectColor(pngcolor const color, + GammaCorrection const gamma, + png_uint_16 const maxval) { + + pngcolor retval; + + retval.r = gammaCorrect(color.r, gamma, maxval); + + return retval; +} + + + +static unsigned int +computePngLineSize(struct pngx * const pngxP) { + + unsigned int const bytesPerSample = + pngx_bitDepth(pngxP) == 16 ? 2 : 1; + + unsigned int samplesPerPixel; + + switch (pngx_colorType(pngxP)) { + case PNG_COLOR_TYPE_GRAY_ALPHA: samplesPerPixel = 2; break; + case PNG_COLOR_TYPE_RGB: samplesPerPixel = 3; break; + case PNG_COLOR_TYPE_RGB_ALPHA: samplesPerPixel = 4; break; + default: samplesPerPixel = 1; + } + + if (UINT_MAX / bytesPerSample / samplesPerPixel < pngx_imageWidth(pngxP)) + pm_error("Width %u of PNG is uncomputably large", + pngx_imageWidth(pngxP)); + + return pngx_imageWidth(pngxP) * bytesPerSample * samplesPerPixel; +} + + + +static void +allocPngRaster(struct pngx * const pngxP, + png_byte *** const pngImageP) { + + unsigned int const lineSize = computePngLineSize(pngxP); + + png_byte ** pngImage; + unsigned int row; + + MALLOCARRAY(pngImage, pngx_imageHeight(pngxP)); + + if (pngImage == NULL) + pm_error("couldn't allocate index space for %u PNG raster rows. " + "Try -byrow, which needs only 1 row of buffer space. ", + pngx_imageHeight(pngxP)); + + for (row = 0; row < pngx_imageHeight(pngxP); ++row) { + MALLOCARRAY(pngImage[row], lineSize); + if (pngImage[row] == NULL) + pm_error("couldn't allocate space for %uth row of PNG raster. " + "Try -byrow, which needs only 1 row of buffer space. ", + row); + } + *pngImageP = pngImage; +} + + + +static void +freePngRaster(png_byte ** const pngRaster, + struct pngx * const pngxP) { + + unsigned int row; + + for (row = 0; row < pngx_imageHeight(pngxP); ++row) + free(pngRaster[row]); + + free(pngRaster); +} + + + +typedef struct { +/*---------------------------------------------------------------------------- + This is an object for reading the raster of the PNG, a row at a time. +-----------------------------------------------------------------------------*/ + struct pngx * pngxP; + png_byte ** pngRaster; + /* The entire raster of the PNG. Null if this is a + row-at-a-time object. Constant. + + We give a pointer into this to the user. + */ + png_byte * rowBuf; + /* The buffer in which we put the most recently read row. + Null if this is an all-at-once object. Constant. + + We give a pointer into this to the user. + */ + unsigned int nextRowNum; + /* The number of the next row to be read from this object. */ + +} Reader; + + + +static Reader * +reader_createAllAtOnce(struct pngx * const pngxP, + FILE * const ifP) { +/*---------------------------------------------------------------------------- + Create a Reader object that uses libpng's all-at-once raster reading + interface (libpng calls this the "high level" interface). + + The Reader object reads the PNG at construction time, stores the entire + raster, and hands it out as you call reader_read(). + + It is essential that *pngxP be already fully set up to read the image + (all options set). +-----------------------------------------------------------------------------*/ + Reader * readerP; + + MALLOCVAR_NOFAIL(readerP); + + readerP->pngxP = pngxP; + + allocPngRaster(pngxP, &readerP->pngRaster); + + readerP->rowBuf = NULL; + + pngx_readImage(pngxP, readerP->pngRaster); + + readerP->nextRowNum = 0; + + return readerP; +} + + + +static Reader * +reader_createRowByRow(struct pngx * const pngxP, + FILE * const ifP) { +/*---------------------------------------------------------------------------- + Create a Reader object that uses libpng's one-row-at-a-time raster reading + interface (libpng calls this the "low level" interface). + + The Reader object reads from the PNG file, via libpng, as its client + requests the rows. +-----------------------------------------------------------------------------*/ + Reader * readerP; + + MALLOCVAR_NOFAIL(readerP); + + readerP->pngxP = pngxP; + + readerP->pngRaster = NULL; + + MALLOCARRAY(readerP->rowBuf, computePngLineSize(pngxP)); + + if (!readerP->rowBuf) + pm_error("Could not allocate %u bytes for a PNG row buffer", + computePngLineSize(pngxP)); + + readerP->nextRowNum = 0; + + if (pngx_interlaceType(pngxP) != PNG_INTERLACE_NONE) + pm_message("WARNING: this is an interlaced PNG. The PAM output " + "will be interlaced. To get proper output, " + "don't use -byrow"); + + return readerP; +} + + + +static void +reader_destroy(Reader * const readerP) { + + if (readerP->pngRaster) + freePngRaster(readerP->pngRaster, readerP->pngxP); + + if (readerP->rowBuf) + free(readerP->rowBuf); + + free(readerP); +} + + + +static png_byte * +reader_read(Reader * const readerP) { +/*---------------------------------------------------------------------------- + Return a pointer to the next row of the raster. + + The pointer is into storage owned by this object. It is good until + the next read from the object, while the object exists. +-----------------------------------------------------------------------------*/ + png_byte * retval; + + if (readerP->pngRaster) { + if (readerP->nextRowNum >= pngx_imageHeight(readerP->pngxP)) + retval = NULL; + else + retval = readerP->pngRaster[readerP->nextRowNum]; + } else { + pngx_readRow(readerP->pngxP, readerP->rowBuf, NULL); + retval = readerP->rowBuf; + } + + ++readerP->nextRowNum; + + return retval; +} + + + static png_uint_16 -get_png_val(const png_byte ** const pp, - int const bit_depth) { +getPngVal(const png_byte ** const pp, + int const bitDepth) { png_uint_16 c; - if (bit_depth == 16) - c = (*((*pp)++)) << 8; + if (bitDepth == 16) + c = *(*pp)++ << 8; else c = 0; - c |= (*((*pp)++)); + c |= *(*pp)++; return c; } @@ -207,13 +474,14 @@ setTuple(const struct pam * const pamP, tuple const tuple, pngcolor const foreground, pngcolor const background, - enum alpha_handling const alphaHandling, + enum AlphaHandling const alphaHandling, + const struct pngx * const pngxP, png_uint_16 const alpha) { if (alphaHandling == ALPHA_ONLY) tuple[0] = alpha; else if (alphaHandling == ALPHA_NONE || - (alphaHandling == ALPHA_MIX && alpha == maxval)) { + (alphaHandling == ALPHA_MIX && alpha == pngxP->maxval)) { if (pamP->depth < 3) tuple[0] = foreground.r; else { @@ -236,227 +504,228 @@ setTuple(const struct pam * const pamP, if (pamP->depth < 3) tuple[0] = - alphaMix(foreground.r, background.r, alpha, maxval); + alphaMix(foreground.r, background.r, alpha, pngxP->maxval); else { tuple[PAM_RED_PLANE] = - alphaMix(foreground.r, background.r, alpha, maxval); + alphaMix(foreground.r, background.r, alpha, pngxP->maxval); tuple[PAM_GRN_PLANE] = - alphaMix(foreground.g, background.g, alpha, maxval); + alphaMix(foreground.g, background.g, alpha, pngxP->maxval); tuple[PAM_BLU_PLANE] = - alphaMix(foreground.b, background.b, alpha, maxval); + alphaMix(foreground.b, background.b, alpha, pngxP->maxval); } } } -static png_uint_16 -gamma_correct(png_uint_16 const v, - float const g) { +static bool +isColor(png_color const c) { - if (g != -1.0) - return (png_uint_16) ROUNDU(pow((double) v / maxval, (1.0 / g)) * - maxval); - else - return v; + return c.red != c.green || c.green != c.blue; } -static int iscolor (png_color c) -{ - return c.red != c.green || c.green != c.blue; -} +static void +saveText(struct pngx * const pngxP, + FILE * const tfP) { -static void save_text (png_info *info_ptr, FILE *tfp) -{ - int i, j, k; - - for (i = 0 ; i < info_ptr->num_text ; i++) { - j = 0; - while (info_ptr->text[i].key[j] != '\0' && info_ptr->text[i].key[j] != ' ') - j++; - if (info_ptr->text[i].key[j] != ' ') { - fprintf (tfp, "%s", info_ptr->text[i].key); - for (j = strlen (info_ptr->text[i].key) ; j < 15 ; j++) - putc (' ', tfp); - } else { - fprintf (tfp, "\"%s\"", info_ptr->text[i].key); - for (j = strlen (info_ptr->text[i].key) ; j < 13 ; j++) - putc (' ', tfp); - } - putc (' ', tfp); /* at least one space between key and text */ + struct pngx_text const text = pngx_text(pngxP); + + unsigned int i; + + for (i = 0 ; i < text.size; ++i) { + unsigned int j; + j = 0; + + while (text.line[i].key[j] != '\0' && + text.line[i].key[j] != ' ') + ++j; + + if (text.line[i].key[j] != ' ') { + fprintf(tfP, "%s", text.line[i].key); + for (j = strlen (text.line[i].key); j < 15; ++j) + putc(' ', tfP); + } else { + fprintf(tfP, "\"%s\"", text.line[i].key); + for (j = strlen (text.line[i].key); j < 13; ++j) + putc(' ', tfP); + } + putc(' ', tfP); /* at least one space between key and text */ - for (j = 0 ; j < info_ptr->text[i].text_length ; j++) { - putc (info_ptr->text[i].text[j], tfp); - if (info_ptr->text[i].text[j] == '\n') - for (k = 0 ; k < 16 ; k++) - putc ((int)' ', tfp); + for (j = 0; j < text.line[i].text_length; ++j) { + putc(text.line[i].text[j], tfP); + if (text.line[i].text[j] == '\n') { + unsigned int k; + for (k = 0; k < 16; ++k) + putc(' ', tfP); + } + } + putc('\n', tfP); } - putc ((int)'\n', tfp); - } } -static void show_time (png_info *info_ptr) -{ - static const char * const month[] = { - "", "January", "February", "March", "April", "May", "June", - "July", "August", "September", "October", "November", "December" - }; - - if (info_ptr->valid & PNG_INFO_tIME) { - if (info_ptr->mod_time.month < 1 || - info_ptr->mod_time.month >= ARRAY_SIZE(month)) { - pm_message("tIME chunk in PNG input is invalid; " - "modification time of image is unknown. " - "The month value, which should be in the range " - "1-12, is %u", info_ptr->mod_time.month); - } else - pm_message ("modification time: %02d %s %d %02d:%02d:%02d", - info_ptr->mod_time.day, month[info_ptr->mod_time.month], - info_ptr->mod_time.year, info_ptr->mod_time.hour, - info_ptr->mod_time.minute, info_ptr->mod_time.second); - } -} -static void pngtopnm_error_handler (png_structp png_ptr, png_const_charp msg) -{ - jmpbuf_wrapper *jmpbuf_ptr; - /* this function, aside from the extra step of retrieving the "error - * pointer" (below) and the fact that it exists within the application - * rather than within libpng, is essentially identical to libpng's - * default error handler. The second point is critical: since both - * setjmp() and longjmp() are called from the same code, they are - * guaranteed to have compatible notions of how big a jmp_buf is, - * regardless of whether _BSD_SOURCE or anything else has (or has not) - * been defined. */ +static void +showTime(struct pngx * const pngxP) { - pm_message("fatal libpng error: %s", msg); + if (pngx_chunkIsPresent(pngxP, PNG_INFO_tIME)) { + png_time const modTime = pngx_time(pngxP); - jmpbuf_ptr = png_get_error_ptr(png_ptr); - if (jmpbuf_ptr == NULL) { - /* we are completely hosed now */ - pm_error("EXTREMELY fatal error: jmpbuf unrecoverable; terminating."); - } + static const char * const month[] = { + "", "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" + }; - longjmp(jmpbuf_ptr->jmpbuf, 1); + if (modTime.month < 1 || modTime.month >= ARRAY_SIZE(month)) { + pm_message("tIME chunk in PNG input is invalid; " + "modification time of image is unknown. " + "The month value, which should be in the range " + "1-12, is %u", modTime.month); + } else { + pm_message("modification time: %02d %s %d %02d:%02d:%02d", + modTime.day, + month[modTime.month], + modTime.year, + modTime.hour, + modTime.minute, + modTime.second); + } + } } static void -dump_png_info(png_info *info_ptr) { +dumpTypeAndFilter(struct pngx * const pngxP) { - const char *type_string; - const char *filter_string; + const char * typeString; + const char * filterString; - switch (info_ptr->color_type) { - case PNG_COLOR_TYPE_GRAY: - type_string = "gray"; + switch (pngx_colorType(pngxP)) { + case PNG_COLOR_TYPE_GRAY: + typeString = "gray"; break; - - case PNG_COLOR_TYPE_GRAY_ALPHA: - type_string = "gray+alpha"; + + case PNG_COLOR_TYPE_GRAY_ALPHA: + typeString = "gray+alpha"; break; - - case PNG_COLOR_TYPE_PALETTE: - type_string = "palette"; + + case PNG_COLOR_TYPE_PALETTE: + typeString = "palette"; break; - case PNG_COLOR_TYPE_RGB: - type_string = "truecolor"; + case PNG_COLOR_TYPE_RGB: + typeString = "truecolor"; break; - case PNG_COLOR_TYPE_RGB_ALPHA: - type_string = "truecolor+alpha"; + case PNG_COLOR_TYPE_RGB_ALPHA: + typeString = "truecolor+alpha"; break; } - switch (info_ptr->filter_type) { + switch (pngx_filterType(pngxP)) { case PNG_FILTER_TYPE_BASE: - asprintfN(&filter_string, "base filter"); + pm_asprintf(&filterString, "base filter"); break; default: - asprintfN(&filter_string, "unknown filter type %d", - info_ptr->filter_type); + pm_asprintf(&filterString, "unknown filter type %d", + pngx_filterType(pngxP)); } - pm_message("reading a %ldw x %ldh image, %d bit%s", - info_ptr->width, info_ptr->height, - info_ptr->bit_depth, info_ptr->bit_depth > 1 ? "s" : ""); pm_message("%s, %s, %s", - type_string, - info_ptr->interlace_type ? + typeString, + pngx_interlaceType(pngxP) ? "Adam7 interlaced" : "not interlaced", - filter_string); - pm_message("background {index, gray, red, green, blue} = " - "{%d, %d, %d, %d, %d}", - info_ptr->background.index, - info_ptr->background.gray, - info_ptr->background.red, - info_ptr->background.green, - info_ptr->background.blue); - - strfree(filter_string); - - if (info_ptr->valid & PNG_INFO_tRNS) + filterString); + + pm_strfree(filterString); +} + + + +static void +dumpPngInfo(struct pngx * const pngxP) { + + pm_message("reading a %u x %u image, %u bit%s", + pngx_imageWidth(pngxP), + pngx_imageHeight(pngxP), + pngx_bitDepth(pngxP), + pngx_bitDepth(pngxP) > 1 ? "s" : ""); + + dumpTypeAndFilter(pngxP); + + if (pngx_chunkIsPresent(pngxP, PNG_INFO_bKGD)) { + png_color_16 const background = pngx_bkgd(pngxP); + + pm_message("background {index, gray, red, green, blue} = " + "{%d, %d, %d, %d, %d}", + background.index, + background.gray, + background.red, + background.green, + background.blue); + } + + if (pngx_chunkIsPresent(pngxP, PNG_INFO_tRNS)) pm_message("tRNS chunk (transparency): %u entries", - info_ptr->num_trans); + pngx_trns(pngxP).numTrans); else pm_message("tRNS chunk (transparency): not present"); - if (info_ptr->valid & PNG_INFO_gAMA) - pm_message("gAMA chunk (image gamma): gamma = %4.2f", info_ptr->gamma); + if (pngx_chunkIsPresent(pngxP, PNG_INFO_gAMA)) + pm_message("gAMA chunk (image gamma): gamma = %4.2f", + pngx_gama(pngxP)); else pm_message("gAMA chunk (image gamma): not present"); - - if (info_ptr->valid & PNG_INFO_sBIT) + + if (pngx_chunkIsPresent(pngxP, PNG_INFO_sBIT)) pm_message("sBIT chunk: present"); else pm_message("sBIT chunk: not present"); - if (info_ptr->valid & PNG_INFO_cHRM) + if (pngx_chunkIsPresent(pngxP, PNG_INFO_cHRM)) pm_message("cHRM chunk: present"); else pm_message("cHRM chunk: not present"); - if (info_ptr->valid & PNG_INFO_PLTE) - pm_message("PLTE chunk: %d entries", info_ptr->num_palette); + if (pngx_chunkIsPresent(pngxP, PNG_INFO_PLTE)) + pm_message("PLTE chunk: %d entries", pngx_plte(pngxP).size); else pm_message("PLTE chunk: not present"); - if (info_ptr->valid & PNG_INFO_bKGD) + if (pngx_chunkIsPresent(pngxP, PNG_INFO_bKGD)) pm_message("bKGD chunk: present"); else pm_message("bKGD chunk: not present"); - if (info_ptr->valid & PNG_INFO_hIST) + if (pngx_chunkIsPresent(pngxP, PNG_INFO_hIST)) pm_message("hIST chunk: present"); else pm_message("hIST chunk: not present"); - if (info_ptr->valid & PNG_INFO_pHYs) + if (pngx_chunkIsPresent(pngxP, PNG_INFO_pHYs)) pm_message("pHYs chunk: present"); else pm_message("pHYs chunk: not present"); - if (info_ptr->valid & PNG_INFO_oFFs) + if (pngx_chunkIsPresent(pngxP, PNG_INFO_oFFs)) pm_message("oFFs chunk: present"); else pm_message("oFFs chunk: not present"); - if (info_ptr->valid & PNG_INFO_tIME) + if (pngx_chunkIsPresent(pngxP, PNG_INFO_tIME)) pm_message("tIME chunk: present"); else pm_message("tIME chunk: not present"); - if (info_ptr->valid & PNG_INFO_pCAL) + if (pngx_chunkIsPresent(pngxP, PNG_INFO_pCAL)) pm_message("pCAL chunk: present"); else pm_message("pCAL chunk: not present"); - if (info_ptr->valid & PNG_INFO_sRGB) + if (pngx_chunkIsPresent(pngxP, PNG_INFO_sRGB)) pm_message("sRGB chunk: present"); else pm_message("sRGB chunk: not present"); @@ -464,83 +733,34 @@ dump_png_info(png_info *info_ptr) { -static unsigned int -computePngLineSize(png_info * const pngInfoP) { - - unsigned int const bytesPerSample = pngInfoP->bit_depth == 16 ? 2 : 1; +static const png_color_16 +transColor(struct pngx * const pngxP) { - unsigned int samplesPerPixel; - - switch (pngInfoP->color_type) { - case PNG_COLOR_TYPE_GRAY_ALPHA: samplesPerPixel = 2; break; - case PNG_COLOR_TYPE_RGB: samplesPerPixel = 3; break; - case PNG_COLOR_TYPE_RGB_ALPHA: samplesPerPixel = 4; break; - default: samplesPerPixel = 1; - } - - if (UINT_MAX / bytesPerSample / samplesPerPixel < pngInfoP->width) - pm_error("Width %u of PNG is uncomputably large", - (unsigned int)pngInfoP->width); - - return pngInfoP->width * bytesPerSample * samplesPerPixel; -} - - - -static void -allocPngRaster(png_info * const pngInfoP, - png_byte *** const pngImageP) { - - unsigned int const lineSize = computePngLineSize(pngInfoP); - - png_byte ** pngImage; - unsigned int row; - - MALLOCARRAY(pngImage, pngInfoP->height); - - if (pngImage == NULL) - pm_error("couldn't allocate space for %u PNG raster rows", - (unsigned int)pngInfoP->height); - - for (row = 0; row < pngInfoP->height; ++row) { - MALLOCARRAY(pngImage[row], lineSize); - if (pngImage[row] == NULL) - pm_error("couldn't allocate space for %uth row of PNG raster", - row); - } - *pngImageP = pngImage; -} - - - -static void -freePngRaster(png_byte ** const pngRaster, - png_info * const pngInfoP) { - - unsigned int row; + struct pngx_trns const trans = pngx_trns(pngxP); - for (row = 0; row < pngInfoP->height; ++row) - free(pngRaster[row]); - - free(pngRaster); + assert(pngx_chunkIsPresent(pngxP, PNG_INFO_tRNS)); + + return trans.transColor; } static bool -isTransparentColor(pngcolor const color, - png_info * const pngInfoP, - double const totalgamma) { +isTransparentColor(pngcolor const color, + struct pngx * const pngxP, + GammaCorrection const gamma) { /*---------------------------------------------------------------------------- Return TRUE iff pixels of color 'color' are supposed to be transparent everywhere they occur. Assume it's an RGB image. - 'color' has been gamma-corrected. + 'gamma' indicats what gamma correction has been applied to 'color' (we need + to know that because *pngxP identifies the color that is supposed to be + transparent in _not_ gamma-corrected form!). -----------------------------------------------------------------------------*/ bool retval; - if (pngInfoP->valid & PNG_INFO_tRNS) { - const png_color_16 * const transColorP = &pngInfoP->trans_values; + if (pngx_chunkIsPresent(pngxP, PNG_INFO_tRNS)) { + png_color_16 const transColor16 = transColor(pngxP); /* It seems odd that libpng lets you get gamma-corrected pixel values, but not gamma-corrected transparency or background @@ -556,15 +776,17 @@ isTransparentColor(pngcolor const color, pixels, and just do it ourselves. */ - switch (pngInfoP->color_type) { + switch (pngx_colorType(pngxP)) { case PNG_COLOR_TYPE_GRAY: - retval = color.r == gamma_correct(transColorP->gray, totalgamma); + retval = color.r == gammaCorrect(transColor16.gray, gamma, + pngxP->maxval); break; - default: - retval = - color.r == gamma_correct(transColorP->red, totalgamma) && - color.g == gamma_correct(transColorP->green, totalgamma) && - color.b == gamma_correct(transColorP->blue, totalgamma); + default: { + pngcolor const transColor = pngcolorFrom16(transColor16); + retval = pngColorEqual(color, + gammaCorrectColor(transColor, gamma, + pngxP->maxval)); + } } } else retval = FALSE; @@ -574,60 +796,63 @@ isTransparentColor(pngcolor const color, -#define SIG_CHECK_SIZE 4 - static void -read_sig_buf(FILE * const ifP) { - - unsigned char sig_buf[SIG_CHECK_SIZE]; - size_t bytesRead; - - bytesRead = fread(sig_buf, 1, SIG_CHECK_SIZE, ifP); - if (bytesRead != SIG_CHECK_SIZE) - pm_error ("input file is empty or too short"); - - if (png_sig_cmp(sig_buf, (png_size_t) 0, (png_size_t) SIG_CHECK_SIZE) - != 0) - pm_error ("input file is not a PNG file"); -} +setupGammaCorrection(struct pngx * const pngxP, + bool const screenGammaIsKnown, + float const screenGamma, + GammaCorrection * const gammaCorrectionP) { +/*---------------------------------------------------------------------------- + Set up to have values from the PNG gamma-corrected. + Return as *gammaCorrectionP the correction necessary and tell the + libpng image reader *pngxP to do that same correction - on the pixels + only, as it can't do it on anything else (hence, Caller will have to + use *gammaCorrectionP to do it). + 'screenGammaIsKnown' means we know what the screen gamma is, and it is + 'screenGamma'. If we don't know what the screen gamma is, gamma + correction is not possible, so we set up for no gamma correction. -static void -setupGammaCorrection(png_struct * const png_ptr, - png_info * const info_ptr, - float const displaygamma, - float * const totalgammaP) { + The gamma correction we ordain is a combination of the image gamma, + recorded in the PNG input and represented by *pngxP, and the screen gamma. - if (displaygamma == -1.0) - *totalgammaP = -1.0; + Note that "screen gamma" is a characteristic of both the display and the + viewing conditions. There are also "display gamma" and "viewing gamma," + respectively, but we don't care about the breakdown. In a dimly lit room, + viewing gamma is 1 and screen gamma is the same as the display gamma. +-----------------------------------------------------------------------------*/ + if (!screenGammaIsKnown) + gammaCorrectionP->needCorrection = false; else { float imageGamma; - if (info_ptr->valid & PNG_INFO_gAMA) - imageGamma = info_ptr->gamma; + if (pngx_chunkIsPresent(pngxP, PNG_INFO_gAMA)) + imageGamma = pngx_gama(pngxP); else { if (verbose) pm_message("PNG doesn't specify image gamma. Assuming 1.0"); imageGamma = 1.0; } - if (fabs(displaygamma * imageGamma - 1.0) < .01) { - *totalgammaP = -1.0; + if (fabs(screenGamma * imageGamma - 1.0) < .01) { + gammaCorrectionP->needCorrection = false; if (verbose) pm_message("image gamma %4.2f matches " - "display gamma %4.2f. No conversion.", - imageGamma, displaygamma); + "screen gamma %4.2f. No conversion.", + imageGamma, screenGamma); } else { - png_set_gamma(png_ptr, displaygamma, imageGamma); - *totalgammaP = imageGamma * displaygamma; - /* in case of gamma-corrections, sBIT's as in the + pngx_setGamma(pngxP, screenGamma, imageGamma); + + gammaCorrectionP->needCorrection = true; + gammaCorrectionP->gamma = imageGamma * screenGamma; + /* In case of gamma-corrections, sBIT's as in the PNG-file are not valid anymore */ - info_ptr->valid &= ~PNG_INFO_sBIT; + pngx_removeChunk(pngxP, PNG_INFO_sBIT); if (verbose) pm_message("image gamma is %4.2f, " - "converted for display gamma of %4.2f", - imageGamma, displaygamma); + "display gamma is %4.2f; " + "combined gamma is %4.2f", + imageGamma, screenGamma, gammaCorrectionP->gamma); } } } @@ -635,20 +860,21 @@ setupGammaCorrection(png_struct * const png_ptr, static bool -paletteHasPartialTransparency(png_info * const info_ptr) { +paletteHasPartialTransparency(struct pngx * const pngxP) { bool retval; - if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { - if (info_ptr->valid & PNG_INFO_tRNS) { + if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_PALETTE) { + if (pngx_chunkIsPresent(pngxP, PNG_INFO_tRNS)) { + struct pngx_trns const trans = pngx_trns(pngxP); + bool foundGray; unsigned int i; for (i = 0, foundGray = FALSE; - i < info_ptr->num_trans && !foundGray; + i < trans.numTrans && !foundGray; ++i) { - if (info_ptr->TRANS_ALPHA[i] != 0 && - info_ptr->TRANS_ALPHA[i] != maxval) { + if (trans.trans[i] != 0 && trans.trans[i] != pngxP->maxval) { foundGray = TRUE; } } @@ -664,61 +890,68 @@ paletteHasPartialTransparency(png_info * const info_ptr) { static void -getComponentSbitFg(png_info * const pngInfoP, - png_byte * const fgSbitP, - bool * const notUniformP) { - - if (pngInfoP->color_type == PNG_COLOR_TYPE_RGB || - pngInfoP->color_type == PNG_COLOR_TYPE_RGB_ALPHA || - pngInfoP->color_type == PNG_COLOR_TYPE_PALETTE) { - if (pngInfoP->sig_bit.red == pngInfoP->sig_bit.blue && - pngInfoP->sig_bit.red == pngInfoP->sig_bit.green) { +getComponentSbitFg(struct pngx * const pngxP, + png_byte * const fgSbitP, + bool * const notUniformP) { + + png_color_8 const sigBit = pngx_sbit(pngxP); + + assert(pngx_chunkIsPresent(pngxP, PNG_INFO_sBIT)); + + if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_RGB || + pngx_colorType(pngxP) == PNG_COLOR_TYPE_RGB_ALPHA || + pngx_colorType(pngxP) == PNG_COLOR_TYPE_PALETTE) { + + if (sigBit.red == sigBit.blue && + sigBit.red == sigBit.green) { *notUniformP = false; - *fgSbitP = pngInfoP->sig_bit.red; + *fgSbitP = sigBit.red; } else *notUniformP = true; } else { /* It has only a gray channel so it's obviously uniform */ *notUniformP = false; - *fgSbitP = pngInfoP->sig_bit.gray; + *fgSbitP = sigBit.gray; } } static void -getComponentSbit(png_info * const pngInfoP, - enum alpha_handling const alphaHandling, +getComponentSbit(struct pngx * const pngxP, + enum AlphaHandling const alphaHandling, png_byte * const componentSbitP, bool * const notUniformP) { + assert(pngx_chunkIsPresent(pngxP, PNG_INFO_sBIT)); + switch (alphaHandling) { - case ALPHA_ONLY: + case ALPHA_ONLY: { /* We care only about the alpha channel, so the uniform Sbit is the alpha Sbit */ *notUniformP = false; - *componentSbitP = pngInfoP->sig_bit.alpha; - break; + *componentSbitP = pngx_sbit(pngxP).alpha; + } break; case ALPHA_NONE: case ALPHA_MIX: /* We aren't going to produce an alpha channel, so we care only about the uniformity of the foreground channels. */ - getComponentSbitFg(pngInfoP, componentSbitP, notUniformP); + getComponentSbitFg(pngxP, componentSbitP, notUniformP); break; case ALPHA_IN: { /* We care about both the foreground and the alpha */ bool fgNotUniform; png_byte fgSbit; - getComponentSbitFg(pngInfoP, &fgSbit, &fgNotUniform); + getComponentSbitFg(pngxP, &fgSbit, &fgNotUniform); if (fgNotUniform) *notUniformP = true; else { - if (fgSbit == pngInfoP->sig_bit.alpha) { + if (fgSbit == pngx_sbit(pngxP).alpha) { *notUniformP = false; *componentSbitP = fgSbit; } else @@ -731,8 +964,8 @@ getComponentSbit(png_info * const pngInfoP, static void -shiftPalette(png_info * const pngInfoP, - unsigned int const shift) { +shiftPalette(struct pngx * const pngxP, + unsigned int const shift) { /*---------------------------------------------------------------------------- Shift every component of every color in the PNG palette right by 'shift' bits because sBIT chunk says only those are significant. @@ -743,12 +976,14 @@ shiftPalette(png_info * const pngInfoP, "but sBIT chunk says %u bits", shift); else { + struct pngx_plte const palette = pngx_plte(pngxP); + unsigned int i; - for (i = 0; i < pngInfoP->num_palette; ++i) { - pngInfoP->palette[i].red >>= (8 - shift); - pngInfoP->palette[i].green >>= (8 - shift); - pngInfoP->palette[i].blue >>= (8 - shift); + for (i = 0; i < palette.size; ++i) { + palette.palette[i].red >>= (8 - shift); + palette.palette[i].green >>= (8 - shift); + palette.palette[i].blue >>= (8 - shift); } } } @@ -756,12 +991,11 @@ shiftPalette(png_info * const pngInfoP, static void -computeMaxvalFromSbit(png_struct * const pngP, - png_info * const pngInfoP, - enum alpha_handling const alphaHandling, +computeMaxvalFromSbit(struct pngx * const pngxP, + enum AlphaHandling const alphaHandling, png_uint_16 * const maxvalP, bool * const succeededP, - int * const errorlevelP) { + int * const errorLevelP) { /* sBIT handling is very tricky. If we are extracting only the image, we can use the sBIT info for grayscale and color images, @@ -782,37 +1016,38 @@ computeMaxvalFromSbit(png_struct * const pngP, Meaningless if they aren't all the same (i.e. 'notUniform') */ - getComponentSbit(pngInfoP, alphaHandling, &componentSigBit, ¬Uniform); + getComponentSbit(pngxP, alphaHandling, &componentSigBit, ¬Uniform); if (notUniform) { pm_message("This program cannot handle " "different bit depths for color channels"); - pm_message("writing file with %u bit resolution", pngInfoP->bit_depth); + pm_message("writing file with %u bit resolution", + pngx_bitDepth(pngxP)); *succeededP = false; - *errorlevelP = PNMTOPNG_WARNING_LEVEL; + *errorLevelP = PNMTOPNG_WARNING_LEVEL; } else if (componentSigBit > 15) { pm_message("Invalid PNG: says %u significant bits for a component; " "max possible is 16. Ignoring sBIT chunk.", componentSigBit); *succeededP = false; - *errorlevelP = PNMTOPNG_WARNING_LEVEL; + *errorLevelP = PNMTOPNG_WARNING_LEVEL; } else { if (alphaHandling == ALPHA_MIX && - (pngInfoP->color_type == PNG_COLOR_TYPE_RGB_ALPHA || - pngInfoP->color_type == PNG_COLOR_TYPE_GRAY_ALPHA || - paletteHasPartialTransparency(pngInfoP))) + (pngx_colorType(pngxP) == PNG_COLOR_TYPE_RGB_ALPHA || + pngx_colorType(pngxP) == PNG_COLOR_TYPE_GRAY_ALPHA || + paletteHasPartialTransparency(pngxP))) *succeededP = false; else { - if (componentSigBit < pngInfoP->bit_depth) { + if (componentSigBit < pngx_bitDepth(pngxP)) { pm_message("Image has fewer significant bits, " "writing file with %u bits", componentSigBit); *maxvalP = (1l << componentSigBit) - 1; *succeededP = true; - - if (pngInfoP->color_type == PNG_COLOR_TYPE_PALETTE) - shiftPalette(pngInfoP, componentSigBit); + + if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_PALETTE) + shiftPalette(pngxP, componentSigBit); else - png_set_shift(pngP, &pngInfoP->sig_bit); + pngx_setShift(pngxP, pngx_sbit(pngxP)); } else *succeededP = false; } @@ -822,50 +1057,48 @@ computeMaxvalFromSbit(png_struct * const pngP, static void -setupSignificantBits(png_struct * const pngP, - png_info * const pngInfoP, - enum alpha_handling const alphaHandling, - png_uint_16 * const maxvalP, - int * const errorlevelP) { +setupSignificantBits(struct pngx * const pngxP, + enum AlphaHandling const alphaHandling, + int * const errorLevelP) { /*---------------------------------------------------------------------------- - Figure out what maxval would best express the information in the PNG - described by *pngP and *pngInfoP, with 'alpha' telling which - information in the PNG we care about (image or alpha mask). + Figure out what maxval is used in the PNG described by *pngxP, with 'alpha' + telling which information in the PNG we care about (image or alpha mask). + Update *pngxP with that information. Return the result as *maxvalP. - Also set up *pngP for the corresponding significant bits. + Also set up *pngxP for the corresponding significant bits. -----------------------------------------------------------------------------*/ bool gotItFromSbit; - if (pngInfoP->valid & PNG_INFO_sBIT) - computeMaxvalFromSbit(pngP, pngInfoP, alphaHandling, - maxvalP, &gotItFromSbit, errorlevelP); + if (pngx_chunkIsPresent(pngxP, PNG_INFO_sBIT)) + computeMaxvalFromSbit(pngxP, alphaHandling, + &pngxP->maxval, &gotItFromSbit, errorLevelP); else gotItFromSbit = false; if (!gotItFromSbit) { - if (pngInfoP->color_type == PNG_COLOR_TYPE_PALETTE) { + if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_PALETTE) { if (alphaHandling == ALPHA_ONLY) { - if (pngInfoP->color_type == PNG_COLOR_TYPE_GRAY || - pngInfoP->color_type == PNG_COLOR_TYPE_RGB) + if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_GRAY || + pngx_colorType(pngxP) == PNG_COLOR_TYPE_RGB) /* The alpha mask will be all opaque, so maxval 1 is plenty */ - *maxvalP = 1; - else if (paletteHasPartialTransparency(pngInfoP)) + pngxP->maxval = 1; + else if (paletteHasPartialTransparency(pngxP)) /* Use same maxval as PNG transparency palette for simplicity */ - *maxvalP = 255; + pngxP->maxval = 255; else /* A common case, so we conserve bits */ - *maxvalP = 1; + pngxP->maxval = 1; } else /* Use same maxval as PNG palette for simplicity */ - *maxvalP = 255; + pngxP->maxval = 255; } else { - *maxvalP = (1l << pngInfoP->bit_depth) - 1; + pngxP->maxval = (1l << pngx_bitDepth(pngxP)) - 1; } } } @@ -873,22 +1106,24 @@ setupSignificantBits(png_struct * const pngP, static bool -imageHasColor(png_info * const info_ptr) { +imageHasColor(struct pngx * const pngxP) { bool retval; - if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY || - info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_GRAY || + pngx_colorType(pngxP) == PNG_COLOR_TYPE_GRAY_ALPHA) retval = FALSE; - else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { + else if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_PALETTE) { + struct pngx_plte const palette = pngx_plte(pngxP); + bool foundColor; unsigned int i; for (i = 0, foundColor = FALSE; - i < info_ptr->num_palette && !foundColor; + i < palette.size && !foundColor; ++i) { - if (iscolor(info_ptr->palette[i])) + if (isColor(palette.palette[i])) foundColor = TRUE; } retval = foundColor; @@ -901,8 +1136,8 @@ imageHasColor(png_info * const info_ptr) { static void -determineOutputType(png_info * const pngInfoP, - enum alpha_handling const alphaHandling, +determineOutputType(struct pngx * const pngxP, + enum AlphaHandling const alphaHandling, pngcolor const bgColor, xelval const maxval, int * const formatP, @@ -916,7 +1151,7 @@ determineOutputType(png_info * const pngInfoP, } else { /* The output is a normal Netpbm image */ bool const outputIsColor = - imageHasColor(pngInfoP) || !isGrayscale(bgColor); + imageHasColor(pngxP) || !isGrayscale(bgColor); if (alphaHandling == ALPHA_IN) { *formatP = PAM_FORMAT; @@ -942,11 +1177,11 @@ determineOutputType(png_info * const pngInfoP, static void -getBackgroundColor(png_info * const info_ptr, - const char * const requestedColor, - float const totalgamma, - xelval const maxval, - pngcolor * const bgColorP) { +getBackgroundColor(struct pngx * const pngxP, + const char * const requestedColor, + GammaCorrection const gamma, + xelval const maxval, + pngcolor * const bgColorP) { /*---------------------------------------------------------------------------- Figure out what the background color should be. If the user requested a particular color ('requestedColor' not null), that's the one. @@ -964,31 +1199,31 @@ getBackgroundColor(png_info * const info_ptr, bgColorP->g = PPM_GETG(backcolor); bgColorP->b = PPM_GETB(backcolor); - } else if (info_ptr->valid & PNG_INFO_bKGD) { - /* didn't manage to get libpng to work (bugs?) concerning background + } else if (pngx_chunkIsPresent(pngxP, PNG_INFO_bKGD)) { + /* Didn't manage to get libpng to work (bugs?) concerning background processing, therefore we do our own. */ - switch (info_ptr->color_type) { + png_color_16 const background = pngx_bkgd(pngxP); + switch (pngx_colorType(pngxP)) { case PNG_COLOR_TYPE_GRAY: case PNG_COLOR_TYPE_GRAY_ALPHA: bgColorP->r = bgColorP->g = bgColorP->b = - gamma_correct(info_ptr->background.gray, totalgamma); + gammaCorrect(background.gray, gamma, pngxP->maxval); break; case PNG_COLOR_TYPE_PALETTE: { + struct pngx_plte const palette = pngx_plte(pngxP); png_color const rawBgcolor = - info_ptr->palette[info_ptr->background.index]; - bgColorP->r = gamma_correct(rawBgcolor.red, totalgamma); - bgColorP->g = gamma_correct(rawBgcolor.green, totalgamma); - bgColorP->b = gamma_correct(rawBgcolor.blue, totalgamma); + palette.palette[background.index]; + *bgColorP = gammaCorrectColor(pngcolorFromByte(rawBgcolor), + gamma, pngxP->maxval); } break; case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_RGB_ALPHA: { - png_color_16 const rawBgcolor = info_ptr->background; + png_color_16 const rawBgcolor = background; - bgColorP->r = gamma_correct(rawBgcolor.red, totalgamma); - bgColorP->g = gamma_correct(rawBgcolor.green, totalgamma); - bgColorP->b = gamma_correct(rawBgcolor.blue, totalgamma); + *bgColorP = gammaCorrectColor(pngcolorFrom16(rawBgcolor), + gamma, pngxP->maxval); } break; } @@ -999,31 +1234,89 @@ getBackgroundColor(png_info * const info_ptr, -#define GET_PNG_VAL(p) get_png_val(&(p), pngInfoP->bit_depth) +static void +warnNonsquarePixels(struct pngx * const pngxP, + int * const errorLevelP) { + + if (pngx_chunkIsPresent(pngxP, PNG_INFO_pHYs)) { + float const r = + (float)pngx_xPixelsPerMeter(pngxP) / pngx_yPixelsPerMeter(pngxP); + + if (r != 1.0) { + const char * const baseMsg = "warning - non-square pixels"; + + if (pm_have_float_format()) + pm_message("%s; to fix do a 'pamscale -%cscale %g'", + baseMsg, + r < 1.0 ? 'x' : 'y', + r < 1.0 ? 1.0 / r : r); + else + pm_message("%s", baseMsg); + + *errorLevelP = PNMTOPNG_WARNING_LEVEL; + } + } +} + + + +static png_uint_16 +paletteAlpha(struct pngx * const pngxP, + png_uint_16 const index, + sample const maxval) { + + png_uint_16 retval; + + if (pngx_chunkIsPresent(pngxP, PNG_INFO_tRNS)) { + struct pngx_trns const trans = pngx_trns(pngxP); + + if (index < trans.numTrans) + retval = trans.trans[index]; + else + retval = maxval; + } else + retval = maxval; + + return retval; +} + + + +#define GET_PNG_VAL(p) getPngVal(&(p), pngx_bitDepth(pngxP)) static void makeTupleRow(const struct pam * const pamP, const tuple * const tuplerow, - png_info * const pngInfoP, + struct pngx * const pngxP, const png_byte * const pngRasterRow, pngcolor const bgColor, - enum alpha_handling const alphaHandling, - double const totalgamma) { - + enum AlphaHandling const alphaHandling, + GammaCorrection const gamma) { +/*---------------------------------------------------------------------------- + Convert a raster row as supplied by libpng, at 'pngRasterRow' and + described by *pngxP, to a libpam-style tuple row at 'tupleRow'. + + Where the raster says the pixel isn't opaque, we either include that + opacity information in the output pixel or we mix the pixel with background + color 'bgColor', as directed by 'alphaHandling'. Or, if 'alphaHandling' + says so, we may produce an output row of _only_ the transparency + information. +-----------------------------------------------------------------------------*/ const png_byte * pngPixelP; unsigned int col; pngPixelP = &pngRasterRow[0]; /* initial value */ - for (col = 0; col < pngInfoP->width; ++col) { - switch (pngInfoP->color_type) { + for (col = 0; col < pngx_imageWidth(pngxP); ++col) { + switch (pngx_colorType(pngxP)) { case PNG_COLOR_TYPE_GRAY: { pngcolor fgColor; fgColor.r = fgColor.g = fgColor.b = GET_PNG_VAL(pngPixelP); setTuple(pamP, tuplerow[col], fgColor, bgColor, alphaHandling, - isTransparentColor(fgColor, pngInfoP, totalgamma) ? - 0 : maxval); + pngxP, + isTransparentColor(fgColor, pngxP, gamma) ? + 0 : pngxP->maxval); } break; @@ -1034,13 +1327,14 @@ makeTupleRow(const struct pam * const pamP, fgColor.r = fgColor.g = fgColor.b = GET_PNG_VAL(pngPixelP); alpha = GET_PNG_VAL(pngPixelP); setTuple(pamP, tuplerow[col], fgColor, bgColor, - alphaHandling, alpha); + alphaHandling, pngxP, alpha); } break; case PNG_COLOR_TYPE_PALETTE: { - png_uint_16 const index = GET_PNG_VAL(pngPixelP); - png_color const paletteColor = pngInfoP->palette[index]; + png_uint_16 const index = GET_PNG_VAL(pngPixelP); + struct pngx_plte const palette = pngx_plte(pngxP); + png_color const paletteColor = palette.palette[index]; pngcolor fgColor; @@ -1049,9 +1343,7 @@ makeTupleRow(const struct pam * const pamP, fgColor.b = paletteColor.blue; setTuple(pamP, tuplerow[col], fgColor, bgColor, alphaHandling, - (pngInfoP->valid & PNG_INFO_tRNS) && - index < pngInfoP->num_trans ? - pngInfoP->TRANS_ALPHA[index] : maxval); + pngxP, paletteAlpha(pngxP, index, pngxP->maxval)); } break; @@ -1062,8 +1354,9 @@ makeTupleRow(const struct pam * const pamP, fgColor.g = GET_PNG_VAL(pngPixelP); fgColor.b = GET_PNG_VAL(pngPixelP); setTuple(pamP, tuplerow[col], fgColor, bgColor, alphaHandling, - isTransparentColor(fgColor, pngInfoP, totalgamma) ? - 0 : maxval); + pngxP, + isTransparentColor(fgColor, pngxP, gamma) ? + 0 : pngxP->maxval); } break; @@ -1076,12 +1369,13 @@ makeTupleRow(const struct pam * const pamP, fgColor.b = GET_PNG_VAL(pngPixelP); alpha = GET_PNG_VAL(pngPixelP); setTuple(pamP, tuplerow[col], fgColor, bgColor, - alphaHandling, alpha); + alphaHandling, pngxP, alpha); } break; default: - pm_error("unknown PNG color type: %d", pngInfoP->color_type); + pm_error("unknown PNG color type: %d", + pngx_colorType(pngxP)); } } } @@ -1103,8 +1397,8 @@ reportOutputFormat(const struct pam * const pamP) { pm_message("Writing a PPM file with maxval %lu", pamP->maxval); break; case PAM_FORMAT: - pm_message("Writing a PAM file with tuple type %s, maxval %u", - pamP->tuple_type, maxval); + pm_message("Writing a PAM file with tuple type %s, maxval %lu", + pamP->tuple_type, pamP->maxval); break; default: assert(false); /* Every possible value handled above */ @@ -1115,15 +1409,15 @@ reportOutputFormat(const struct pam * const pamP) { static void writeNetpbm(struct pam * const pamP, - png_info * const pngInfoP, - png_byte ** const pngRaster, + struct pngx * const pngxP, + Reader * const rasterReaderP, pngcolor const bgColor, - enum alpha_handling const alphaHandling, - double const totalgamma) { + enum AlphaHandling const alphaHandling, + GammaCorrection const gamma) { /*---------------------------------------------------------------------------- Write a Netpbm image of either the image or the alpha mask, according to - 'alphaHandling' that is in the PNG image described by 'pngInfoP' and - pngRaster. + 'alphaHandling' that is in the PNG image described by *pngxP, reading + its raster with the raster reader object *rasterReaderP. *pamP describes the required output image and is consistent with *pngInfoP. @@ -1141,9 +1435,13 @@ writeNetpbm(struct pam * const pamP, tuplerow = pnm_allocpamrow(pamP); - for (row = 0; row < pngInfoP->height; ++row) { - makeTupleRow(pamP, tuplerow, pngInfoP, pngRaster[row], bgColor, - alphaHandling, totalgamma); + for (row = 0; row < pngx_imageHeight(pngxP); ++row) { + png_byte * const pngRow = reader_read(rasterReaderP); + + assert(pngRow); + + makeTupleRow(pamP, tuplerow, pngxP, pngRow, bgColor, + alphaHandling, gamma); pnm_writepamrow(pamP, tuplerow); } @@ -1153,97 +1451,68 @@ writeNetpbm(struct pam * const pamP, static void -convertpng(FILE * const ifp, - FILE * const tfp, - struct cmdlineInfo const cmdline, - int * const errorlevelP) { - - png_struct * png_ptr; - png_info * info_ptr; - png_byte ** png_image; +convertpng(FILE * const ifP, + FILE * const tfP, + struct CmdlineInfo const cmdline, + int * const errorLevelP) { + + Reader * rasterReaderP; pngcolor bgColor; - float totalgamma; + GammaCorrection gamma; struct pam pam; + jmp_buf jmpbuf; + struct pngx * pngxP; - *errorlevelP = 0; + *errorLevelP = 0; - read_sig_buf(ifp); - - png_ptr = png_create_read_struct( - PNG_LIBPNG_VER_STRING, - &pngtopnm_jmpbuf_struct, pngtopnm_error_handler, NULL); - if (png_ptr == NULL) - pm_error("cannot allocate main libpng structure (png_ptr)"); - - info_ptr = png_create_info_struct (png_ptr); - if (info_ptr == NULL) - pm_error("cannot allocate LIBPNG structures"); - - if (setjmp(pngtopnm_jmpbuf_struct.jmpbuf)) + if (setjmp(jmpbuf)) pm_error ("setjmp returns error condition"); - png_init_io (png_ptr, ifp); - png_set_sig_bytes (png_ptr, SIG_CHECK_SIZE); - png_read_info (png_ptr, info_ptr); - - allocPngRaster(info_ptr, &png_image); - - if (info_ptr->bit_depth < 8) - png_set_packing (png_ptr); + pngx_create(&pngxP, PNGX_READ, &jmpbuf); - setupGammaCorrection(png_ptr, info_ptr, cmdline.gamma, &totalgamma); - - setupSignificantBits(png_ptr, info_ptr, cmdline.alpha, - &maxval, errorlevelP); - - getBackgroundColor(info_ptr, cmdline.background, totalgamma, maxval, - &bgColor); - - png_read_image(png_ptr, png_image); - png_read_end(png_ptr, info_ptr); + pngx_readStart(pngxP, ifP); if (verbose) - /* Note that some of info_ptr is not defined until png_read_end() - completes. That's because it comes from chunks that are at the - end of the stream. - */ - dump_png_info(info_ptr); + dumpPngInfo(pngxP); if (cmdline.time) - show_time(info_ptr); - if (tfp) - save_text(info_ptr, tfp); + showTime(pngxP); + if (tfP) + saveText(pngxP, tfP); - if (info_ptr->valid & PNG_INFO_pHYs) { - float const r = - (float)info_ptr->x_pixels_per_unit / info_ptr->y_pixels_per_unit; - if (r != 1.0) { - pm_message ("warning - non-square pixels; " - "to fix do a 'pamscale -%cscale %g'", - r < 1.0 ? 'x' : 'y', - r < 1.0 ? 1.0 / r : r ); - *errorlevelP = PNMTOPNG_WARNING_LEVEL; - } - } + warnNonsquarePixels(pngxP, errorLevelP); + setupGammaCorrection(pngxP, cmdline.gammaSpec, cmdline.gamma, &gamma); + + setupSignificantBits(pngxP, cmdline.alpha, errorLevelP); + + getBackgroundColor(pngxP, cmdline.background, gamma, pngxP->maxval, + &bgColor); + pam.size = sizeof(pam); pam.len = PAM_STRUCT_SIZE(tuple_type); pam.file = stdout; pam.plainformat = 0; - pam.height = info_ptr->height; - pam.width = info_ptr->width; - pam.maxval = maxval; + pam.height = pngx_imageHeight(pngxP); + pam.width = pngx_imageWidth(pngxP); + pam.maxval = pngxP->maxval; - determineOutputType(info_ptr, cmdline.alpha, bgColor, maxval, + determineOutputType(pngxP, cmdline.alpha, bgColor, pngxP->maxval, &pam.format, &pam.depth, pam.tuple_type); - writeNetpbm(&pam, info_ptr, png_image, bgColor, cmdline.alpha, totalgamma); + rasterReaderP = cmdline.byrow ? + reader_createRowByRow(pngxP, ifP) : reader_createAllAtOnce(pngxP, ifP); - fflush(stdout); + writeNetpbm(&pam, pngxP, rasterReaderP, bgColor, + cmdline.alpha, gamma); + + reader_destroy(rasterReaderP); - freePngRaster(png_image, info_ptr); + pngx_readEnd(pngxP); - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + fflush(stdout); + + pngx_destroy(pngxP); } @@ -1251,10 +1520,10 @@ convertpng(FILE * const ifp, int main(int argc, const char *argv[]) { - struct cmdlineInfo cmdline; + struct CmdlineInfo cmdline; FILE * ifP; FILE * tfP; - int errorlevel; + int errorLevel; pm_proginit(&argc, argv); @@ -1262,14 +1531,14 @@ main(int argc, const char *argv[]) { verbose = cmdline.verbose; - ifP = pm_openr(cmdline.inputFilespec); + ifP = pm_openr(cmdline.inputFileName); if (cmdline.text) tfP = pm_openw(cmdline.text); else tfP = NULL; - convertpng(ifP, tfP, cmdline, &errorlevel); + convertpng(ifP, tfP, cmdline, &errorLevel); if (tfP) pm_close(tfP); @@ -1277,5 +1546,8 @@ main(int argc, const char *argv[]) { pm_close(ifP); pm_close(stdout); - return errorlevel; + return errorLevel; } + + + diff --git a/converter/other/pngtopnm.c b/converter/other/pngtopnm.c deleted file mode 100644 index a8ea25a7..00000000 --- a/converter/other/pngtopnm.c +++ /dev/null @@ -1,1249 +0,0 @@ -/* -** pngtopnm.c - -** read a Portable Network Graphics file and produce a PNM. -** -** Copyright (C) 1995,1998 by Alexander Lehmann -** and Willem van Schaik -** -** Permission to use, copy, modify, and distribute this software and its -** documentation for any purpose and without fee is hereby granted, provided -** that the above copyright notice appear in all copies and that both that -** copyright notice and this permission notice appear in supporting -** documentation. This software is provided "as is" without express or -** implied warranty. -** -** modeled after giftopnm by David Koblas and -** with lots of bits pasted from libpng.txt by Guy Eric Schalnat -*/ - -#ifndef PNMTOPNG_WARNING_LEVEL -# define PNMTOPNG_WARNING_LEVEL 0 /* use 0 for backward compatibility, */ -#endif /* 2 for warnings (1 == error) */ - -#include -#include -#include -#include /* includes zlib.h and setjmp.h */ -#define VERSION "2.37.4 (5 December 1999) +netpbm" - -#include "pm_c_util.h" -#include "mallocvar.h" -#include "nstring.h" -#include "shhopt.h" -#include "pnm.h" - -/* A hack until we can remove direct access to png_info from the program */ -#if PNG_LIBPNG_VER >= 10400 -#define TRANS_ALPHA trans_alpha -#else -#define TRANS_ALPHA trans -#endif - - -enum alpha_handling {ALPHA_NONE, ALPHA_ONLY, ALPHA_MIX}; - -struct cmdlineInfo { - /* All the information the user supplied in the command line, - in a form easy for the program to use. - */ - const char *inputFilespec; /* '-' if stdin */ - unsigned int verbose; - enum alpha_handling alpha; - const char * background; - float gamma; /* -1.0 means unspecified */ - const char * text; - unsigned int time; -}; - - -typedef struct { -/*---------------------------------------------------------------------------- - A color in a format compatible with the PNG library. - - Note that the PNG library declares types png_color and png_color_16 - which are similar. ------------------------------------------------------------------------------*/ - png_uint_16 r; - png_uint_16 g; - png_uint_16 b; -} pngcolor; - - -static png_uint_16 maxval; -static bool verbose; - - -static void -parseCommandLine(int argc, - const char ** argv, - struct cmdlineInfo * cmdlineP ) { -/*---------------------------------------------------------------------------- - Parse program command line described in Unix standard form by argc - and argv. Return the information in the options as *cmdlineP. - - If command line is internally inconsistent (invalid options, etc.), - issue error message to stderr and abort program. - - Note that the strings we return are stored in the storage that - was passed to us as the argv array. We also trash *argv. ------------------------------------------------------------------------------*/ - optEntry * option_def; - /* Instructions to optParseOptions3 on how to parse our options. - */ - optStruct3 opt; - - unsigned int option_def_index; - - unsigned int alphaSpec, mixSpec, backgroundSpec, gammaSpec, textSpec; - - MALLOCARRAY(option_def, 100); - - option_def_index = 0; /* incremented by OPTENT3 */ - OPTENT3(0, "verbose", OPT_FLAG, NULL, - &cmdlineP->verbose, 0); - OPTENT3(0, "alpha", OPT_FLAG, NULL, - &alphaSpec, 0); - OPTENT3(0, "mix", OPT_FLAG, NULL, - &mixSpec, 0); - OPTENT3(0, "background", OPT_STRING, &cmdlineP->background, - &backgroundSpec, 0); - OPTENT3(0, "gamma", OPT_FLOAT, &cmdlineP->gamma, - &gammaSpec, 0); - OPTENT3(0, "text", OPT_STRING, &cmdlineP->text, - &textSpec, 0); - OPTENT3(0, "time", OPT_FLAG, NULL, - &cmdlineP->time, 0); - - opt.opt_table = option_def; - opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ - opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - - optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); - /* Uses and sets argc, argv, and some of *cmdlineP and others. */ - - - if (alphaSpec && mixSpec) - pm_error("You cannot specify both -alpha and -mix"); - else if (alphaSpec) - cmdlineP->alpha = ALPHA_ONLY; - else if (mixSpec) - cmdlineP->alpha = ALPHA_MIX; - else - cmdlineP->alpha = ALPHA_NONE; - - if (backgroundSpec && !mixSpec) - pm_error("-background is useless without -mix"); - - if (!backgroundSpec) - cmdlineP->background = NULL; - - if (!gammaSpec) - cmdlineP->gamma = -1.0; - - if (!textSpec) - cmdlineP->text = NULL; - - if (argc-1 < 1) - cmdlineP->inputFilespec = "-"; - else if (argc-1 == 1) - cmdlineP->inputFilespec = argv[1]; - else - pm_error("Program takes at most one argument: input file name. " - "you specified %d", argc-1); -} - - - -static void -pngtopnmErrorHandler(png_structp const png_ptr, - png_const_charp const msg) { - - jmp_buf * jmpbufP; - - /* this function, aside from the extra step of retrieving the "error - pointer" (below) and the fact that it exists within the application - rather than within libpng, is essentially identical to libpng's - default error handler. The second point is critical: since both - setjmp() and longjmp() are called from the same code, they are - guaranteed to have compatible notions of how big a jmp_buf is, - regardless of whether _BSD_SOURCE or anything else has (or has not) - been defined. - */ - - pm_message("fatal libpng error: %s", msg); - - jmpbufP = png_get_error_ptr(png_ptr); - - if (!jmpbufP) { - /* we are completely hosed now */ - pm_error("EXTREMELY fatal error: jmpbuf unrecoverable; terminating."); - } - - longjmp(*jmpbufP, 1); -} - - - -struct pngx { - png_structp png_ptr; - png_infop info_ptr; -}; - - - -static void -pngx_createRead(struct pngx ** const pngxPP, - jmp_buf * const jmpbufP) { - - struct pngx * pngxP; - - MALLOCVAR(pngxP); - - if (!pngxP) - pm_error("Failed to allocate memory for PNG object"); - else { - pngxP->png_ptr = png_create_read_struct( - PNG_LIBPNG_VER_STRING, - jmpbufP, pngtopnmErrorHandler, NULL); - - if (!pngxP->png_ptr) - pm_error("cannot allocate main libpng structure (png_ptr)"); - else { - pngxP->info_ptr = png_create_info_struct(pngxP->png_ptr); - - if (!pngxP->info_ptr) - pm_error("cannot allocate libpng info structure (info_ptr)"); - else - *pngxPP = pngxP; - } - } -} - - - -static void -pngx_destroy(struct pngx * const pngxP) { - - png_destroy_read_struct(&pngxP->png_ptr, &pngxP->info_ptr, NULL); - - free(pngxP); -} - - - -static bool -pngx_chunkIsPresent(struct pngx * const pngxP, - uint32_t const chunkType) { - - return png_get_valid(pngxP->png_ptr, pngxP->info_ptr, chunkType); -} - - - -static void -verifyFileIsPng(FILE * const ifP, - size_t * const consumedByteCtP) { - - unsigned char buffer[4]; - size_t bytesRead; - - bytesRead = fread(buffer, 1, sizeof(buffer), ifP); - if (bytesRead != sizeof(buffer)) - pm_error("input file is empty or too short"); - - if (png_sig_cmp(buffer, (png_size_t) 0, (png_size_t) sizeof(buffer)) != 0) - pm_error("input file is not a PNG file " - "(does not have the PNG signature in its first 4 bytes)"); - else - *consumedByteCtP = bytesRead; -} - - - -static unsigned int -computePngLineSize(struct pngx * const pngxP) { - - unsigned int const bytesPerSample = - pngxP->info_ptr->bit_depth == 16 ? 2 : 1; - - unsigned int samplesPerPixel; - - switch (pngxP->info_ptr->color_type) { - case PNG_COLOR_TYPE_GRAY_ALPHA: samplesPerPixel = 2; break; - case PNG_COLOR_TYPE_RGB: samplesPerPixel = 3; break; - case PNG_COLOR_TYPE_RGB_ALPHA: samplesPerPixel = 4; break; - default: samplesPerPixel = 1; - } - - if (UINT_MAX / bytesPerSample / samplesPerPixel < pngxP->info_ptr->width) - pm_error("Width %u of PNG is uncomputably large", - (unsigned int)pngxP->info_ptr->width); - - return pngxP->info_ptr->width * bytesPerSample * samplesPerPixel; -} - - - -static void -allocPngRaster(struct pngx * const pngxP, - png_byte *** const pngImageP) { - - unsigned int const lineSize = computePngLineSize(pngxP); - - png_byte ** pngImage; - unsigned int row; - - MALLOCARRAY(pngImage, pngxP->info_ptr->height); - - if (pngImage == NULL) - pm_error("couldn't allocate space for %u PNG raster rows", - (unsigned int)pngxP->info_ptr->height); - - for (row = 0; row < pngxP->info_ptr->height; ++row) { - MALLOCARRAY(pngImage[row], lineSize); - if (pngImage[row] == NULL) - pm_error("couldn't allocate space for %uth row of PNG raster", - row); - } - *pngImageP = pngImage; -} - - - -static void -freePngRaster(png_byte ** const pngRaster, - struct pngx * const pngxP) { - - unsigned int row; - - for (row = 0; row < pngxP->info_ptr->height; ++row) - free(pngRaster[row]); - - free(pngRaster); -} - - - -static void -readPng(struct pngx * const pngxP, - FILE * const ifP, - png_byte *** const pngRasterP) { - - size_t sigByteCt; - png_byte ** pngRaster; - - verifyFileIsPng(ifP, &sigByteCt); - - /* Declare that we already read the signature bytes */ - png_set_sig_bytes(pngxP->png_ptr, (int)sigByteCt); - - png_init_io(pngxP->png_ptr, ifP); - - png_read_info(pngxP->png_ptr, pngxP->info_ptr); - - allocPngRaster(pngxP, &pngRaster); - - if (pngxP->info_ptr->bit_depth < 8) - png_set_packing(pngxP->png_ptr); - - png_read_image(pngxP->png_ptr, pngRaster); - - png_read_end(pngxP->png_ptr, pngxP->info_ptr); - - /* Note that some of info_ptr is not defined until png_read_end() - completes. That's because it comes from chunks that are at the - end of the stream. - */ - - *pngRasterP = pngRaster; -} - - - -static png_uint_16 -get_png_val(const png_byte ** const pp, - int const bit_depth) { - - png_uint_16 c; - - if (bit_depth == 16) - c = (*((*pp)++)) << 8; - else - c = 0; - - c |= (*((*pp)++)); - - return c; -} - - - -static bool -isGrayscale(pngcolor const color) { - - return color.r == color.g && color.r == color.b; -} - - - -static void -setXel(xel * const xelP, - pngcolor const foreground, - pngcolor const background, - enum alpha_handling const alpha_handling, - png_uint_16 const alpha) { - - if (alpha_handling == ALPHA_ONLY) { - PNM_ASSIGN1(*xelP, alpha); - } else { - if ((alpha_handling == ALPHA_MIX) && (alpha != maxval)) { - double const opacity = (double)alpha / maxval; - double const transparency = 1.0 - opacity; - - pngcolor mix; - - mix.r = foreground.r * opacity + background.r * transparency + 0.5; - mix.g = foreground.g * opacity + background.g * transparency + 0.5; - mix.b = foreground.b * opacity + background.b * transparency + 0.5; - PPM_ASSIGN(*xelP, mix.r, mix.g, mix.b); - } else - PPM_ASSIGN(*xelP, foreground.r, foreground.g, foreground.b); - } -} - - - -static png_uint_16 -gamma_correct(png_uint_16 const v, - float const g) { - - if (g != -1.0) - return (png_uint_16) ROUNDU(pow((double) v / maxval, (1.0 / g)) * - maxval); - else - return v; -} - - - -static bool -iscolor(png_color const c) { - - return c.red != c.green || c.green != c.blue; -} - - - -static void -saveText(struct pngx * const pngxP, - FILE * const tfP) { - - png_info * const info_ptr = pngxP->info_ptr; - - unsigned int i; - - for (i = 0 ; i < info_ptr->num_text; ++i) { - unsigned int j; - j = 0; - - while (info_ptr->text[i].key[j] != '\0' && - info_ptr->text[i].key[j] != ' ') - ++j; - - if (info_ptr->text[i].key[j] != ' ') { - fprintf(tfP, "%s", info_ptr->text[i].key); - for (j = strlen (info_ptr->text[i].key); j < 15; ++j) - putc(' ', tfP); - } else { - fprintf(tfP, "\"%s\"", info_ptr->text[i].key); - for (j = strlen (info_ptr->text[i].key); j < 13; ++j) - putc(' ', tfP); - } - putc(' ', tfP); /* at least one space between key and text */ - - for (j = 0; j < info_ptr->text[i].text_length; ++j) { - putc(info_ptr->text[i].text[j], tfP); - if (info_ptr->text[i].text[j] == '\n') { - unsigned int k; - for (k = 0; k < 16; ++k) - putc(' ', tfP); - } - } - putc('\n', tfP); - } -} - - - -static void -showTime(struct pngx * const pngxP) { - - static const char * const month[] = { - "", "January", "February", "March", "April", "May", "June", - "July", "August", "September", "October", "November", "December" - }; - - if (pngxP->info_ptr->valid & PNG_INFO_tIME) { - if (pngxP->info_ptr->mod_time.month < 1 || - pngxP->info_ptr->mod_time.month >= ARRAY_SIZE(month)) { - pm_message("tIME chunk in PNG input is invalid; " - "modification time of image is unknown. " - "The month value, which should be in the range " - "1-12, is %u", pngxP->info_ptr->mod_time.month); - } else - pm_message("modification time: %02d %s %d %02d:%02d:%02d", - pngxP->info_ptr->mod_time.day, - month[pngxP->info_ptr->mod_time.month], - pngxP->info_ptr->mod_time.year, - pngxP->info_ptr->mod_time.hour, - pngxP->info_ptr->mod_time.minute, - pngxP->info_ptr->mod_time.second); - } -} - - - -static void -dumpPngInfo(struct pngx * const pngxP) { - - png_info * const info_ptr = pngxP->info_ptr; - const char *type_string; - const char *filter_string; - - switch (info_ptr->color_type) { - case PNG_COLOR_TYPE_GRAY: - type_string = "gray"; - break; - - case PNG_COLOR_TYPE_GRAY_ALPHA: - type_string = "gray+alpha"; - break; - - case PNG_COLOR_TYPE_PALETTE: - type_string = "palette"; - break; - - case PNG_COLOR_TYPE_RGB: - type_string = "truecolor"; - break; - - case PNG_COLOR_TYPE_RGB_ALPHA: - type_string = "truecolor+alpha"; - break; - } - - switch (info_ptr->filter_type) { - case PNG_FILTER_TYPE_BASE: - asprintfN(&filter_string, "base filter"); - break; - default: - asprintfN(&filter_string, "unknown filter type %d", - info_ptr->filter_type); - } - - pm_message("reading a %ldw x %ldh image, %d bit%s", - info_ptr->width, info_ptr->height, - info_ptr->bit_depth, info_ptr->bit_depth > 1 ? "s" : ""); - pm_message("%s, %s, %s", - type_string, - info_ptr->interlace_type ? - "Adam7 interlaced" : "not interlaced", - filter_string); - pm_message("background {index, gray, red, green, blue} = " - "{%d, %d, %d, %d, %d}", - info_ptr->background.index, - info_ptr->background.gray, - info_ptr->background.red, - info_ptr->background.green, - info_ptr->background.blue); - - strfree(filter_string); - - if (info_ptr->valid & PNG_INFO_tRNS) - pm_message("tRNS chunk (transparency): %u entries", - info_ptr->num_trans); - else - pm_message("tRNS chunk (transparency): not present"); - - if (info_ptr->valid & PNG_INFO_gAMA) - pm_message("gAMA chunk (image gamma): gamma = %4.2f", info_ptr->gamma); - else - pm_message("gAMA chunk (image gamma): not present"); - - if (info_ptr->valid & PNG_INFO_sBIT) - pm_message("sBIT chunk: present"); - else - pm_message("sBIT chunk: not present"); - - if (info_ptr->valid & PNG_INFO_cHRM) - pm_message("cHRM chunk: present"); - else - pm_message("cHRM chunk: not present"); - - if (info_ptr->valid & PNG_INFO_PLTE) - pm_message("PLTE chunk: %d entries", info_ptr->num_palette); - else - pm_message("PLTE chunk: not present"); - - if (info_ptr->valid & PNG_INFO_bKGD) - pm_message("bKGD chunk: present"); - else - pm_message("bKGD chunk: not present"); - - if (info_ptr->valid & PNG_INFO_PLTE) - pm_message("hIST chunk: present"); - else - pm_message("hIST chunk: not present"); - - if (info_ptr->valid & PNG_INFO_pHYs) - pm_message("pHYs chunk: present"); - else - pm_message("pHYs chunk: not present"); - - if (info_ptr->valid & PNG_INFO_oFFs) - pm_message("oFFs chunk: present"); - else - pm_message("oFFs chunk: not present"); - - if (info_ptr->valid & PNG_INFO_tIME) - pm_message("tIME chunk: present"); - else - pm_message("tIME chunk: not present"); - - if (info_ptr->valid & PNG_INFO_pCAL) - pm_message("pCAL chunk: present"); - else - pm_message("pCAL chunk: not present"); - - if (info_ptr->valid & PNG_INFO_sRGB) - pm_message("sRGB chunk: present"); - else - pm_message("sRGB chunk: not present"); -} - - - -static const png_color_16 * -transColor(struct pngx * const pngxP) { - - png_bytep trans; - int numTrans; - png_color_16 * transColor; - - assert(pngx_chunkIsPresent(pngxP, PNG_INFO_tRNS)); - - png_get_tRNS(pngxP->png_ptr, pngxP->info_ptr, - &trans, &numTrans, &transColor); - - return transColor; -} - - - -static bool -isTransparentColor(pngcolor const color, - struct pngx * const pngxP, - double const totalgamma) { -/*---------------------------------------------------------------------------- - Return TRUE iff pixels of color 'color' are supposed to be transparent - everywhere they occur. Assume it's an RGB image. - - 'color' has been gamma-corrected. ------------------------------------------------------------------------------*/ - bool retval; - - if (pngx_chunkIsPresent(pngxP, PNG_INFO_tRNS)) { - const png_color_16 * const transColorP = transColor(pngxP); - - /* It seems odd that libpng lets you get gamma-corrected pixel - values, but not gamma-corrected transparency or background - values. But as that is the case, we have to gamma-correct - the transparency values. - - Note that because we compare the gamma-corrected values and - there may be many-to-one mapping of uncorrected to corrected - values, more pixels may be transparent than what the user - intended. - - We could fix this by not letting libpng gamma-correct the - pixels, and just do it ourselves. - */ - - switch (pngxP->info_ptr->color_type) { - case PNG_COLOR_TYPE_GRAY: - retval = color.r == gamma_correct(transColorP->gray, totalgamma); - break; - default: - retval = - color.r == gamma_correct(transColorP->red, totalgamma) && - color.g == gamma_correct(transColorP->green, totalgamma) && - color.b == gamma_correct(transColorP->blue, totalgamma); - } - } else - retval = FALSE; - - return retval; -} - - - -static void -setupGammaCorrection(struct pngx * const pngxP, - float const displaygamma, - float * const totalgammaP) { - - if (displaygamma == -1.0) - *totalgammaP = -1.0; - else { - float imageGamma; - if (pngxP->info_ptr->valid & PNG_INFO_gAMA) - imageGamma = pngxP->info_ptr->gamma; - else { - if (verbose) - pm_message("PNG doesn't specify image gamma. Assuming 1.0"); - imageGamma = 1.0; - } - - if (fabs(displaygamma * imageGamma - 1.0) < .01) { - *totalgammaP = -1.0; - if (verbose) - pm_message("image gamma %4.2f matches " - "display gamma %4.2f. No conversion.", - imageGamma, displaygamma); - } else { - png_set_gamma(pngxP->png_ptr, displaygamma, imageGamma); - *totalgammaP = imageGamma * displaygamma; - /* in case of gamma-corrections, sBIT's as in the - PNG-file are not valid anymore - */ - pngxP->info_ptr->valid &= ~PNG_INFO_sBIT; - if (verbose) - pm_message("image gamma is %4.2f, " - "converted for display gamma of %4.2f", - imageGamma, displaygamma); - } - } -} - - - -static bool -paletteHasPartialTransparency(png_info * const info_ptr) { - - bool retval; - - if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { - if (info_ptr->valid & PNG_INFO_tRNS) { - bool foundGray; - unsigned int i; - - for (i = 0, foundGray = FALSE; - i < info_ptr->num_trans && !foundGray; - ++i) { - if (info_ptr->TRANS_ALPHA[i] != 0 && - info_ptr->TRANS_ALPHA[i] != maxval) { - foundGray = TRUE; - } - } - retval = foundGray; - } else - retval = FALSE; - } else - retval = FALSE; - - return retval; -} - - - -static void -setupSignificantBits(struct pngx * const pngxP, - enum alpha_handling const alpha, - png_uint_16 * const maxvalP, - int * const errorLevelP) { -/*---------------------------------------------------------------------------- - Figure out what maxval would best express the information in the PNG - described by *pngxP, with 'alpha' telling which information in the PNG we - care about (image or alpha mask). - - Return the result as *maxvalP. ------------------------------------------------------------------------------*/ - png_info * const info_ptr = pngxP->info_ptr; - - /* Initial assumption of maxval */ - if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { - if (alpha == ALPHA_ONLY) { - if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY || - info_ptr->color_type == PNG_COLOR_TYPE_RGB) - /* The alpha mask will be all opaque, so maxval 1 is plenty */ - *maxvalP = 1; - else if (paletteHasPartialTransparency(info_ptr)) - /* Use same maxval as PNG transparency palette for simplicity*/ - *maxvalP = 255; - else - /* A common case, so we conserve bits */ - *maxvalP = 1; - } else - /* Use same maxval as PNG palette for simplicity */ - *maxvalP = 255; - } else { - *maxvalP = (1l << info_ptr->bit_depth) - 1; - } - - /* sBIT handling is very tricky. If we are extracting only the - image, we can use the sBIT info for grayscale and color images, - if the three values agree. If we extract the transparency/alpha - mask, sBIT is irrelevant for trans and valid for alpha. If we - mix both, the multiplication may result in values that require - the normal bit depth, so we will use the sBIT info only for - transparency, if we know that only solid and fully transparent - is used - */ - - if (info_ptr->valid & PNG_INFO_sBIT) { - switch (alpha) { - case ALPHA_MIX: - if (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || - info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - break; - if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE && - (info_ptr->valid & PNG_INFO_tRNS)) { - - bool trans_mix; - unsigned int i; - trans_mix = TRUE; - for (i = 0; i < info_ptr->num_trans; ++i) - if (info_ptr->TRANS_ALPHA[i] != 0 && info_ptr->TRANS_ALPHA[i] != 255) { - trans_mix = FALSE; - break; - } - if (!trans_mix) - break; - } - - /* else fall though to normal case */ - - case ALPHA_NONE: - if ((info_ptr->color_type == PNG_COLOR_TYPE_PALETTE || - info_ptr->color_type == PNG_COLOR_TYPE_RGB || - info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) && - (info_ptr->sig_bit.red != info_ptr->sig_bit.green || - info_ptr->sig_bit.red != info_ptr->sig_bit.blue) && - alpha == ALPHA_NONE) { - pm_message("This program cannot handle " - "different bit depths for color channels"); - pm_message("writing file with %d bit resolution", - info_ptr->bit_depth); - *errorLevelP = PNMTOPNG_WARNING_LEVEL; - } else { - if ((info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) && - (info_ptr->sig_bit.red < 255)) { - unsigned int i; - for (i = 0; i < info_ptr->num_palette; ++i) { - info_ptr->palette[i].red >>= - (8 - info_ptr->sig_bit.red); - info_ptr->palette[i].green >>= - (8 - info_ptr->sig_bit.green); - info_ptr->palette[i].blue >>= - (8 - info_ptr->sig_bit.blue); - } - *maxvalP = (1l << info_ptr->sig_bit.red) - 1; - if (verbose) - pm_message ("image has fewer significant bits, " - "writing file with %d bits per channel", - info_ptr->sig_bit.red); - } else - if ((info_ptr->color_type == PNG_COLOR_TYPE_RGB || - info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) && - (info_ptr->sig_bit.red < info_ptr->bit_depth)) { - png_set_shift(pngxP->png_ptr, &(info_ptr->sig_bit)); - *maxvalP = (1l << info_ptr->sig_bit.red) - 1; - if (verbose) - pm_message("image has fewer significant bits, " - "writing file with %d " - "bits per channel", - info_ptr->sig_bit.red); - } else - if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY || - info_ptr->color_type == - PNG_COLOR_TYPE_GRAY_ALPHA) && - (info_ptr->sig_bit.gray < info_ptr->bit_depth)) { - png_set_shift(pngxP->png_ptr, &info_ptr->sig_bit); - *maxvalP = (1l << info_ptr->sig_bit.gray) - 1; - if (verbose) - pm_message("image has fewer significant bits, " - "writing file with %d bits", - info_ptr->sig_bit.gray); - } - } - break; - - case ALPHA_ONLY: - if ((info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || - info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) && - (info_ptr->sig_bit.gray < info_ptr->bit_depth)) { - png_set_shift(pngxP->png_ptr, &info_ptr->sig_bit); - if (verbose) - pm_message ("image has fewer significant bits, " - "writing file with %d bits", - info_ptr->sig_bit.alpha); - *maxvalP = (1l << info_ptr->sig_bit.alpha) - 1; - } - break; - - } - } -} - - - -static bool -imageHasColor(struct pngx * const pngxP) { - - bool retval; - - if (pngxP->info_ptr->color_type == PNG_COLOR_TYPE_GRAY || - pngxP->info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - - retval = FALSE; - else if (pngxP->info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { - bool foundColor; - unsigned int i; - - for (i = 0, foundColor = FALSE; - i < pngxP->info_ptr->num_palette && !foundColor; - ++i) { - if (iscolor(pngxP->info_ptr->palette[i])) - foundColor = TRUE; - } - retval = foundColor; - } else - retval = TRUE; - - return retval; -} - - - -static void -determineOutputType(struct pngx * const pngxP, - enum alpha_handling const alphaHandling, - pngcolor const bgColor, - xelval const maxval, - int * const pnmTypeP) { - - if (alphaHandling != ALPHA_ONLY && - (imageHasColor(pngxP) || !isGrayscale(bgColor))) - *pnmTypeP = PPM_TYPE; - else { - if (maxval > 1) - *pnmTypeP = PGM_TYPE; - else - *pnmTypeP = PBM_TYPE; - } -} - - - -static void -getBackgroundColor(struct pngx * const pngxP, - const char * const requestedColor, - float const totalgamma, - xelval const maxval, - pngcolor * const bgColorP) { -/*---------------------------------------------------------------------------- - Figure out what the background color should be. If the user requested - a particular color ('requestedColor' not null), that's the one. - Otherwise, if the PNG specifies a background color, that's the one. - And otherwise, it's white. ------------------------------------------------------------------------------*/ - if (requestedColor) { - /* Background was specified from the command-line; we always - use that. I chose to do no gamma-correction in this case; - which is a bit arbitrary. - */ - pixel const backcolor = ppm_parsecolor(requestedColor, maxval); - - bgColorP->r = PPM_GETR(backcolor); - bgColorP->g = PPM_GETG(backcolor); - bgColorP->b = PPM_GETB(backcolor); - - } else if (pngxP->info_ptr->valid & PNG_INFO_bKGD) { - /* didn't manage to get libpng to work (bugs?) concerning background - processing, therefore we do our own. - */ - switch (pngxP->info_ptr->color_type) { - case PNG_COLOR_TYPE_GRAY: - case PNG_COLOR_TYPE_GRAY_ALPHA: - bgColorP->r = bgColorP->g = bgColorP->b = - gamma_correct(pngxP->info_ptr->background.gray, totalgamma); - break; - case PNG_COLOR_TYPE_PALETTE: { - png_color const rawBgcolor = - pngxP->info_ptr->palette[pngxP->info_ptr->background.index]; - bgColorP->r = gamma_correct(rawBgcolor.red, totalgamma); - bgColorP->g = gamma_correct(rawBgcolor.green, totalgamma); - bgColorP->b = gamma_correct(rawBgcolor.blue, totalgamma); - } - break; - case PNG_COLOR_TYPE_RGB: - case PNG_COLOR_TYPE_RGB_ALPHA: { - png_color_16 const rawBgcolor = pngxP->info_ptr->background; - - bgColorP->r = gamma_correct(rawBgcolor.red, totalgamma); - bgColorP->g = gamma_correct(rawBgcolor.green, totalgamma); - bgColorP->b = gamma_correct(rawBgcolor.blue, totalgamma); - } - break; - } - } else - /* when no background given, we use white [from version 2.37] */ - bgColorP->r = bgColorP->g = bgColorP->b = maxval; -} - - - -static void -warnNonsquarePixels(struct pngx * const pngxP, - int * const errorLevelP) { - - if (pngxP->info_ptr->valid & PNG_INFO_pHYs) { - float const r = - (float)pngxP->info_ptr->x_pixels_per_unit / - pngxP->info_ptr->y_pixels_per_unit; - - if (r != 1.0) { - pm_message ("warning - non-square pixels; " - "to fix do a 'pamscale -%cscale %g'", - r < 1.0 ? 'x' : 'y', - r < 1.0 ? 1.0 / r : r ); - *errorLevelP = PNMTOPNG_WARNING_LEVEL; - } - } -} - - - -#define GET_PNG_VAL(p) get_png_val(&(p), pngxP->info_ptr->bit_depth) - - - -static void -makeXelRow(xel * const xelrow, - xelval const maxval, - int const pnmType, - struct pngx * const pngxP, - const png_byte * const pngRasterRow, - pngcolor const bgColor, - enum alpha_handling const alphaHandling, - double const totalgamma) { - - const png_byte * pngPixelP; - unsigned int col; - - pngPixelP = &pngRasterRow[0]; /* initial value */ - for (col = 0; col < pngxP->info_ptr->width; ++col) { - switch (pngxP->info_ptr->color_type) { - case PNG_COLOR_TYPE_GRAY: { - pngcolor fgColor; - fgColor.r = fgColor.g = fgColor.b = GET_PNG_VAL(pngPixelP); - setXel(&xelrow[col], fgColor, bgColor, alphaHandling, - isTransparentColor(fgColor, pngxP, totalgamma) ? - 0 : maxval); - } - break; - - case PNG_COLOR_TYPE_GRAY_ALPHA: { - pngcolor fgColor; - png_uint_16 alpha; - - fgColor.r = fgColor.g = fgColor.b = GET_PNG_VAL(pngPixelP); - alpha = GET_PNG_VAL(pngPixelP); - setXel(&xelrow[col], fgColor, bgColor, alphaHandling, alpha); - } - break; - - case PNG_COLOR_TYPE_PALETTE: { - png_uint_16 const index = GET_PNG_VAL(pngPixelP); - png_color const paletteColor = pngxP->info_ptr->palette[index]; - - pngcolor fgColor; - - fgColor.r = paletteColor.red; - fgColor.g = paletteColor.green; - fgColor.b = paletteColor.blue; - - setXel(&xelrow[col], fgColor, bgColor, alphaHandling, - (pngxP->info_ptr->valid & PNG_INFO_tRNS) && - index < pngxP->info_ptr->num_trans ? - pngxP->info_ptr->TRANS_ALPHA[index] : maxval); - } - break; - - case PNG_COLOR_TYPE_RGB: { - pngcolor fgColor; - - fgColor.r = GET_PNG_VAL(pngPixelP); - fgColor.g = GET_PNG_VAL(pngPixelP); - fgColor.b = GET_PNG_VAL(pngPixelP); - setXel(&xelrow[col], fgColor, bgColor, alphaHandling, - isTransparentColor(fgColor, pngxP, totalgamma) ? - 0 : maxval); - } - break; - - case PNG_COLOR_TYPE_RGB_ALPHA: { - pngcolor fgColor; - png_uint_16 alpha; - - fgColor.r = GET_PNG_VAL(pngPixelP); - fgColor.g = GET_PNG_VAL(pngPixelP); - fgColor.b = GET_PNG_VAL(pngPixelP); - alpha = GET_PNG_VAL(pngPixelP); - setXel(&xelrow[col], fgColor, bgColor, alphaHandling, alpha); - } - break; - - default: - pm_error("unknown PNG color type: %d", - pngxP->info_ptr->color_type); - } - } -} - - - -static void -writePnm(FILE * const ofP, - xelval const maxval, - int const pnmType, - struct pngx * const pngxP, - png_byte ** const pngRaster, - pngcolor const bgColor, - enum alpha_handling const alphaHandling, - double const totalgamma) { -/*---------------------------------------------------------------------------- - Write a PNM of either the image or the alpha mask, according to - 'alphaHandling' that is in the PNG image described by *pngxP and - pngRaster[][]. - - 'pnmType' and 'maxval' are of the output image. - - Use background color 'bgColor' in the output if the PNG is such that a - background color is needed. ------------------------------------------------------------------------------*/ - int const plainFalse = 0; - - xel * xelrow; - unsigned int row; - - if (verbose) - pm_message("writing a %s file (maxval=%u)", - pnmType == PBM_TYPE ? "PBM" : - pnmType == PGM_TYPE ? "PGM" : - pnmType == PPM_TYPE ? "PPM" : - "UNKNOWN!", - maxval); - - xelrow = pnm_allocrow(pngxP->info_ptr->width); - - pnm_writepnminit(stdout, - pngxP->info_ptr->width, pngxP->info_ptr->height, maxval, - pnmType, plainFalse); - - for (row = 0; row < pngxP->info_ptr->height; ++row) { - makeXelRow(xelrow, maxval, pnmType, pngxP, pngRaster[row], bgColor, - alphaHandling, totalgamma); - - pnm_writepnmrow(ofP, xelrow, pngxP->info_ptr->width, maxval, - pnmType, plainFalse); - } - pnm_freerow (xelrow); -} - - - -static void -convertpng(FILE * const ifP, - FILE * const tfP, - struct cmdlineInfo const cmdline, - int * const errorLevelP) { - - png_byte ** pngRaster; - int pnmType; - pngcolor bgColor; - float totalgamma; - jmp_buf jmpbuf; - struct pngx * pngxP; - - *errorLevelP = 0; - - if (setjmp(jmpbuf)) - pm_error ("setjmp returns error condition"); - - pngx_createRead(&pngxP, &jmpbuf); - - readPng(pngxP, ifP, &pngRaster); - - if (verbose) - dumpPngInfo(pngxP); - - if (cmdline.time) - showTime(pngxP); - if (tfP) - saveText(pngxP, tfP); - - warnNonsquarePixels(pngxP, errorLevelP); - - setupGammaCorrection(pngxP, cmdline.gamma, &totalgamma); - - setupSignificantBits(pngxP, cmdline.alpha, &maxval, errorLevelP); - - getBackgroundColor(pngxP, cmdline.background, totalgamma, maxval, - &bgColor); - - determineOutputType(pngxP, cmdline.alpha, bgColor, maxval, &pnmType); - - writePnm(stdout, maxval, pnmType, pngxP, pngRaster, bgColor, - cmdline.alpha, totalgamma); - - fflush(stdout); - - freePngRaster(pngRaster, pngxP); - - pngx_destroy(pngxP); -} - - - -int -main(int argc, const char *argv[]) { - - struct cmdlineInfo cmdline; - FILE * ifP; - FILE * tfP; - int errorLevel; - - pm_proginit(&argc, argv); - - parseCommandLine(argc, argv, &cmdline); - - verbose = cmdline.verbose; - - ifP = pm_openr(cmdline.inputFilespec); - - if (cmdline.text) - tfP = pm_openw(cmdline.text); - else - tfP = NULL; - - convertpng(ifP, tfP, cmdline, &errorLevel); - - if (tfP) - pm_close(tfP); - - pm_close(ifP); - pm_close(stdout); - - return errorLevel; -} diff --git a/converter/other/pngtxt.c b/converter/other/pngtxt.c index bbbec099..e02ee227 100644 --- a/converter/other/pngtxt.c +++ b/converter/other/pngtxt.c @@ -1,122 +1,251 @@ +#define HAVE_PNGLIB_WITH_ITXT 0 + #include #include #include + #include +#include "mallocvar.h" #include "nstring.h" +#include "pngx.h" #include "pngtxt.h" #include "pm.h" -#include "mallocvar.h" - -#define MAXCOMMENTS 256 static void -readOffKey(char const textline[], - unsigned int const lineLength, - unsigned int * const cursorP, - char ** const keyP) { +readToken(char const textline[], + unsigned int const lineLength, + unsigned int * const cursorP, + const char ** const tokenP) { +/*---------------------------------------------------------------------------- + Read a token from 'textline' (whose length is 'lineLength'), assuming the + cursor is positioned to it now, leaving the cursor positioned after it. - /* Get the comment key */ + Tokens are delimited by white space. We don't skip any white space before + or after the token. Ergo, if we are positioned to white space right now, + the token we read is a null string. +-----------------------------------------------------------------------------*/ + char * tokenBuffer; char * cp; unsigned int cursor; cursor = *cursorP; - MALLOCARRAY(cp, lineLength + 1); /* leave room for terminating NUL */ - if (cp == NULL) - pm_error("Unable to allocate memory for text chunks"); - - *keyP = cp; + MALLOCARRAY(tokenBuffer, lineLength + 1); + /* leave room for terminating NUL */ + if (tokenBuffer == NULL) + pm_error("Unable to allocate memory for a %u-character " + "text string file line", lineLength); + + cp = &tokenBuffer[0]; /* initial value */ if (textline[0] == '"') { - ++cursor; /* skip past opening " */ + ++cursor; /* skip past opening quotation mark */ while (textline[cursor] != '"') { - if (textline[cursor] == '\0') { - *cp = '\0'; - pm_error("Invalid comment file format: keyword contains " + if (cursor >= lineLength) + pm_error("Invalid text string file format. Line ends in " + "the middle of a quoted token. Text at the end of " + "the line is '%s'", tokenBuffer); + if (textline[cursor] == '\0') + pm_error("Invalid text string file format: Token contains " "a NUL character. Text leading up to the NUL " - "character is '%s'", *keyP); - } + "character is '%s'", tokenBuffer); *(cp++) = textline[cursor++]; } - ++cursor; /* skip past closing " */ + ++cursor; /* skip past closing quotation mark */ } else { - while (cursor < lineLength && - textline[cursor] != ' ' && textline[cursor] != '\t' && - textline[cursor] != '\0') + while ((cursor < lineLength) && + (textline[cursor] != ' ') && (textline[cursor] != '\t')) { + + if (textline[cursor] == '\0') + pm_error("Invalid text string file format: Token contains " + "a NUL character. Text leading up to the NUL " + "character is '%s'", tokenBuffer); *(cp++) = textline[cursor++]; + } } *cp++ = '\0'; *cursorP = cursor; + + *tokenP = tokenBuffer; } static void -startComment(struct png_text_struct * const commentP, - char const textline[], - unsigned int const lineLength, - bool const compressed) { +skipWhiteSpace(char const textline[], + unsigned int const lineLength, + unsigned int * const cursorP) { /*---------------------------------------------------------------------------- - Assuming 'textline' is the first line of a comment in a comment file, - put the information from it in the comment record *commentP. - Use the text on this line as the comment text, even though the true - comment text may include text from subsequent continuation lines as - well. + Move *cursorP past white space (or, for some reason, NUL characters), + in 'textline', which is 'lineLength' long. +-----------------------------------------------------------------------------*/ + unsigned int cursor; - 'textline' is not NUL-terminated. Its length is 'lineLength', and - it is at least one character long. 'textline' does not contain a - newline character. + cursor = *cursorP; /* initial value */ + + while (cursor < lineLength && + (textline[cursor] == ' ' || textline[cursor] == '\t' || + textline[cursor] == '\0')) + ++cursor; - 'compressed' means the comment text is compressed. + *cursorP = cursor; +} + + + +static void +readTextString(char const textline[], + unsigned int const lineLength, + unsigned int const startPos, + png_charp * const textStringP, + png_size_t * const textStringLengthP) { +/*---------------------------------------------------------------------------- + Extract the text string at 'startPos' in the buffer 'textline', whose + length is 'lineLength'. Return it in newly malloced storage with a + pointer to that storage as 'textString' and the size of the text as + *textStringLengthP. -----------------------------------------------------------------------------*/ - unsigned int cursor; + char * cp; + + MALLOCARRAY(cp, lineLength + 1); /* incl '\0' */ + if (!cp) + pm_error("Unable to allocate memory for text chunks"); + + memcpy(cp, textline + startPos, lineLength - startPos); + cp[lineLength - startPos] = '\0'; /* for safety - not part of text */ + *textStringP = cp; + *textStringLengthP = lineLength - startPos; +} + - /* the following is a not that accurate check on Author or Title */ - if ((!compressed) || (textline[0] == 'A') || (textline[0] == 'T')) - commentP->compression = -1; - else - commentP->compression = 0; + +static void +startTextChunkEngl(png_text * const textChunkP, + char const textline[], + unsigned int const lineLength, + bool const isCompressed, + bool const verbose) { +/*---------------------------------------------------------------------------- + Assuming 'textline' is the first line of an entry in an English text + string file, put the information from it in the comment record *textChunkP. + Use the text on this line as the comment text, even though the true text + string may include text from subsequent continuation lines as well. + + 'textline' is not NUL-terminated. Its length is 'lineLength', and it is at + least one character long. 'textline' does not contain a newline character. + + 'isCompressed' means it is a compressed text chunk. +-----------------------------------------------------------------------------*/ + unsigned int cursor; cursor = 0; - readOffKey(textline, lineLength, &cursor, &commentP->key); + { + const char * key; + + readToken(textline, lineLength, &cursor, &key); + + pngx_setTextKey(textChunkP, key); + + pm_strfree(key); + } + + skipWhiteSpace(textline, lineLength, &cursor); + + pngx_setTextLang(textChunkP, NULL); + + readTextString(textline, lineLength, cursor, &textChunkP->text, + &textChunkP->text_length); + + textChunkP->compression = + isCompressed ? PNG_TEXT_COMPRESSION_zTXt : PNG_TEXT_COMPRESSION_NONE; +} + + + +static void +startTextChunkIntl(png_text * const textChunkP, + char const textline[], + unsigned int const lineLength, + bool const isCompressed, + bool const verbose) { +/*---------------------------------------------------------------------------- + Assuming 'textline' is the first line of an entry in an international (not + English) text string file, put the information from it in the text chunk + *textChunkP. Use the text on this line as the text string, even though the + true text string may include text from subsequent continuation lines as + well. + + 'textline' is not NUL-terminated. Its length is 'lineLength', and it is at + least one character long. 'textline' does not contain a newline character. + + 'isInternational' means it is an international (i.e. non-English) text + chunk. + + Leave the language attribute (textChunkP->lang) unset. +-----------------------------------------------------------------------------*/ + unsigned int cursor; + + cursor = 0; /* Initial value */ - /* skip over delimiters between key and comment text */ - while (cursor < lineLength && - (textline[cursor] == ' ' || textline[cursor] == '\t' || - textline[cursor] == '\0')) - ++cursor; - { - /* Get the first line of the comment text */ - unsigned int const startPos = cursor; - char *cp; - - MALLOCARRAY(cp, lineLength+1); /* leave room for safety NUL */ - if (!cp) - pm_error("Unable to allocate memory for text chunks"); - - memcpy(cp, textline + startPos, lineLength - startPos); - cp[lineLength - startPos] = '\0'; /* for safety - not part of text */ - commentP->text = cp; - commentP->text_length = lineLength - startPos; + const char * key; + + readToken(textline, lineLength, &cursor, &key); + + pngx_setTextKey(textChunkP, key); + + pm_strfree(key); } + + skipWhiteSpace(textline, lineLength, &cursor); + + { + const char * isoLang; + + readToken(textline, lineLength, &cursor, &isoLang); + + pngx_setTextLang(textChunkP, isoLang); + + pm_strfree(isoLang); + } + + skipWhiteSpace(textline, lineLength, &cursor); + + { + const char * langKey; + + readToken(textline, lineLength, &cursor, &langKey); + + pngx_setTextLangKey(textChunkP, langKey); + + pm_strfree(langKey); + } + + skipWhiteSpace(textline, lineLength, &cursor); + + /* Beginning of text string (continuation lines may follow) */ + readTextString(textline, lineLength, cursor, &textChunkP->text, + &textChunkP->text_length); + + textChunkP->compression = + isCompressed ? PNG_ITXT_COMPRESSION_zTXt :PNG_ITXT_COMPRESSION_NONE; } static void -continueComment(struct png_text_struct * const commentP, - char const textline[], - unsigned int const lineLength) { +continueTextString(png_text * const textChunkP, + char const textline[], + unsigned int const lineLength) { /*---------------------------------------------------------------------------- - Update the comment record *commentP by adding to it the text - from textline[], which is a continuation line from a comment file. + Update the text chunk *textChunkP by adding to it the text from + textline[], which is a continuation line from a text string file. 'textline' is not NUL-terminated. Its length is 'lineLength', and it is at least one character long. 'textline' does not contain a @@ -125,29 +254,27 @@ continueComment(struct png_text_struct * const commentP, unsigned int cursor; /* cursor into textline[] */ unsigned int const newTextLength = - commentP->text_length + lineLength + 1 + 1; + textChunkP->text_length + lineLength + 1 + 1; - REALLOCARRAY(commentP->text, newTextLength); + REALLOCARRAY(textChunkP->text, newTextLength); - if (commentP->text == NULL) - pm_error("Unable to allocate %u bytes of memory for comment chunk", + if (textChunkP->text == NULL) + pm_error("Unable to allocate %u bytes of memory for text string", newTextLength); - commentP->text[commentP->text_length++] = '\n'; + textChunkP->text[textChunkP->text_length++] = '\n'; - /* Skip past leading delimiter characters in file line */ - cursor = 0; - while (textline[cursor] == ' ' || textline[cursor] == '\t' || - textline[cursor] == '\0') - ++cursor; + cursor = 0; + + skipWhiteSpace(textline, lineLength, &cursor); - memcpy(commentP->text + commentP->text_length, + memcpy(textChunkP->text + textChunkP->text_length, textline + cursor, lineLength - cursor); - commentP->text_length += lineLength - cursor; + textChunkP->text_length += lineLength - cursor; - commentP->text[commentP->text_length] = '\0'; /* for safety */ + textChunkP->text[textChunkP->text_length] = '\0'; /* for safety */ } @@ -171,16 +298,16 @@ getFileLine(FILE * const fileP, -----------------------------------------------------------------------------*/ char * textline; /* malloc'ed */ unsigned int cursor; /* cursor into textline[] */ - unsigned int allocated; + unsigned int allocatedSz; /* The number of characters of space that are allocated for 'textline' */ bool eol; bool gotSomething; - allocated = 128; /* initial value */ + allocatedSz = 128; /* initial value */ - MALLOCARRAY(textline, allocated); + MALLOCARRAY(textline, allocatedSz); if (textline == NULL) pm_error("Unable to allocate buffer to read a line of a file."); @@ -197,9 +324,10 @@ getFileLine(FILE * const fileP, if (c == '\n' || c == EOF) eol = TRUE; else { - if (cursor > allocated - 1 - 1) { /* leave space for safety NUL */ - allocated *= 2; - REALLOCARRAY(textline, allocated); + /* leave space for safety NUL */ + if (cursor > allocatedSz - 1 - 1) { + allocatedSz *= 2; + REALLOCARRAY(textline, allocatedSz); if (textline == NULL) pm_error("Unable to allocate buffer to read a line of " "a file."); @@ -222,93 +350,153 @@ getFileLine(FILE * const fileP, static void handleArrayAllocation(png_text ** const arrayP, - unsigned int * const allocatedCommentsP, - unsigned int const commentIdx) { + unsigned int * const allocatedChunkCtP, + unsigned int const chunkIdx) { - if (commentIdx >= *allocatedCommentsP) { - *allocatedCommentsP *= 2; - REALLOCARRAY(*arrayP, *allocatedCommentsP); + if (chunkIdx >= *allocatedChunkCtP) { + *allocatedChunkCtP *= 2; + REALLOCARRAY(*arrayP, *allocatedChunkCtP); if (*arrayP == NULL) - pm_error("unable to allocate memory for comment array"); + pm_error("unable to allocate memory for %u text chunks", + *allocatedChunkCtP); } } + +static bool +isContinuationLine(const char * const line) { +/*---------------------------------------------------------------------------- + Text line 'line', if it is from a text string file, is a continuation of a + text string started in an earlier line. + + What identifies a line as a continuation line is that it starts with + a space or tab. +-----------------------------------------------------------------------------*/ + return line[0] == ' ' || line[0] == '\t'; +} + + + +static void +reportChunkCt(bool const ztxt, + bool const itxt, + unsigned int const chunkCt) { + + const char * chunkType; + + if (itxt) + chunkType = "iTXt"; + else { + if (ztxt) + chunkType = "zTXt"; + else + chunkType = "tEXt"; + } + + pm_message("Writing %u %s chunks", chunkCt, chunkType); +} + + + /****************************************************************************** EXTERNAL SUBROUTINES ******************************************************************************/ void -pnmpng_read_text (png_info * const info_ptr, - FILE * const tfp, - bool const ztxt, - bool const verbose) { - - const char * textline; - unsigned int lineLength; - unsigned int commentIdx; - bool noCommentsYet; +pngtxt_addChunk(struct pngx * const pngxP, + FILE * const tfP, + bool const ztxt, + bool const itxt, + bool const verbose) { +/*---------------------------------------------------------------------------- + Add text chunks (tEXt, zTXt, or iTXt) to the PNG image represented by + *pngxP as directed by file *tfP. + + 'itxt' means to make them international language (iTXt) chunks. Otherwise + they are either tEXt or zTXt chunks, depending upon 'ztxt'. + + 'ztxt' means to make the text compressed. If the chunks are not + international (i.e. 'itxt' is false), this means the chunks are zTXt chunks + instead of 'tEXt' chunks. +-----------------------------------------------------------------------------*/ + bool noChunksYet; bool eof; - unsigned int allocatedComments; - /* Number of entries currently allocated for the info_ptr->text - array - */ + png_textp text; /* An array; one chunk per element */ + unsigned int chunkCt; + /* Number of chunks we have completed in the 'text' array */ + unsigned int allocatedChunkCt; + /* Number of entries currently allocated for the PNG text array */ + + /* In an international text string file, the first entry tells the + language of all of the chunks, by having key 'Language'. + */ - allocatedComments = 256; /* initial value */ + allocatedChunkCt = 256; /* initial value */ - MALLOCARRAY(info_ptr->text, allocatedComments); - if (info_ptr->text == NULL) - pm_error("unable to allocate memory for comment array"); + MALLOCARRAY(text, allocatedChunkCt); + if (text == NULL) + pm_error("unable to allocate memory for text chunk array"); - commentIdx = 0; - noCommentsYet = TRUE; - - eof = FALSE; - while (!eof) { - getFileLine(tfp, &textline, &lineLength); + for (chunkCt = 0, noChunksYet = true, eof = false; !eof; ) { + const char * textline; + unsigned int lineLength; + + getFileLine(tfP, &textline, &lineLength); if (textline == NULL) - eof = TRUE; + eof = true; else { if (lineLength == 0) { /* skip this empty line */ } else { - handleArrayAllocation(&info_ptr->text, &allocatedComments, - commentIdx); - if ((textline[0] != ' ') && (textline[0] != '\t')) { - /* Line doesn't start with white space, which - means it starts a new comment. - */ - if (noCommentsYet) { - /* No previous comment to move past */ - } else - ++commentIdx; - noCommentsYet = FALSE; + handleArrayAllocation(&text, &allocatedChunkCt, chunkCt); + + if (!isContinuationLine(textline)) { + png_text * textChunkP; - startComment(&info_ptr->text[commentIdx], - textline, lineLength, ztxt); + if (noChunksYet) { + /* No previous chunk to move past */ + } else + ++chunkCt; + noChunksYet = false; + + textChunkP = &text[chunkCt]; + + if (itxt) + startTextChunkIntl(textChunkP, + textline, lineLength, ztxt, + verbose); + else + startTextChunkEngl(textChunkP, + textline, lineLength, ztxt, + verbose); } else { + png_text * const textChunkP = &text[chunkCt]; + /* Line starts with whitespace, which means it is - a continuation of the current comment. + a continuation of the current text string. */ - if (noCommentsYet) - pm_error("Invalid comment file format: " + if (noChunksYet) + pm_error("Invalid text string file format: " "first line is a continuation line! " "(It starts with whitespace)"); - continueComment(&info_ptr->text[commentIdx], - textline, lineLength); + continueTextString(textChunkP, textline, lineLength); } } - strfree(textline); + pm_strfree(textline); } - } - if (noCommentsYet) - info_ptr->num_text = 0; - else - info_ptr->num_text = commentIdx + 1; + } + if (!noChunksYet) + ++chunkCt; if (verbose) - pm_message("%d comments placed in text chunk", info_ptr->num_text); + reportChunkCt(ztxt, itxt, chunkCt); + + if (chunkCt > 0) + pngx_setText(pngxP, text, chunkCt); + + free(text); } diff --git a/converter/other/pngtxt.h b/converter/other/pngtxt.h index ae7fe2c4..3e6ff2af 100644 --- a/converter/other/pngtxt.h +++ b/converter/other/pngtxt.h @@ -1,13 +1,17 @@ #ifndef PNGTXT_H_INCLUDED #define PNGTXT_H_INCLUDED -#include "pm_c_util.h" +#include +#include #include +struct pngx; + void -pnmpng_read_text (png_info * const info_ptr, - FILE * const tfp, - bool const ztxt, - bool const verbose); +pngtxt_addChunk(struct pngx * const pngxP, + FILE * const tfp, + bool const ztxt, + bool const itxt, + bool const verbose); #endif diff --git a/converter/other/pngx.c b/converter/other/pngx.c new file mode 100644 index 00000000..a5171066 --- /dev/null +++ b/converter/other/pngx.c @@ -0,0 +1,733 @@ +#include +#include +#include "pm_c_util.h" +#include "mallocvar.h" +#include "nstring.h" +#include "pm.h" + +/* defines (or doesn't) PNG_iTXt_SUPPORTED to tell us whether libpng + has facilities related to PNG iTXt chunks. +*/ +#ifdef PNG_iTXt_SUPPORTED + #define HAVE_PNGLIB_WITH_ITXT 1 +#else + #define HAVE_PNGLIB_WITH_ITXT 0 +#endif + +#include "pngx.h" + + +static void +errorHandler(png_structp const png_ptr, + png_const_charp const msg) { + + jmp_buf * jmpbufP; + + /* this function, aside from the extra step of retrieving the "error + pointer" (below) and the fact that it exists within the application + rather than within libpng, is essentially identical to libpng's + default error handler. The second point is critical: since both + setjmp() and longjmp() are called from the same code, they are + guaranteed to have compatible notions of how big a jmp_buf is, + regardless of whether _BSD_SOURCE or anything else has (or has not) + been defined. + */ + + pm_message("fatal libpng error: %s", msg); + + jmpbufP = png_get_error_ptr(png_ptr); + + if (!jmpbufP) { + /* we are completely hosed now */ + pm_error("EXTREMELY fatal error: jmpbuf unrecoverable; terminating."); + } + + longjmp(*jmpbufP, 1); +} + + + +void +pngx_create(struct pngx ** const pngxPP, + pngx_rw const rw, + jmp_buf * const jmpbufP) { + + struct pngx * pngxP; + + MALLOCVAR(pngxP); + + if (!pngxP) + pm_error("Failed to allocate memory for PNG object"); + else { + pngxP->numPassesRequired = 1; + + switch(rw) { + case PNGX_READ: + pngxP->png_ptr = png_create_read_struct( + PNG_LIBPNG_VER_STRING, + jmpbufP, errorHandler, NULL); + break; + case PNGX_WRITE: + pngxP->png_ptr = png_create_write_struct( + PNG_LIBPNG_VER_STRING, + jmpbufP, errorHandler, NULL); + break; + } + if (!pngxP->png_ptr) + pm_error("cannot allocate main libpng structure (png_ptr)"); + else { + pngxP->info_ptr = png_create_info_struct(pngxP->png_ptr); + + if (!pngxP->info_ptr) + pm_error("cannot allocate libpng info structure (info_ptr)"); + else + *pngxPP = pngxP; + } + pngxP->rw = rw; + } +} + + + +void +pngx_destroy(struct pngx * const pngxP) { + + switch(pngxP->rw) { + case PNGX_READ: + png_destroy_read_struct(&pngxP->png_ptr, &pngxP->info_ptr, NULL); + break; + case PNGX_WRITE: + png_destroy_write_struct(&pngxP->png_ptr, &pngxP->info_ptr); + break; + } + + free(pngxP); +} + + + +bool +pngx_chunkIsPresent(struct pngx * const pngxP, + uint32_t const chunkType) { + + return png_get_valid(pngxP->png_ptr, pngxP->info_ptr, chunkType); +} + + + +unsigned int +pngx_bitDepth(struct pngx * const pngxP) { + + return png_get_bit_depth(pngxP->png_ptr, pngxP->info_ptr); +} + + + +png_color_16 +pngx_bkgd(struct pngx * const pngxP) { + + png_color_16 * colorP; + + png_get_bKGD(pngxP->png_ptr, pngxP->info_ptr, &colorP); + + return *colorP; +} + + + +png_byte +pngx_colorType(struct pngx * const pngxP) { + + return png_get_color_type(pngxP->png_ptr, pngxP->info_ptr); +} + + + +png_byte +pngx_filterType(struct pngx * const pngxP) { + + return png_get_filter_type(pngxP->png_ptr, pngxP->info_ptr); +} + + + +double +pngx_gama(struct pngx * const pngxP) { + + double retval; + + png_get_gAMA(pngxP->png_ptr, pngxP->info_ptr, &retval); + + return retval; +} + + + +uint32_t +pngx_imageHeight(struct pngx * const pngxP) { + + return png_get_image_height(pngxP->png_ptr, pngxP->info_ptr); +} + + + +uint32_t +pngx_imageWidth(struct pngx * const pngxP) { + + return png_get_image_width(pngxP->png_ptr, pngxP->info_ptr); +} + + + +png_byte +pngx_interlaceType(struct pngx * const pngxP) { + + return png_get_interlace_type(pngxP->png_ptr, pngxP->info_ptr); +} + + + +struct pngx_plte +pngx_plte(struct pngx * const pngxP) { + + struct pngx_plte retval; + + int size; + + png_get_PLTE(pngxP->png_ptr, pngxP->info_ptr, &retval.palette, &size); + + assert(size >= 0); + + retval.size = size; + + return retval; +} + + + +png_color_8 +pngx_sbit(struct pngx * const pngxP) { + + png_color_8 * sbitP; + + png_get_sBIT(pngxP->png_ptr, pngxP->info_ptr, &sbitP); + + return *sbitP; +} + + + +struct pngx_text +pngx_text(struct pngx * const pngxP) { + + struct pngx_text retval; + + int size; + + png_get_text(pngxP->png_ptr, pngxP->info_ptr, &retval.line, &size); + + assert(size >= 0); + + retval.size = size; + + return retval; +} + + + +png_time +pngx_time(struct pngx * const pngxP) { + + png_time * timeP; + + png_get_tIME(pngxP->png_ptr, pngxP->info_ptr, &timeP); + + return *timeP; +} + + + +struct pngx_trns +pngx_trns(struct pngx * const pngxP) { + + struct pngx_trns retval; + + int numTrans; + png_color_16 * transColorP; + + png_get_tRNS(pngxP->png_ptr, pngxP->info_ptr, + &retval.trans, &numTrans, &transColorP); + + assert(numTrans >= 0); + + retval.numTrans = numTrans; + retval.transColor = *transColorP; + + return retval; +} + + + +uint32_t +pngx_xPixelsPerMeter(struct pngx * const pngxP) { + + return png_get_x_pixels_per_meter(pngxP->png_ptr, pngxP->info_ptr); +} + + + +uint32_t +pngx_yPixelsPerMeter(struct pngx * const pngxP) { + + return png_get_y_pixels_per_meter(pngxP->png_ptr, pngxP->info_ptr); +} + + + +void +pngx_removeChunk(struct pngx * const pngxP, + uint32_t const chunkType) { + + png_set_invalid(pngxP->png_ptr, pngxP->info_ptr, chunkType); +} + + + +void +pngx_setBkgdPalette(struct pngx * const pngxP, + unsigned int const backgroundIndex) { + + png_color_16 background; + + background.index = backgroundIndex; + + png_set_bKGD(pngxP->png_ptr, pngxP->info_ptr, &background); +} + + + +void +pngx_setBkgdRgb(struct pngx * const pngxP, + png_color_16 const backgroundArg) { + + png_color_16 background; + + background = backgroundArg; + + png_set_bKGD(pngxP->png_ptr, pngxP->info_ptr, &background); +} + + + +void +pngx_setChrm(struct pngx * const pngxP, + struct pngx_chroma const chroma) { + + png_set_cHRM(pngxP->png_ptr, pngxP->info_ptr, + chroma.wx, chroma.wy, + chroma.rx, chroma.ry, + chroma.gx, chroma.gy, + chroma.bx, chroma.by); +} + + + +const char * +pngx_srgbIntentDesc(pngx_srgbIntent const srgbIntent) { + + switch (srgbIntent) { + case PNGX_PERCEPTUAL: return "PERCEPTUAL"; + case PNGX_RELATIVE_COLORIMETRIC: return "RELATIVE COLORIMETRIC"; + case PNGX_SATURATION: return "SATURATION"; + case PNGX_ABSOLUTE_COLORIMETRIC: return "ABSOLUTE_COLORIMETRIC"; + } + assert(false); +} + + + +static int +const libpngSrgbIntentCode(pngx_srgbIntent const srgbIntent) { + + switch (srgbIntent) { + case PNGX_PERCEPTUAL: return 0; + case PNGX_RELATIVE_COLORIMETRIC: return 1; + case PNGX_SATURATION: return 2; + case PNGX_ABSOLUTE_COLORIMETRIC: return 3; + } + + assert(false); /* All cases above return */ +} + + + +void +pngx_setSrgb(struct pngx * const pngxP, + pngx_srgbIntent const srgbIntent) { + + png_set_sRGB(pngxP->png_ptr, pngxP->info_ptr, + libpngSrgbIntentCode(srgbIntent)); +} + + + +void +pngx_setCompressionSize(struct pngx * const pngxP, + unsigned int const bufferSize) { + +#if PNG_LIBPNG_VER >= 10009 + png_set_compression_buffer_size(pngxP->png_ptr, bufferSize); +#else + pm_error("Your PNG library cannot set the compression buffer size. " + "You need at least Version 1.0.9 of Libpng; you have Version %s", + PNG_LIBPNG_VER_STRING); +#endif +} + + + +void +pngx_setFilter(struct pngx * const pngxP, + int const filterSet) { + + png_set_filter(pngxP->png_ptr, 0, filterSet); +} + + + +void +pngx_setGama(struct pngx * const pngxP, + float const fileGamma) { + + png_set_gAMA(pngxP->png_ptr, pngxP->info_ptr, fileGamma); +} + + + +void +pngx_setGamma(struct pngx * const pngxP, + float const screenGamma, + float const imageGamma) { + + png_set_gamma(pngxP->png_ptr, screenGamma, imageGamma); +} + + + +void +pngx_setHist(struct pngx * const pngxP, + png_uint_16 * const histogram) { + + png_set_hIST(pngxP->png_ptr, pngxP->info_ptr, histogram); +} + + + +void +pngx_setIhdr(struct pngx * const pngxP, + unsigned int const width, + unsigned int const height, + unsigned int const bitDepth, + int const colorType, + int const interlaceMethod, + int const compressionMethod, + int const filterMethod) { + + png_set_IHDR(pngxP->png_ptr, pngxP->info_ptr, width, height, + bitDepth, colorType, interlaceMethod, compressionMethod, + filterMethod); +} + + + +void +pngx_setInterlaceHandling(struct pngx * const pngxP) { + + pngxP->numPassesRequired = png_set_interlace_handling(pngxP->png_ptr); +} + + + +void +pngx_setPacking(struct pngx * const pngxP) { + + png_set_packing(pngxP->png_ptr); +} + + + +void +pngx_setPhys(struct pngx * const pngxP, + struct pngx_phys const phys) { + + png_set_pHYs(pngxP->png_ptr, pngxP->info_ptr, + phys.x, phys.y, phys.unit); +} + + + +void +pngx_setPlte(struct pngx * const pngxP, + png_color * const palette, + unsigned int const paletteSize) { + + png_set_PLTE(pngxP->png_ptr, pngxP->info_ptr, palette, paletteSize); +} + + + +void +pngx_setSbit(struct pngx * const pngxP, + png_color_8 const sbitArg) { + + png_color_8 sbit; + + sbit = sbitArg; + + png_set_sBIT(pngxP->png_ptr, pngxP->info_ptr, &sbit); +} + + + +void +pngx_setShift(struct pngx * const pngxP, + png_color_8 const sigBitArg) { + + png_color_8 sigBit; + + sigBit = sigBitArg; + + png_set_shift(pngxP->png_ptr, &sigBit); +} + + + +void +pngx_setSigBytes(struct pngx * const pngxP, + unsigned int const sigByteCt) { + + assert(sigByteCt <= INT_MAX); + + png_set_sig_bytes(pngxP->png_ptr, sigByteCt); +} + + + +void +pngx_setTextKey(png_text * const textP, + const char * const key) { + + /* textP->key is improperly declared in libpng as char *; should + be const char * + */ + textP->key = (char *)pm_strdup(key); +} + + + +void +pngx_setTextLang(png_text * const textP, + const char * const language) { + +#if HAVE_PNGLIB_WITH_ITXT + if (language) + textP->lang = (char *)pm_strdup(language); + else + textP->lang = NULL; +#else + if (language) + pm_error("PNG library does not have ability to create an iTXT " + "chunk (i.e. to create a PNG with text strings in a language " + "other than English)"); +#endif +} + + + +void +pngx_setTextLangKey(png_text * const textP, + const char * const key) { + +#if HAVE_PNGLIB_WITH_ITXT + textP->lang_key = (char *)pm_strdup(key); +#else + pm_error("PNG library does not have ability to create an iTXT " + "chunk (i.e. to create a PNG with text strings in a language " + "other than English)"); +#endif +} + + +void +pngx_termText(png_text * const textP) { + + pm_strfree(textP->key); + +#if HAVE_PNGLIB_WITH_ITXT + if (textP->lang) { + pm_strfree(textP->lang); + pm_strfree(textP->lang_key); + } +#endif + + free(textP->text); +} + + + +void +pngx_setText(struct pngx * const pngxP, + png_text * const textP, + unsigned int const count) { + + png_set_text(pngxP->png_ptr, pngxP->info_ptr, textP, count); +} + + + +void +pngx_setTime(struct pngx * const pngxP, + time_t const timeArg) { + + png_time pngTime; + + png_convert_from_time_t(&pngTime, timeArg); + + png_set_tIME(pngxP->png_ptr, pngxP->info_ptr, &pngTime); +} + + + +void +pngx_setTrnsPalette(struct pngx * const pngxP, + const png_byte * const transPalette, + unsigned int const paletteSize) { + + png_set_tRNS(pngxP->png_ptr, pngxP->info_ptr, + (png_byte *)transPalette, paletteSize, NULL); +} + + + +void +pngx_setTrnsValue(struct pngx * const pngxP, + png_color_16 const transColorArg) { + + png_color_16 transColor; + + transColor = transColorArg; + + png_set_tRNS(pngxP->png_ptr, pngxP->info_ptr, + NULL, 0, &transColor); +} + + + +void +pngx_readInfo(struct pngx * const pngxP) { + + png_read_info(pngxP->png_ptr, pngxP->info_ptr); +} + + + +void +pngx_writeInfo(struct pngx * const pngxP) { + + png_write_info(pngxP->png_ptr, pngxP->info_ptr); +} + + + +static void +verifyFileIsPng(FILE * const ifP, + size_t * const consumedByteCtP) { + + unsigned char buffer[4]; + size_t bytesRead; + + bytesRead = fread(buffer, 1, sizeof(buffer), ifP); + if (bytesRead != sizeof(buffer)) + pm_error("input file is empty or too short"); + + if (png_sig_cmp(buffer, (png_size_t) 0, (png_size_t) sizeof(buffer)) != 0) + pm_error("input file is not a PNG file " + "(does not have the PNG signature in its first 4 bytes)"); + else + *consumedByteCtP = bytesRead; +} + + + +void +pngx_readStart(struct pngx * const pngxP, + FILE * const ifP) { + + size_t sigByteCt; + + verifyFileIsPng(ifP, &sigByteCt); + + /* Declare that we already read the signature bytes */ + pngx_setSigBytes(pngxP, (unsigned int)sigByteCt); + + png_init_io(pngxP->png_ptr, ifP); + + pngx_readInfo(pngxP); + + if (pngx_bitDepth(pngxP) < 8) + pngx_setPacking(pngxP); +} + + + +void +pngx_readRow(struct pngx * const pngxP, + png_byte * const rowBuf, + png_byte * const displayRow) { + + png_read_row(pngxP->png_ptr, rowBuf, displayRow); +} + + + +void +pngx_readImage(struct pngx * const pngxP, + png_byte ** const image) { + + png_read_image(pngxP->png_ptr, image); +} + + + +void +pngx_writeRow(struct pngx * const pngxP, + const png_byte * const line) { + + png_write_row(pngxP->png_ptr, (png_byte *)line); +} + + + +void +pngx_readEnd(struct pngx * const pngxP) { + + /* Note that some of info_ptr is not defined until png_read_end() + completes. That's because it comes from chunks that are at the + end of the stream. In particular, text and time chunks may + be at the end. Furthermore, they may be in both places, in + which case info_ptr contains different information before and + after png_read_end(). + */ + png_read_end(pngxP->png_ptr, pngxP->info_ptr); +} + + + +void +pngx_writeEnd(struct pngx * const pngxP) { + + png_write_end(pngxP->png_ptr, pngxP->info_ptr); +} + + + diff --git a/converter/other/pngx.h b/converter/other/pngx.h new file mode 100644 index 00000000..cabb0663 --- /dev/null +++ b/converter/other/pngx.h @@ -0,0 +1,268 @@ +#ifndef PNGX_H_INCLUDED +#define PNGX_H_INCLUDED + +#include +#include "pm_c_util.h" + +/* pngx is designed to be an extension of the PNG library to make using + the PNG library easier and cleaner. +*/ + +struct pngx_chroma { + float wx; + float wy; + float rx; + float ry; + float gx; + float gy; + float bx; + float by; +}; + +struct pngx_phys { + int x; + int y; + int unit; +}; + +struct pngx_text { + png_text * line; + unsigned int size; +}; + +struct pngx_plte { + png_color * palette; + unsigned int size; +}; + +struct pngx_trns { + png_byte * trans; + unsigned int numTrans; + png_color_16 transColor; +}; + +typedef enum {PNGX_READ, PNGX_WRITE} pngx_rw; + +struct pngx { + png_structp png_ptr; + png_infop info_ptr; + pngx_rw rw; + png_uint_16 maxval; + unsigned int numPassesRequired; + /* The number of times we have write the complete image to the + compressor. This is more than one when the compressor is set + up to do an interlaced format. + */ +}; + +void +pngx_create(struct pngx ** const pngxPP, + pngx_rw const rw, + jmp_buf * const jmpbufP); + +void +pngx_destroy(struct pngx * const pngxP); + +bool +pngx_chunkIsPresent(struct pngx * const pngxP, + uint32_t const chunkType); + +unsigned int +pngx_bitDepth(struct pngx * const pngxP); + +png_color_16 +pngx_bkgd(struct pngx * const pngxP); + +png_byte +pngx_colorType(struct pngx * const pngxP); + +png_byte +pngx_filterType(struct pngx * const pngxP); + +double +pngx_gama(struct pngx * const pngxP); + +uint32_t +pngx_imageHeight(struct pngx * const pngxP); + +uint32_t +pngx_imageWidth(struct pngx * const pngxP); + +png_byte +pngx_interlaceType(struct pngx * const pngxP); + +struct pngx_plte +pngx_plte(struct pngx * const pngxP); + +png_color_8 +pngx_sbit(struct pngx * const pngxP); + +struct pngx_text +pngx_text(struct pngx * const pngxP); + +png_time +pngx_time(struct pngx * const pngxP); + +struct pngx_trns +pngx_trns(struct pngx * const pngxP); + +uint32_t +pngx_xPixelsPerMeter(struct pngx * const pngxP); + +uint32_t +pngx_yPixelsPerMeter(struct pngx * const pngxP); + +void +pngx_removeChunk(struct pngx * const pngxP, + uint32_t const chunkType); + +void +pngx_setBkgdPalette(struct pngx * const pngxP, + unsigned int const backgroundIndex); + +void +pngx_setBkgdRgb(struct pngx * const pngxP, + png_color_16 const backgroundArg); + +void +pngx_setChrm(struct pngx * const pngxP, + struct pngx_chroma const chroma); + +typedef enum { + PNGX_PERCEPTUAL, + PNGX_RELATIVE_COLORIMETRIC, + PNGX_SATURATION, + PNGX_ABSOLUTE_COLORIMETRIC +} pngx_srgbIntent; + +const char * +pngx_srgbIntentDesc(pngx_srgbIntent const srgbIntent); + +void +pngx_setSrgb(struct pngx * const pngxP, + pngx_srgbIntent const srgbIntent); + +void +pngx_setCompressionSize(struct pngx * const pngxP, + unsigned int const bufferSize); + +void +pngx_setFilter(struct pngx * const pngxP, + int const filterSet); + +void +pngx_setGama(struct pngx * const pngxP, + float const fileGamma); + +void +pngx_setGamma(struct pngx * const pngxP, + float const displayGamma, + float const imageGamma); + +void +pngx_setHist(struct pngx * const pngxP, + png_uint_16 * const histogram); + +void +pngx_setIhdr(struct pngx * const pngxP, + unsigned int const width, + unsigned int const height, + unsigned int const bitDepth, + int const colorType, + int const interlaceMethod, + int const compressionMethod, + int const filterMethod); + +void +pngx_setInterlaceHandling(struct pngx * const pngxP); + +void +pngx_setInvalid(struct pngx * const pngxP); + +void +pngx_setPacking(struct pngx * const pngxP); + +void +pngx_setPhys(struct pngx * const pngxP, + struct pngx_phys const phys); + +void +pngx_setPlte(struct pngx * const pngxP, + png_color * const palette, + unsigned int const paletteSize); + +void +pngx_setSbit(struct pngx * const pngxP, + png_color_8 const sbit); + +void +pngx_setShift(struct pngx * const pngxP, + png_color_8 const sigBitArg); + +void +pngx_setSigBytes(struct pngx * const pngxP, + unsigned int const sigByteCt); + +void +pngx_setTextKey(png_text * const textP, + const char * const key); + +void +pngx_setTextLang(png_text * const textP, + const char * const language); + +void +pngx_setTextLangKey(png_text * const textP, + const char * const key); + +void +pngx_termText(png_text * const textP); + +void +pngx_setText(struct pngx * const pngxP, + png_textp const textP, + unsigned int const count); + +void +pngx_setTime(struct pngx * const pngxP, + time_t const timeArg); + +void +pngx_setTrnsPalette(struct pngx * const pngxP, + const png_byte * const transPalette, + unsigned int const paletteSize); + +void +pngx_setTrnsValue(struct pngx * const pngxP, + png_color_16 const transColorArg); + +void +pngx_readInfo(struct pngx * const pngxP); + +void +pngx_writeInfo(struct pngx * const pngxP); + +void +pngx_readStart(struct pngx * const pngxP, + FILE * const ifP); + +void +pngx_readRow(struct pngx * const pngxP, + png_byte * const rowBuf, + png_byte * const displayRow); + +void +pngx_readImage(struct pngx * const pngxP, + png_byte ** const image); + +void +pngx_writeRow(struct pngx * const pngxP, + const png_byte * const line); + +void +pngx_readEnd(struct pngx * const pngxP); + +void +pngx_writeEnd(struct pngx * const pngxP); + +#endif diff --git a/converter/other/pnmtojpeg.c b/converter/other/pnmtojpeg.c index 198aa156..ce231c94 100644 --- a/converter/other/pnmtojpeg.c +++ b/converter/other/pnmtojpeg.c @@ -271,7 +271,7 @@ parseCommandLine(const int argc, char ** argv, cmdlineP->comment = NULL; cmdlineP->exif_filespec = NULL; - /* Make private copy of arguments for optParseOptions to corrupt */ + /* Make private copy of arguments for pm_optParseOptions to corrupt */ argc_parse = argc; for (i=0; i < argc; i++) argv_parse[i] = argv[i]; @@ -279,7 +279,7 @@ parseCommandLine(const int argc, char ** argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3(&argc_parse, argv_parse, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc_parse, argv_parse, opt, sizeof(opt), 0); if (!qualitySpec) cmdlineP->quality = -1; /* unspecified */ @@ -898,7 +898,7 @@ write_exif_header(struct jpeg_compress_struct * const cinfoP, pm_error("Invalid length %u at start of exif file", length); else { unsigned char * exif_data; - int rc; + size_t rc; size_t const data_length = length - 2; /* Subtract 2 byte length field*/ @@ -906,14 +906,15 @@ write_exif_header(struct jpeg_compress_struct * const cinfoP, exif_data = malloc(data_length); if (exif_data == NULL) - pm_error("Unable to allocate %d bytes for exif header buffer", - data_length); + pm_error("Unable to allocate %u bytes for exif header buffer", + (unsigned)data_length); rc = fread(exif_data, 1, data_length, exif_file); if (rc != data_length) pm_error("Premature end of file on exif header file. Should be " - "%d bytes of data, read only %d", data_length, rc); + "%u bytes of data, read only %u", + (unsigned)data_length, (unsigned)rc); jpeg_write_marker(cinfoP, JPEG_APP0+1, (const JOCTET *) exif_data, data_length); diff --git a/converter/other/pnmtopalm/Makefile b/converter/other/pnmtopalm/Makefile index 7f99f95a..edc7da64 100644 --- a/converter/other/pnmtopalm/Makefile +++ b/converter/other/pnmtopalm/Makefile @@ -8,8 +8,10 @@ VPATH=.:$(SRCDIR)/$(SUBDIR) include $(BUILDDIR)/config.mk BINARIES = palmtopnm pnmtopalm +PORTBINARIES = $(BINARIES) gen_palm_colormap SCRIPTS = -OBJECTS = $(BINARIES:%=%.o) palmcolormap.o +ADDL_OBJECTS = palmcolormap.o +OBJECTS = $(BINARIES:%=%.o) $(ADDL_OBJECTS) gen_palm_colormap.o MERGE_OBJECTS = $(BINARIES:%=%.o2) palmcolormap.o MERGEBINARIES = $(BINARIES) DATAFILES = palmcolor8.map palmgray1.map palmgray2.map palmgray4.map @@ -18,17 +20,7 @@ all: $(BINARIES) include $(SRCDIR)/common.mk -LIBOPTS = $(shell $(LIBOPT) $(NETPBMLIB)) - -$(BINARIES): %: %.o palmcolormap.o $(NETPBMLIB) $(LIBOPT) - $(LD) -o $@ $< palmcolormap.o $(LIBOPTS) \ - $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD) - -gen_palm_colormap : % : %.c palmcolormap.o - $(CC) -I importinc $(CPPFLAGS) $(CFLAGS) -o $@ \ - $< palmcolormap.o \ - $(LIBOPTS) $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(LADD) - +$(BINARIES): $(ADDL_OBJECTS) clean: cleanspecial .PHONY: cleanspecial diff --git a/converter/other/pnmtopalm/gen_palm_colormap.c b/converter/other/pnmtopalm/gen_palm_colormap.c index c7172c6b..0f3f8a5f 100644 --- a/converter/other/pnmtopalm/gen_palm_colormap.c +++ b/converter/other/pnmtopalm/gen_palm_colormap.c @@ -3,8 +3,8 @@ * Based on an earlier version by Bill Janssen */ -#include "ppm.h" -#include "pm_c_util.h" +#include "netpbm/ppm.h" +#include "netpbm/pm_c_util.h" #include "palm.h" diff --git a/converter/other/pnmtopalm/palm.h b/converter/other/pnmtopalm/palm.h index 170c8cec..718a66cf 100644 --- a/converter/other/pnmtopalm/palm.h +++ b/converter/other/pnmtopalm/palm.h @@ -44,13 +44,9 @@ typedef struct { typedef Colormap_s * Colormap; -int -palmcolor_compare_indices(const void * const p1, - const void * const p2); +qsort_comparison_fn palmcolor_compare_indices; -int -palmcolor_compare_colors(const void * const p1, - const void * const p2); +qsort_comparison_fn palmcolor_compare_colors; Colormap palmcolor_build_custom_8bit_colormap(unsigned int const rows, diff --git a/converter/other/pnmtopalm/palmcolormap.c b/converter/other/pnmtopalm/palmcolormap.c index a1a1cec1..0f47558c 100644 --- a/converter/other/pnmtopalm/palmcolormap.c +++ b/converter/other/pnmtopalm/palmcolormap.c @@ -10,7 +10,9 @@ int palmcolor_compare_indices(const void * const p1, const void * const p2) { - +/*---------------------------------------------------------------------------- + This is a 'qsort' collation function. +-----------------------------------------------------------------------------*/ if ((*((Color) p1) & 0xFF000000) < (*((Color) p2) & 0xFF000000)) return -1; else if ((*((Color) p1) & 0xFF000000) > (*((Color) p2) & 0xFF000000)) @@ -24,7 +26,9 @@ palmcolor_compare_indices(const void * const p1, int palmcolor_compare_colors(const void * const p1, const void * const p2) { - +/*---------------------------------------------------------------------------- + This is a 'qsort' collation function. +-----------------------------------------------------------------------------*/ unsigned long const val1 = *((const unsigned long *) p1) & 0xFFFFFF; unsigned long const val2 = *((const unsigned long *) p2) & 0xFFFFFF; diff --git a/converter/other/pnmtopalm/palmtopnm.c b/converter/other/pnmtopalm/palmtopnm.c index 88088817..00aa35e4 100644 --- a/converter/other/pnmtopalm/palmtopnm.c +++ b/converter/other/pnmtopalm/palmtopnm.c @@ -92,7 +92,7 @@ parseCommandLine(int argc, char ** argv, was passed to us as the argv array. -----------------------------------------------------------------------------*/ optEntry *option_def = malloc( 100*sizeof( optEntry ) ); - /* Instructions to optParseOptions3 on how to parse our options. + /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; @@ -114,7 +114,7 @@ parseCommandLine(int argc, char ** argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We may have parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ diff --git a/converter/other/pnmtopalm/pnmtopalm.c b/converter/other/pnmtopalm/pnmtopalm.c index 90737b78..6e290777 100644 --- a/converter/other/pnmtopalm/pnmtopalm.c +++ b/converter/other/pnmtopalm/pnmtopalm.c @@ -33,8 +33,8 @@ struct cmdline_info { /* All the information the user supplied in the command line, in a form easy for the program to use. */ - const char *inputFilespec; /* Filespecs of input files */ - char *transparent; /* -transparent value. Null if unspec */ + const char * inputFilespec; /* Filespecs of input files */ + const char * transparent; /* -transparent value. Null if unspec */ unsigned int depth; /* -depth value. 0 if unspec */ unsigned int maxdepth; /* -maxdepth value. 0 if unspec */ enum compressionType compression; @@ -90,7 +90,7 @@ parseCommandLine(int argc, char ** argv, struct cmdline_info *cmdlineP) { opt.short_allowed = FALSE; /* We have some short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdline_p and others. */ if (depthSpec) { @@ -289,7 +289,7 @@ formatName(int const format) { static void -findTransparentColor(char * const colorSpec, +findTransparentColor(const char * const colorSpec, pixval const newMaxval, bool const directColor, pixval const maxval, @@ -497,7 +497,7 @@ writeDummy() { Write a dummy Palm Bitmap header. This is a 16 byte header, of type version 1 and with (only) pixelSize set to 0xFF. - An old viewer will see this as invalid due to the pixelSize, and stop + An old viewer will see this as invalid because of the pixelSize, and stop reading the stream. A new viewer will recognize this for what it is (a dummy header designed to stop old viewers from reading further in the stream) and continue reading the stream. Presumably, what follows @@ -835,6 +835,7 @@ rleCompressAndBufferRow(const unsigned char * const rowdata, +/* FIXME Incorrect for images with pixelSize == 16 */ static void computeNextPackbitsRun(const unsigned char * const rowdata, unsigned int const rowbytes, @@ -912,7 +913,7 @@ packbitsCompressAndBufferRow(const unsigned char * const rowdata, unsigned int const rowbytes, struct seqBuffer * const rasterBufferP) { /*---------------------------------------------------------------------------- - Take the raw Palm Bitmap row 'rowdata', which is 'rowbytess' bytes, and + Take the raw Palm Bitmap row 'rowdata', which is 'rowbytes' bytes, and add the packbits-compressed representation of it to the buffer with handle 'rasterBufferP'. -----------------------------------------------------------------------------*/ diff --git a/converter/other/pnmtopclxl.c b/converter/other/pnmtopclxl.c index e16afb14..8cabb614 100644 --- a/converter/other/pnmtopclxl.c +++ b/converter/other/pnmtopclxl.c @@ -34,6 +34,7 @@ #include "shhopt.h" #include "mallocvar.h" #include "nstring.h" +#include "runlength.h" #include "pclxl.h" @@ -54,7 +55,7 @@ struct cmdlineInfo { in a form easy for the program to use. */ InputSource * sourceP; - int dpi; + unsigned int dpi; enum MediaSize format; unsigned int feederSpec; int feeder; @@ -71,6 +72,7 @@ struct cmdlineInfo { unsigned int verbose; const char * jobsetup; /* -jobsetup option value. NULL if none */ unsigned int rendergray; + unsigned int embedded; }; @@ -89,7 +91,7 @@ parseCommandLine(int argc, char ** argv, was passed to us as the argv array. We also trash *argv. -----------------------------------------------------------------------------*/ optEntry *option_def = malloc( 100*sizeof( optEntry ) ); - /* Instructions to optParseOptions3 on how to parse our options. + /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; @@ -126,12 +128,14 @@ parseCommandLine(int argc, char ** argv, &jobsetupSpec, 0); OPTENT3(0, "rendergray", OPT_FLAG, NULL, &cmdlineP->rendergray, 0 ); + OPTENT3(0, "embedded", OPT_FLAG, NULL, + &cmdlineP->embedded, 0 ); opt.opt_table = option_def; opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3( &argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (!dpiSpec) @@ -174,6 +178,20 @@ parseCommandLine(int argc, char ** argv, if (!jobsetupSpec) cmdlineP->jobsetup = NULL; + if (cmdlineP->embedded) { + if (xoffsSpec || yoffsSpec || formatSpec || cmdlineP->duplexSpec + || cmdlineP->copiesSpec || dpiSpec || cmdlineP->center + || cmdlineP->feederSpec || cmdlineP->outtraySpec + || jobsetupSpec || cmdlineP->rendergray) + pm_error("With -embedded, you may not specify " + "-xoffs, -yoffs, -format, -duplex, copies, -dpi, " + "-center, -feeder, -outtray, -jobsetup, or -rendergray"); + + if (argc-1 > 1) + pm_message("With -embedded, you may not specify more than one " + "input image. You specified %u", argc-1); + } + if (argc-1 < 1) { MALLOCVAR(cmdlineP->sourceP); cmdlineP->sourceP->name = "-"; @@ -196,154 +214,248 @@ parseCommandLine(int argc, char ** argv, -#define XY_RLE_FBUFSIZE (1024) -typedef struct XY_rle { - int error; - unsigned char buf[128]; - int bpos; - int state; - unsigned char *fbuf; - int fbpos; - int fbufsize; - int fd; -} XY_rle; - +static void +freeSource(InputSource * const firstSourceP) { + + InputSource * sourceP; -static void -XY_RLEreset(XY_rle *rle) -{ - rle->state = eSTART; - rle->bpos = 0; - rle->fbpos=0; - rle->error=0; -} -static XY_rle * -XY_RLEnew(int size) { - XY_rle *rle; - - MALLOCVAR(rle); - if(rle==NULL) - return rle; - if(size<1024) - size=1024; - rle->fbuf=malloc(size); - rle->fbufsize=size; - if(!rle->fbuf) { - free(rle); - return NULL; + sourceP = firstSourceP; + while(sourceP) { + InputSource * const nextP = sourceP->next; + free(sourceP); + sourceP = nextP; } - return rle; } + + + static void -XY_RLEdelete(XY_rle *rle) { - free(rle->fbuf); - free(rle); +freeCmdline(struct cmdlineInfo const cmdline) { + + freeSource(cmdline.sourceP); } -static int -out(XY_rle *rle,int count) { - if(rle->state==eRLE) { - rle->fbuf[rle->fbpos++]=-count+1; - rle->fbuf[rle->fbpos++]=rle->buf[0]; - } else if(rle->bpos>0) { - rle->fbuf[rle->fbpos++]=count-1; - memcpy(rle->fbuf+rle->fbpos,rle->buf,count); - rle->fbpos+=count; + + +static int +XY_Write(int const fd, + const void * const buf, + int const cnt) { + + int len; + bool error; + + for (len =0, error = false; len < cnt && !error;) { + ssize_t const rc = write(fd, (char*)buf + len , cnt - len); + if (rc <= 0) + error = true; + else + len += rc; } - if(rle->fbpos+129>rle->fbufsize) { - if (rle->fbufsize > INT_MAX/1.2) - pm_error("Arithmetic overflow during attempt to expand RLE " - "output buffer beyond %u", rle->fbufsize); - rle->fbufsize*=1.2; - rle->fbuf=realloc(rle->fbuf,rle->fbufsize); - if(rle->fbuf==NULL) { - pm_error("Out of memory while attempting to expand RLE " - "output buffer beyond %u", rle->fbufsize); - rle->error=-1; - rle->fbpos=0; - return -1; - } + return error ? -1 : len; +} + + + +#define XY_Puts(fd, str) XY_Write(fd, str, strlen(str)) + + + +typedef struct pclGenerator { + enum ColorDepth colorDepth; + enum Colorspace colorSpace; + int width,height; + unsigned int linelen; /* bytes per line */ + unsigned int paddedLinelen; /* bytes per line + padding */ + unsigned char * data; + unsigned int cursor; + void (*getnextrow)(struct pclGenerator *, struct pam *); +} pclGenerator; + + + +static void +pnmToPcllinePackbits(pclGenerator * const pclGeneratorP, + struct pam * const pamP) { + + tuple * tuplerow; + unsigned char accum; + unsigned char bitmask; + unsigned int col, padCt; + unsigned int const padsize = + pclGeneratorP->paddedLinelen - pclGeneratorP->linelen; + + tuplerow = pnm_allocpamrow(pamP); + + pnm_readpamrow(pamP, tuplerow); + + bitmask = 0x80; accum = 0x00; + for (col = 0; col < pamP->width; ++col) { + if (tuplerow[col][0] == PAM_PBM_WHITE) + accum |= bitmask; + bitmask >>= 1; + if (bitmask == 0) { + pclGeneratorP->data[pclGeneratorP->cursor++] = accum; + bitmask = 0x80; accum = 0x0; + } } - rle->bpos=0; - rle->state=eSTART; - return 0; + if (bitmask != 0x80) + pclGeneratorP->data[pclGeneratorP->cursor++] = accum; + + for (padCt = 0; padCt < padsize; ++padCt) + pclGeneratorP->data[pclGeneratorP->cursor++] = 0; + + pnm_freepamrow(tuplerow); } -static int -XY_RLEfinish (XY_rle *rle) { - out(rle,rle->bpos); - if(rle->error<0) - return rle->error; - else - return rle->fbpos; + + + +static unsigned int +pclPaddedLinelen(unsigned int const linelen) { + + if (UINT_MAX - 3 < linelen) + pm_error("Image too big to process"); + + return (((linelen + 3) / 4) * 4); } -static void -rle_putbyte(XY_rle *rle,unsigned char u) -{ - switch (rle->state) { - case eRLE: - if(u!=rle->buf[0]) { - out(rle,rle->bpos); - } - break; - case eLIT: - if((u==rle->buf[rle->bpos-1])&&(u==rle->buf[rle->bpos-2])) { - out(rle,rle->bpos-2); - rle->buf[0]=u; - rle->bpos+=2; - rle->state=eRLE; - } - break; - case eSTART: - if(rle->bpos==1) { - if(u==rle->buf[rle->bpos-1]) { - rle->state=eRLE; - } else { - rle->state=eLIT; - } - } - break; + + + +static unsigned int +pclDatabuffSize(unsigned int const paddedLinelen) { + + if (UINT_MAX / 20 < paddedLinelen) + pm_error("Image too big to process"); + + return (paddedLinelen * 20); +} + + + +static void +createPclGeneratorPackbits(struct pam * const pamP, + pclGenerator ** const pclGeneratorPP) { + + /* Samples are black or white and packed 8 to a byte */ + + pclGenerator * pclGeneratorP; + + MALLOCVAR_NOFAIL(pclGeneratorP); + + pclGeneratorP->colorDepth = e1Bit; + pclGeneratorP->colorSpace = eGray; + pclGeneratorP->linelen = (pamP->width+7)/8; + pclGeneratorP->paddedLinelen = pclPaddedLinelen(pclGeneratorP->linelen); + pclGeneratorP->height = pamP->height; + pclGeneratorP->width = (pamP->width); + + pclGeneratorP->data = + malloc(pclDatabuffSize(pclGeneratorP->paddedLinelen)); + if (pclGeneratorP->data == NULL) + pm_error("Unable to allocate row buffer."); + + pclGeneratorP->getnextrow = pnmToPcllinePackbits; + + *pclGeneratorPP = pclGeneratorP; +} + + + +static void +pnmToPcllineWholebytes(pclGenerator * const pclGeneratorP, + struct pam * const pamP) { + + tuple * tuplerow; + unsigned int col, padCt; + unsigned int const padsize = + pclGeneratorP->paddedLinelen - pclGeneratorP->linelen; + + tuplerow = pnm_allocpamrow(pamP); + + pnm_readpamrow(pamP, tuplerow); + + for (col = 0; col < pamP->width; ++col) { + unsigned int plane; + for (plane = 0; plane < pamP->depth; ++plane) { + pclGeneratorP->data[pclGeneratorP->cursor++] = + pnm_scalesample(tuplerow[col][plane], pamP->maxval, 255); + } } - rle->buf[rle->bpos++]=u; - if(rle->bpos==128) { - out(rle,rle->bpos); - } + + for(padCt=0; padCt < padsize; ++padCt) + pclGeneratorP->data[pclGeneratorP->cursor++] = 0; + + pnm_freepamrow(tuplerow); } static void -XY_RLEput(XY_rle *rle,const unsigned char buf[],int count) -{ - int i; - for(i=0;idepth < 3) + pclGenP->colorSpace = eGray; + else + pclGenP->colorSpace = eRGB; + + pclGenP->colorDepth = e8Bit; + pclGenP->height = pamP->height; + pclGenP->width = pamP->width; + + if (UINT_MAX / pamP->width < pamP->depth) + pm_error("Image too big to process"); + else { + pclGenP->linelen = pamP->width * pamP->depth; + pclGenP->paddedLinelen = pclPaddedLinelen(pclGenP->linelen); + pclGenP->data = malloc(pclDatabuffSize(pclGenP->paddedLinelen)); + if (pclGenP->data == NULL) + pm_error("Unable to allocate row buffer."); } + pclGenP->getnextrow = pnmToPcllineWholebytes; + + *pclGenPP = pclGenP; } -static int -XY_Write(int fd, const void *buf,int cnt) { - int len=0; - while(lendata); + + free(pclGenP); } -#define XY_Puts(fd,str) XY_Write(fd,str,strlen(str)) -typedef struct pclGenerator { - enum ColorDepth colorDepth; - enum Colorspace colorSpace; - int width,height; - int linelen; /* bytes per line */ - unsigned char *data; - void (*getnextrow)(const struct pclGenerator *, struct pam *); -} pclGenerator; + + +static void +createPclGenerator(struct pam * const pamP, + pclGenerator ** const pclGeneratorPP, + bool const colorok) { + + if (pamP->depth > 1 && !colorok) + pm_message("WARNING: generating a color print stream because the " + "input image is PPM. " + "To generate a black and white print stream, run the input " + "through Ppmtopgm. To suppress this warning, use the " + "-colorok option."); + + if (pamP->depth == 1 && pamP->maxval == 1) + createPclGeneratorPackbits(pamP, pclGeneratorPP); + else + createPclGeneratorWholebytes(pamP, pclGeneratorPP); +} + + + struct tPrinter { const char *name; @@ -358,74 +470,85 @@ struct tPrinter { static int -out_ubyte(int fd,unsigned char data) { - return XY_Write(fd,&data,1); +out_ubyte(int const fd, + unsigned char const data) { + + return XY_Write(fd, &data, 1); } -static int -XL_Operator(int fd,enum Operator const data) { - return out_ubyte(fd,data); + + + +static int +XL_Operator(int const fd, + enum Operator const data) { + + return out_ubyte(fd, data); } + + + static int -out_uint16(int fd,unsigned short data ) { +out_uint16(int const fd, + unsigned short const data ) { + unsigned char c[2]; - c[0]=data&0xff; c[1]=data>>8; - return XY_Write(fd,c,2); + + c[0] = data & 0xff; + c[1] = data >>8; + + return XY_Write(fd, c , ARRAY_SIZE(c)); } + + + static int out_uint32(int fd,unsigned int data ) { unsigned char c[4]; c[0] = data&0xff; c[1]=(data>>8)&0xff; c[2]=(data>>16)&0xff; c[3]=data>>24; return XY_Write(fd,c,4); } + + + static int -out_sint16(int fd,signed short sdata ) { - unsigned short data=(unsigned short)sdata; +out_sint16(int const fd, + signed short const sdata ) { + + unsigned short const data= (unsigned short)sdata; + unsigned char c[2]; - c[0]=data&0xff; c[1]=data>>8; - return XY_Write(fd,c,2); -} -#if 0 -static int -out_sint32(int fd,signed int sdata ) { - unsigned int data=(unsigned int)sdata; - unsigned char c[4]; - c[0] = data&0xff; c[1]=(data>>8)&0xff; c[2]=(data>>16)&0xff; c[3]=data>>24; - return XY_Write(fd,c,4); -} -#endif -static int -xl_ubyte(int fd,unsigned char data) { - unsigned char const tag=0xc0; - XY_Write(fd,&tag,1); - return out_ubyte(fd,data); -} -static int -xl_uint16(int fd,unsigned short data ) { - unsigned char const tag=0xc1; - XY_Write(fd,&tag,1); - return out_uint16(fd,data); -} -#if 0 -static int -xl_uint32(int fd,unsigned int data ) { - unsigned char const c=0xc2; - XY_Write(fd,&c,1); - return out_uint32(fd,data); + c[0] = data & 0xff; + c[1] = data >> 8; + + return XY_Write(fd, c, ARRAY_SIZE(c)); } + + + static int -xl_sint16(int fd,signed short data ) { - unsigned char const c=0xc3; - XY_Write(fd,&c,1); - return out_sint16(fd,data); +xl_ubyte(int const fd, + unsigned char const data) { + + unsigned char const tag = 0xc0; + + XY_Write(fd, &tag, 1); + + return out_ubyte(fd, data); } + + + static int -xl_sint32(int fd,signed int data ) { - unsigned char const c=0xc4; - XY_Write(fd,&c,1); - return out_sint32(fd,data); +xl_uint16(int const fd, + unsigned short const data) { + + unsigned char const tag = 0xc1; + + XY_Write(fd, &tag, 1); + + return out_uint16(fd, data); } -#endif @@ -439,10 +562,10 @@ xl_ubyte_array(int const fd, head[0] = 0xc8; head[1] = 0xc1; - head[2] = len&0xff; - head[3] = (len>>8)&0xff; + head[2] = len & 0xff; + head[3] = (len >> 8) & 0xff; - XY_Write(fd, head, 4); + XY_Write(fd, head, ARRAY_SIZE(head)); for (i = 0; i < len; ++i) out_ubyte(fd, data[i]); @@ -452,123 +575,182 @@ xl_ubyte_array(int const fd, -#if 0 static int -xl_uint16_array(int fd,unsigned short *data,int len) { - int i; - unsigned char head[4]; - head[0]=0xc9;head[1]=0xc1;head[2]=len&0xff;head[3]=(len>>8)&0xff; - XY_Write(fd,head,4); - for(i=0;i>8)&0xff; - XY_Write(fd,head,4); - for(i=0;i>8)&0xff; - XY_Write(fd,head,4); - for(i=0;i>8)&0xff; - XY_Write(fd,head,4); - for(i=0;icursor = 0; + for (line = firstLine; line < firstLine + lineCt; ++line) { + pclGeneratorP->getnextrow(pclGeneratorP, pamP); + } + + pm_rlenc_compressbyte(pclGeneratorP->data, outbuf, PM_RLE_PACKBITS, + pclGeneratorP->paddedLinelen * lineCt, &rlelen); + + xl_dataLength(outFd, rlelen); + XY_Write(outFd, outbuf, rlelen); +} + + + +/* + * ------------------------------------------------------------ + * XL_WriteImage + * Write a PCL-XL image to the datastream + * ------------------------------------------------------------ + */ +static void +convertAndWriteImage(int const outFd, + pclGenerator * const pclGenP, + struct pam * const pamP) { + + size_t const inSize = (pclGenP-> linelen + 3) * 20; + + int blockStartLine; + unsigned char * outbuf; + + xl_ubyte(outFd, eDirectPixel); xl_attr_ubyte(outFd, aColorMapping); + xl_ubyte(outFd, pclGenP->colorDepth); xl_attr_ubyte(outFd, aColorDepth); + xl_uint16(outFd, pclGenP->width); xl_attr_ubyte(outFd, aSourceWidth); + xl_uint16(outFd, pclGenP->height); xl_attr_ubyte(outFd, aSourceHeight); + xl_uint16_xy(outFd, pclGenP->width*1, pclGenP->height*1); + xl_attr_ubyte(outFd, aDestinationSize); + XL_Operator(outFd, oBeginImage); + + pm_rlenc_allocoutbuf(&outbuf, inSize, PM_RLE_PACKBITS); + + for (blockStartLine = 0; blockStartLine < pclGenP->height; ) { + unsigned int const blockHeight = + MIN(20, pclGenP->height-blockStartLine); + + xl_uint16(outFd, blockStartLine); xl_attr_ubyte(outFd, aStartLine); + xl_uint16(outFd, blockHeight); xl_attr_ubyte(outFd, aBlockHeight); + xl_ubyte(outFd, eRLECompression); xl_attr_ubyte(outFd, aCompressMode); + /* In modern PCL-XL, we could use a PadBytesMultiple attribute + here to avoid having to pad the data to a multiple of 4 + bytes. But PCL-XL 1.1 didn't have PadBytesMultiple. + xl_ubyte(outFd, 1); xl_attr_ubyte(outFd, aPadBytesMultiple); + */ + XL_Operator(outFd, oReadImage); + convertAndWriteRleBlock(outFd, pclGenP, pamP, + blockStartLine, blockHeight, outbuf); + blockStartLine += blockHeight; } - return 0; + pm_rlenc_freebuf(outbuf); + XL_Operator(outFd, oEndImage); } -static int -xl_ubyte_xy(int fd,unsigned char xdata,unsigned char ydata) { - unsigned char const tag=0xd0; - XY_Write(fd,&data,1); - out_ubyte(fd,ydata); - return out_ubyte(fd,xdata); -} -#endif -static int -xl_uint16_xy(int fd,unsigned short xdata,unsigned short ydata ) { - unsigned char const tag=0xd1; - XY_Write(fd,&tag,1); - out_uint16(fd,xdata); - return out_uint16(fd,ydata); -} -#if 0 -static int -xl_uint32_xy(int fd,unsigned int xdata,unsigned int ydata ) { - unsigned char const tag=0xd2; - XY_Write(fd,&tag,1); - out_uint32(fd,xdata); - return out_uint32(fd,ydata); -} -#endif -static int -xl_sint16_xy(int fd,signed short xdata,signed short ydata ) { - unsigned char const tag=0xd3; - XY_Write(fd,&tag,1); - out_sint16(fd,xdata); - return out_sint16(fd,ydata); -} -#if 0 -static int -xl_sint32_xy(int fd,signed int xdata,signed int ydata ) { - unsigned char const tag=0xd4; - XY_Write(fd,&tag,1); - out_sint32(fd,xdata); - return out_sint32(fd,ydata); -} -#endif -static int -xl_attr_ubyte(int fd,enum Attribute const data) { - unsigned char const tag=0xf8; - XY_Write(fd,&tag,1); - return out_ubyte(fd,data); -} -#if 0 -static int -xl_attr_uint16(int fd,enum Attribute const data ) { - unsigned char const tag=0xf9; - XY_Write(fd,&tag,1); - return out_uint16(fd,data); -} -#endif -static int -xl_dataLength(int fd,unsigned int dataLength ) { - unsigned char const tag=0xfa; - XY_Write(fd,&tag,1); - return out_uint32(fd,dataLength); -} +static void +printEmbeddedImage(int const outFd, + const InputSource * const sourceP, + bool const colorok) { -#if 0 -static int -xl_dataLengthbytes(int fd,unsigned char dataLengthBytes) { - unsigned char const tag=0xfb; - XY_Write(fd,&tag,1); - return out_ubyte(fd,dataLengthBytes); + FILE * ifP; + struct pam pam; + pclGenerator * pclGeneratorP; + + openDataSource(outFd, eBinaryLowByteFirst, eDefaultSource); + + ifP = pm_openr(sourceP->name); + + pnm_readpaminit(ifP, &pam, PAM_STRUCT_SIZE(tuple_type)); + + createPclGenerator(&pam, &pclGeneratorP, colorok); + + convertAndWriteImage(outFd, pclGeneratorP, &pam); + + destroyPclGenerator(pclGeneratorP); + + pm_close(ifP); + + closeDataSource(outFd); } -#endif @@ -628,10 +810,10 @@ jobHead(int const outFd, copyFile(userJobSetupFileName, outFd); if (renderGray) - XY_Puts(outFd,"@PJL SET RENDERMODE=GRAYSCALE\n"); + XY_Puts(outFd, "@PJL SET RENDERMODE=GRAYSCALE\n"); - XY_Puts(outFd,"@PJL ENTER LANGUAGE=PCLXL\n"); - XY_Puts(outFd,") HP-PCL XL;1;1;Generated by Netpbm Pnmtopclxl\n"); + XY_Puts(outFd, "@PJL ENTER LANGUAGE=PCLXL\n"); + XY_Puts(outFd, ") HP-PCL XL;1;1;Generated by Netpbm Pnmtopclxl\n"); } @@ -682,18 +864,6 @@ beginPage(int const outFd, -static void -openDataSource(int const outFd, - enum DataOrg const dataOrg, - enum DataSource const dataSource) { - - xl_ubyte(outFd, dataOrg); xl_attr_ubyte(outFd,aDataOrg); - xl_ubyte(outFd, dataSource); xl_attr_ubyte(outFd,aSourceType); - XL_Operator(outFd,oOpenDataSource); -} - - - static void setColorSpace(int const outFd, enum Colorspace const colorSpace, @@ -747,7 +917,7 @@ positionCursor(int const outFd, float const yoffs, int const imageWidth, int const imageHeight, - int const dpi, + unsigned int const dpi, enum MediaSize const format) { /*---------------------------------------------------------------------------- Emit printer control to position the cursor to start the page. @@ -770,88 +940,6 @@ positionCursor(int const outFd, -static void -convertAndWriteRleBlock(int const outFd, - const pclGenerator * const pclGeneratorP, - struct pam * const pamP, - int const firstLine, - int const nlines, - XY_rle * const rle) { - - unsigned char const pad[4] = {0,0,0,0}; - unsigned int const paddedLinelen = ((pclGeneratorP->linelen+3)/4)*4; - int rlelen; - unsigned int line; - - XY_RLEreset(rle); - - for (line = firstLine; line < firstLine + nlines; ++line) { - pclGeneratorP->getnextrow(pclGeneratorP, pamP); - XY_RLEput(rle, pclGeneratorP->data, pclGeneratorP->linelen); - XY_RLEput(rle, pad, paddedLinelen - pclGeneratorP->linelen); - } - rlelen = XY_RLEfinish(rle); - if (rlelen<0) - pm_error("Error on Making rle"); - - xl_dataLength(outFd, rlelen); - XY_Write(outFd, rle->fbuf, rlelen); -} - - - -/* - * ------------------------------------------------------------ - * XL_WriteImage - * Write a PCL-XL image to the datastream - * ------------------------------------------------------------ - */ -static void -convertAndWriteImage(int const outFd, - const pclGenerator * const pclGenP, - struct pam * const pamP) { - - int blockStartLine; - XY_rle * rle; - - xl_ubyte(outFd, eDirectPixel); xl_attr_ubyte(outFd, aColorMapping); - xl_ubyte(outFd, pclGenP->colorDepth); xl_attr_ubyte(outFd, aColorDepth); - xl_uint16(outFd, pclGenP->width); xl_attr_ubyte(outFd, aSourceWidth); - xl_uint16(outFd, pclGenP->height); xl_attr_ubyte(outFd, aSourceHeight); - xl_uint16_xy(outFd, pclGenP->width*1, pclGenP->height*1); - xl_attr_ubyte(outFd, aDestinationSize); - XL_Operator(outFd, oBeginImage); - - if (pclGenP->linelen > INT_MAX / 20) - pm_error("Image too big"); - rle = XY_RLEnew(pclGenP->linelen*20); - if (!rle) - pm_error("Unable to allocate %d bytes for the RLE buffer", - pclGenP->linelen * 20); - - blockStartLine = 0; - while (blockStartLine < pclGenP->height) { - unsigned int const blockHeight = - MIN(20, pclGenP->height-blockStartLine); - xl_uint16(outFd, blockStartLine); xl_attr_ubyte(outFd, aStartLine); - xl_uint16(outFd, blockHeight); xl_attr_ubyte(outFd, aBlockHeight); - xl_ubyte(outFd, eRLECompression); xl_attr_ubyte(outFd, aCompressMode); - /* In modern PCL-XL, we could use a PadBytesMultiple attribute - here to avoid having to pad the data to a multiple of 4 - bytes. But PCL-XL 1.1 didn't have PadBytesMultiple. - xl_ubyte(outFd, 1); xl_attr_ubyte(outFd, aPadBytesMultiple); - */ - XL_Operator(outFd, oReadImage); - convertAndWriteRleBlock(outFd, pclGenP, pamP, - blockStartLine, blockHeight, rle); - blockStartLine += blockHeight; - } - XY_RLEdelete(rle); - XL_Operator(outFd, oEndImage); -} - - - static void endPage(int const outFd, bool const doCopies, @@ -870,10 +958,10 @@ endPage(int const outFd, static void convertAndPrintPage(int const outFd, - const pclGenerator * const pclGeneratorP, + pclGenerator * const pclGeneratorP, struct pam * const pamP, enum MediaSize const format, - int const dpi, + unsigned int const dpi, bool const center, float const xoffs, float const yoffs, @@ -935,162 +1023,11 @@ endSession(int outFd) { -static void -pnmToPcllinePackbits(const pclGenerator * const pclGeneratorP, - struct pam * const pamP) { - - tuple * tuplerow; - unsigned int pcl_cursor; - unsigned char accum; - unsigned char bitmask; - unsigned int col; - - tuplerow = pnm_allocpamrow(pamP); - - pnm_readpamrow(pamP, tuplerow); - - pcl_cursor = 0; bitmask = 0x80; accum = 0x00; - for (col = 0; col < pamP->width; ++col) { - if (tuplerow[col][0] == PAM_PBM_WHITE) - accum |= bitmask; - bitmask >>= 1; - if (bitmask == 0) { - pclGeneratorP->data[pcl_cursor++] = accum; - bitmask = 0x80; accum = 0x0; - } - } - if (bitmask != 0x80) - pclGeneratorP->data[pcl_cursor++] = accum; - - pnm_freepamrow(tuplerow); -} - - - -static void -createPclGeneratorPackbits(struct pam * const pamP, - pclGenerator ** const pclGeneratorPP) { - - /* Samples are black or white and packed 8 to a byte */ - - pclGenerator * pclGeneratorP; - - MALLOCVAR_NOFAIL(pclGeneratorP); - - pclGeneratorP->colorDepth = e1Bit; - pclGeneratorP->colorSpace = eGray; - pclGeneratorP->linelen = (pamP->width+7)/8; - pclGeneratorP->height = pamP->height; - pclGeneratorP->width = (pamP->width); - - pclGeneratorP->data = malloc(pclGeneratorP->linelen); - - if (pclGeneratorP->data == NULL) - pm_error("Unable to allocate row buffer."); - - pclGeneratorP->getnextrow = pnmToPcllinePackbits; - - *pclGeneratorPP = pclGeneratorP; -} - - - -static void -pnmToPcllineWholebytes(const pclGenerator * const pclGeneratorP, - struct pam * const pamP) { - - tuple * tuplerow; - unsigned int pcl_cursor; - unsigned int col; - - tuplerow = pnm_allocpamrow(pamP); - - pnm_readpamrow(pamP, tuplerow); - - pcl_cursor = 0; /* initial value */ - - for (col = 0; col < pamP->width; ++col) { - unsigned int plane; - for (plane = 0; plane < pamP->depth; ++plane) { - pclGeneratorP->data[pcl_cursor++] = - pnm_scalesample(tuplerow[col][plane], pamP->maxval, 255); - } - } - pnm_freepamrow(tuplerow); -} - - - -static void -createPclGeneratorWholebytes(struct pam * const pamP, - pclGenerator ** const pclGenPP) { - /* One sample per byte */ - - pclGenerator * pclGenP; - - MALLOCVAR_NOFAIL(pclGenP); - - if (pamP->depth < 3) - pclGenP->colorSpace = eGray; - else - pclGenP->colorSpace = eRGB; - - pclGenP->colorDepth = e8Bit; - pclGenP->height = pamP->height; - pclGenP->width = pamP->width; - pclGenP->linelen = pamP->width * pamP->depth; - - if (UINT_MAX / pamP->width < pamP->depth) - pm_error("Image to big to process"); - else - pclGenP->data = malloc(pamP->width * pamP->depth); - - if (pclGenP->data == NULL) - pm_error("Unable to allocate row buffer."); - - pclGenP->getnextrow = pnmToPcllineWholebytes; - - *pclGenPP = pclGenP; -} - - - -static void -destroyPclGenerator(pclGenerator * const pclGenP) { - - free(pclGenP->data); - - free(pclGenP); -} - - - -static void -createPclGenerator(struct pam * const pamP, - pclGenerator ** const pclGeneratorPP, - bool const colorok) { - - if (pamP->depth > 1 && !colorok) - pm_message("WARNING: generating a color print stream because the " - "input image is PPM. " - "To generate a black and white print stream, run the input " - "through Ppmtopgm. To suppress this warning, use the " - "-colorok option."); - - if (pamP->depth == 1 && pamP->maxval == 1) - createPclGeneratorPackbits(pamP, pclGeneratorPP); - else - createPclGeneratorWholebytes(pamP, pclGeneratorPP); -} - - - - static void printPages(int const outFd, InputSource * const firstSourceP, enum MediaSize const format, - int const dpi, + unsigned int const dpi, bool const center, float const xoffs, float const yoffs, @@ -1116,12 +1053,12 @@ printPages(int const outFd, sourceNum = 0; /* initial value */ while (sourceP) { - FILE * in_file; + FILE * ifP; struct pam pam; - bool eof; + int eof; unsigned int pageNum; - in_file = pm_openr(sourceP->name); + ifP = pm_openr(sourceP->name); ++sourceNum; @@ -1129,14 +1066,14 @@ printPages(int const outFd, eof = FALSE; while(!eof) { - pnm_nextimage(in_file, &eof); + pnm_nextimage(ifP, &eof); if (!eof) { pclGenerator * pclGeneratorP; ++pageNum; pm_message("Processing File %u, Page %u", sourceNum, pageNum); - pnm_readpaminit(in_file, &pam, PAM_STRUCT_SIZE(tuple_type)); + pnm_readpaminit(ifP, &pam, PAM_STRUCT_SIZE(tuple_type)); createPclGenerator(&pam, &pclGeneratorP, colorok); @@ -1149,25 +1086,10 @@ printPages(int const outFd, destroyPclGenerator(pclGeneratorP); } } - pm_close(in_file); + pm_close(ifP); sourceP = sourceP->next; } - XL_Operator(outFd, oCloseDataSource); -} - - - -static void -freeSource(InputSource * const firstSourceP) { - - InputSource * sourceP; - - sourceP = firstSourceP; - while(sourceP) { - InputSource * const nextP = sourceP->next; - free(sourceP); - sourceP = nextP; - } + closeDataSource(outFd); } @@ -1189,25 +1111,28 @@ main(int argc, char *argv[]) { parseCommandLine(argc, argv, &cmdline); - jobHead(outFd, cmdline.rendergray, cmdline.jobsetup); - - beginSession(outFd, cmdline.dpi, cmdline.dpi, eInch, - FALSE, eBackChAndErrPage); - - printPages(outFd,cmdline.sourceP, - cmdline.format, cmdline.dpi, cmdline.center, - cmdline.xoffs, cmdline.yoffs, - cmdline.duplexSpec, cmdline.duplex, - cmdline.copiesSpec, cmdline.copies, - cmdline.feederSpec, cmdline.feeder, - cmdline.outtraySpec, cmdline.outtray, - cmdline.colorok - ); - endSession(outFd); - - jobEnd(outFd); - - freeSource(cmdline.sourceP); + if (cmdline.embedded) + printEmbeddedImage(outFd, cmdline.sourceP, cmdline.colorok); + else { + jobHead(outFd, cmdline.rendergray, cmdline.jobsetup); + + beginSession(outFd, cmdline.dpi, cmdline.dpi, eInch, + FALSE, eBackChAndErrPage); + + printPages(outFd, cmdline.sourceP, + cmdline.format, cmdline.dpi, cmdline.center, + cmdline.xoffs, cmdline.yoffs, + cmdline.duplexSpec, cmdline.duplex, + cmdline.copiesSpec, cmdline.copies, + cmdline.feederSpec, cmdline.feeder, + cmdline.outtraySpec, cmdline.outtray, + cmdline.colorok + ); + endSession(outFd); + + jobEnd(outFd); + } + freeCmdline(cmdline); return 0; } diff --git a/converter/other/pnmtopng.README b/converter/other/pnmtopng.README deleted file mode 100644 index bfa524dc..00000000 --- a/converter/other/pnmtopng.README +++ /dev/null @@ -1,101 +0,0 @@ -Pnmtopng and Pngtopnm are based on programs of the same name in the -Pnmtopng package owned by Alexander Lehmann and Willem Van Schaik, -available at http://www.libpng.org/pub/png/src on 2001.07.14. - -I added it to and adapted it to Netpbm on 2000.03.02 to make it more -easily available to people. I applied a patch on 2000.06.03 to bring -it up the 2.37.4 release of that package. I updated it again on -2001.07.14 to bring it up to Release 2.37.5. There is no process in -place to bring improvements to the base package into the Netpbm -version, but there hasn't been a lot of update activity anyway. - -Attached below is the file README from Release 2.37.5 of the base -package. - -Here are the differences between the base and the Netpbm version: - - I added an "unsigned" to make formal and actual arguments to png_sig_cmp() - match and quiet a compiler warning. - - I fixed an "include" statement so the dependencies work out right. - - I removed the BIGGRAYS stuff, which became obsolete in Netpbm 9.0 - - I replaced a PPM_MAXVAL with PPM_OVERALLMAXAL to handle the new 16 bits - formats. - - macro VERSION is defined directly in pngtopnm.c and pnmtopng.c instead - of being included via file version.h. - - Pnmtopng, since June 2001, reads one row at a time instead of holding - the entire image in memory. That makes it work with large bitmaps - where it would otherwise run out of memory. It also works faster with - bitmaps since a bit takes up only a bit of memory in a cached input - file, but 96 bits of memory after reading it into a Netpbm data - structure. - - The base Pnmtopng ignores -transparent if it specifies a color that - isn't in the image. Netpbm's Pnmtopng selects a nearby color that _is_ - in the image, which is what base Pnmtopng did before October 2000. - Netpbm's Pnmtopng lets you put an '=' sign before the color to specify - that you don't want a nearby color to be chosen, i.e. you want the - base Pnmtopng function. This is consistent with Pnmtogif. - -There were some other changes necessary before Netpbm 9.0, but the change -of the xelval type from 1 byte to 4 made them unnecessary. - - -** PNMTOPNG / PNGTOPNM -** version 2.37.5 - 24 October 2000 - -[This is a semi-official bug-fix and enhancement release; I sort of took over - maintenance of this package while Willem was on an extended bike trip, and - for now I'm continuing with periodic, small updates. Version 2.37 (March - 1998) was never publicly released, partly because Willem had hoped to quiet - gcc's " might be clobbered by `longjmp'" warnings. Those are fixed in - 2.37.2; under Solaris, they resulted in stack corruption even when there was - no error in the image files or libraries. Version 2.37.3 fixes a minor bug - w.r.t. error exits and generally does cleaner error exits (close files, etc.) - Version 2.37.4 fixes a bug that caused 16-shade grayscale images to be written - as 8-bit grayscale instead of (smaller) 4-bit colormapped images (bug report, - analysis and fix by Rafal Rzeczkowski), and it supports the new/upcoming - pbmplus release. Version 2.37.5 fixes a bug in -transparent handling (pnmtopng - no longer chooses an approximate color if the specified one isn't present) and - quiets a gcc warning in the non-16-bit version. - --Greg Roelofs] - -The utilities pnmtopng and pngtopnm are based on other pbm tools and require -the libraries included in the pbmplus/netpbm package. Also required are the -png library and the zlib compression library. - -These can be found at: - ftp://swrinde.nde.swri.edu/pub/png/src/libpng-* - ftp://swrinde.nde.swri.edu/pub/png/src/zlib-* - ftp://ftp.x.org/contrib/utilities/netpbm-1mar1994* -or see - http://www.libpng.org/pub/png/apps/pnmtopng.html - http://netpbm.sourceforge.net/ - http://www.acme.com/software/pbmplus/ [update coming soon?] - -To compile and install a makefile is provided. Do check the directories -where you have put the required libraries. Then either accommodate the -makefile or make links from generic names (e.g., zlib) to version-specific -directories (e.g., zlib-1.1.3), which is the recommended way. - -For testing purposes, have a look at the test-set PngSuite.tar.gz, which -contains a small test-image for every PNG color type and for most PNG chunk -types. It can be found at: - http://www.schaik.com/pngsuite/pngsuite.html - ftp://swrinde.nde.swri.edu/pub/png/images/suite/ - -Other web pages with PNG images are at: - http://www.libpng.org/pub/png/png-textures.html - http://www.libpng.org/pub/png/pngs-img.html - http://www.libpng.org/pub/png/pngpic2.html - http://www.libpng.org/pub/png/colorcube/ - http://www.libpng.org/pub/png/pngmisc.html#images - ------- -Alexander Lehmann -Willem van Schaik -Greg Roelofs diff --git a/converter/other/pnmtopng.c b/converter/other/pnmtopng.c index 52f69423..ac171453 100644 --- a/converter/other/pnmtopng.c +++ b/converter/other/pnmtopng.c @@ -1,6 +1,5 @@ /* -** pnmtopng.c - -** read a portable anymap and produce a Portable Network Graphics file +** read a PNM image and produce a Portable Network Graphics file ** ** derived from pnmtorast.c (c) 1990,1991 by Jef Poskanzer and some ** parts derived from ppmtogif.c by Marcel Wijkstra @@ -59,25 +58,22 @@ #include #include /* strcat() */ #include -#include /* includes zlib.h and setjmp.h */ +#include +/* Because of a design error in png.h, you must not #include before + . If you do, png.h won't compile. +*/ +#include +#include #include "pm_c_util.h" #include "pnm.h" +#include "pngx.h" #include "pngtxt.h" #include "shhopt.h" #include "mallocvar.h" #include "nstring.h" #include "version.h" -/* A hack until we can remove direct access to png_info from the program */ -#if PNG_LIBPNG_VER >= 10400 -#define trans_values trans_color -#define TRANS_ALPHA trans_alpha -#else -#define TRANS_ALPHA trans -#endif - - struct zlibCompression { /* These are parameters that describe a form of zlib compression. Values have the same meaning as the similarly named arguments to @@ -97,23 +93,6 @@ struct zlibCompression { unsigned int buffer_size; }; -struct chroma { - float wx; - float wy; - float rx; - float ry; - float gx; - float gy; - float bx; - float by; -}; - -struct phys { - int x; - int y; - int unit; -}; - typedef struct cahitem { xel color; gray alpha; @@ -127,7 +106,7 @@ struct cmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ - const char * inputFilename; /* '-' if stdin */ + const char * inputFileName; /* '-' if stdin */ const char * alpha; unsigned int verbose; unsigned int downscale; @@ -138,9 +117,11 @@ struct cmdlineInfo { float gamma; /* Meaningless if !gammaSpec */ unsigned int hist; unsigned int rgbSpec; - struct chroma rgb; /* Meaningless if !rgbSpec */ + struct pngx_chroma rgb; /* Meaningless if !rgbSpec */ unsigned int sizeSpec; - struct phys size; /* Meaningless if !sizeSpec */ + struct pngx_phys size; /* Meaningless if !sizeSpec */ + unsigned int srgbintentSpec; + pngx_srgbIntent srgbintent; const char * text; /* NULL if none */ const char * ztxt; /* NULL if none */ unsigned int modtimeSpec; @@ -149,7 +130,6 @@ struct cmdlineInfo { int filterSet; unsigned int force; unsigned int libversion; - unsigned int compressionSpec; struct zlibCompression zlibCompression; }; @@ -185,8 +165,8 @@ static int errorlevel; static void -parseSizeOpt(const char * const sizeOpt, - struct phys * const sizeP) { +parseSizeOpt(const char * const sizeOpt, + struct pngx_phys * const sizeP) { int count; @@ -200,8 +180,8 @@ parseSizeOpt(const char * const sizeOpt, static void -parseRgbOpt(const char * const rgbOpt, - struct chroma * const rgbP) { +parseRgbOpt(const char * const rgbOpt, + struct pngx_chroma * const rgbP) { int count; @@ -220,6 +200,27 @@ parseRgbOpt(const char * const rgbOpt, +static void +parseSrgbintentOpt(const char * const srgbintentOpt, + pngx_srgbIntent * const srgbintentP) { + + if (streq(srgbintentOpt, "perceptual")) + *srgbintentP = PNGX_PERCEPTUAL; + else if (streq(srgbintentOpt, "relativecolorimetric")) + *srgbintentP = PNGX_RELATIVE_COLORIMETRIC; + else if (streq(srgbintentOpt, "saturation")) + *srgbintentP = PNGX_SATURATION; + else if (streq(srgbintentOpt, "absolutecolorimetric")) + *srgbintentP = PNGX_ABSOLUTE_COLORIMETRIC; + else + pm_error("Unrecognized sRGB intent value '%s'. We understand " + "only 'perceptual', 'relativecolorimetric', " + "'saturation', and 'absolutecolorimetric'", + srgbintentOpt); +} + + + static void parseModtimeOpt(const char * const modtimeOpt, time_t * const modtimeP) { @@ -284,7 +285,7 @@ parseModtimeOpt(const char * const modtimeOpt, static void -parseCommandLine(int argc, char ** argv, +parseCommandLine(int argc, const char ** argv, struct cmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- parse program command line described in Unix standard form by argc @@ -297,7 +298,7 @@ parseCommandLine(int argc, char ** argv, was passed to us as the argv array. We also trash *argv. -----------------------------------------------------------------------------*/ optEntry *option_def; - /* Instructions to optParseOptions3 on how to parse our options. + /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; @@ -314,6 +315,7 @@ parseCommandLine(int argc, char ** argv, const char * modtime; const char * compMethod; const char * compStrategy; + const char * srgbintent; MALLOCARRAY_NOFAIL(option_def, 100); @@ -328,6 +330,8 @@ parseCommandLine(int argc, char ** argv, &cmdlineP->rgbSpec, 0); OPTENT3(0, "size", OPT_STRING, &size, &cmdlineP->sizeSpec, 0); + OPTENT3(0, "srgbintent", OPT_STRING, &srgbintent, + &cmdlineP->srgbintentSpec, 0); OPTENT3(0, "text", OPT_STRING, &cmdlineP->text, &textSpec, 0); OPTENT3(0, "ztxt", OPT_STRING, &cmdlineP->ztxt, @@ -392,7 +396,7 @@ parseCommandLine(int argc, char ** argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ @@ -455,6 +459,9 @@ parseCommandLine(int argc, char ** argv, if (cmdlineP->rgbSpec) parseRgbOpt(rgb, &cmdlineP->rgb); + if (cmdlineP->srgbintentSpec) + parseSrgbintentOpt(srgbintent, &cmdlineP->srgbintent); + if (cmdlineP->modtimeSpec) parseModtimeOpt(modtime, &cmdlineP->modtime); @@ -492,19 +499,41 @@ parseCommandLine(int argc, char ** argv, if (argc-1 < 1) - cmdlineP->inputFilename = "-"; + cmdlineP->inputFileName = "-"; else if (argc-1 == 1) - cmdlineP->inputFilename = argv[1]; + cmdlineP->inputFileName = argv[1]; else pm_error("Program takes at most one argument: input file name"); } +static void +reportInputType(int const format, + xelval const maxval) { + + switch (PNM_FORMAT_TYPE(format)) { + case PBM_TYPE: + pm_message ("reading a PBM file"); + break; + case PGM_TYPE: + pm_message ("reading a PGM file (maxval=%d)", maxval); + break; + case PPM_TYPE: + pm_message ("reading a PPM file (maxval=%d)", maxval); + break; + default: + assert(false); + } +} + + + static png_color_16 -xelToPngColor_16(xel const input, +xelToPngColor_16(xel const input, xelval const maxval, xelval const pngMaxval) { + png_color_16 retval; xel scaled; @@ -634,36 +663,6 @@ lookupColorAlpha(coloralphahash_table const caht, -static void -pnmtopng_error_handler(png_structp const png_ptr, - png_const_charp const msg) { - - jmpbuf_wrapper *jmpbuf_ptr; - - /* this function, aside from the extra step of retrieving the "error - * pointer" (below) and the fact that it exists within the application - * rather than within libpng, is essentially identical to libpng's - * default error handler. The second point is critical: since both - * setjmp() and longjmp() are called from the same code, they are - * guaranteed to have compatible notions of how big a jmp_buf is, - * regardless of whether _BSD_SOURCE or anything else has (or has not) - * been defined. */ - - fprintf(stderr, "pnmtopng: fatal libpng error: %s\n", msg); - fflush(stderr); - - jmpbuf_ptr = png_get_error_ptr(png_ptr); - if (jmpbuf_ptr == NULL) { /* we are completely hosed now */ - fprintf(stderr, - "pnmtopng: EXTREMELY fatal error: jmpbuf unrecoverable; terminating.\n"); - fflush(stderr); - exit(99); - } - - longjmp(jmpbuf_ptr->jmpbuf, 1); -} - - /* The following variables belong to getChv() and freeChv() */ static bool getChv_computed = FALSE; static colorhist_vector getChv_chv; @@ -907,7 +906,7 @@ tryTransparentColor(FILE * const ifp, pixel const transcolor, bool * const singleColorIsTransP) { - int const pnm_type = PNM_FORMAT_TYPE(format); + int const pnmType = PNM_FORMAT_TYPE(format); xel * xelrow; bool singleColorIsTrans; @@ -928,7 +927,7 @@ tryTransparentColor(FILE * const ifp, /* If we have a second transparent color, we're disqualified */ - if (pnm_type == PPM_TYPE) { + if (pnmType == PPM_TYPE) { if (!PPM_EQUAL(xelrow[col], transcolor)) singleColorIsTrans = FALSE; } else { @@ -945,7 +944,7 @@ tryTransparentColor(FILE * const ifp, the same color as our candidate transparent color, that disqualifies us. */ - if (pnm_type == PPM_TYPE) { + if (pnmType == PPM_TYPE) { if (PPM_EQUAL(xelrow[col], transcolor)) singleColorIsTrans = FALSE; } else { @@ -1049,6 +1048,170 @@ analyzeAlpha(FILE * const ifP, +static void +determineTransparency(struct cmdlineInfo const cmdline, + FILE * const ifP, + pm_filepos const rasterPos, + unsigned int const cols, + unsigned int const rows, + xelval const maxval, + int const format, + FILE * const afP, + bool * const alphaP, + int * const transparentP, + pixel * const transColorP, + bool * const transExactP, + gray *** const alphaMaskP, + gray * const alphaMaxvalP) { +/*---------------------------------------------------------------------------- + Determine the various aspects of transparency we need to generate the + PNG. + + Note that there are two kinds of transparency: pixel-by-pixel + transparency/translucency with an alpha mask and all pixels of a certain + color being transparent. Both these exist both in input from the user and + as representations in the PNG -- i.e. user may supply an alpha mask, + or identify a transparent color and the PNG may contain an alpha mask + or identify a transparent color. + + We return as *transparentP: + + -1 PNG is not to have single-color transparency + 1 PNG is to have single-color transparency as directed by user + 2 PNG is to have single-color transparency that effects an alpha + mask that the user supplied. + + In the cases where there is to be single-color transparency, *transColorP + is that color. +-----------------------------------------------------------------------------*/ + if (cmdline.alpha) { + pixel alphaTranscolor; + bool alphaCanBeTransparencyIndex; + bool allOpaque; + int alphaCols, alphaRows; + gray alphaMaxval; + gray ** alphaMask; + + if (verbose) + pm_message("reading alpha-channel image..."); + alphaMask = pgm_readpgm(afP, &alphaCols, &alphaRows, &alphaMaxval); + + if (alphaCols != cols || alphaRows != rows) { + pm_error("dimensions for image and alpha mask do not agree"); + } + analyzeAlpha(ifP, rasterPos, cols, rows, maxval, format, + alphaMask, alphaMaxval, &allOpaque, + &alphaCanBeTransparencyIndex, &alphaTranscolor); + + if (alphaCanBeTransparencyIndex && !cmdline.force) { + if (verbose) + pm_message("converting alpha mask to transparency index"); + *alphaP = FALSE; + *transparentP = 2; + *transColorP = alphaTranscolor; + } else if (allOpaque) { + if (verbose) + pm_message("Skipping alpha because mask is all opaque"); + *alphaP = FALSE; + *transparentP = -1; + } else { + *alphaP = TRUE; + *transparentP = -1; + } + *alphaMaxvalP = alphaMaxval; + *alphaMaskP = alphaMask; + } else { + /* Though there's no alpha_mask, we still need an alpha_maxval for + use with trans[], which can have stuff in it if the user specified + a transparent color. + */ + *alphaP = FALSE; + *alphaMaxvalP = 255; + + if (cmdline.transparent) { + const char * transstring2; + /* The -transparent value, but with possible leading '=' removed */ + if (cmdline.transparent[0] == '=') { + *transExactP = TRUE; + transstring2 = &cmdline.transparent[1]; + } else { + *transExactP = FALSE; + transstring2 = cmdline.transparent; + } + /* We do this funny PPM_DEPTH thing instead of just passing 'maxval' + to ppm_parsecolor() because ppm_parsecolor() does a cheap maxval + scaling, and this is more precise. + */ + PPM_DEPTH(*transColorP, + ppm_parsecolor(transstring2, PNM_OVERALLMAXVAL), + PNM_OVERALLMAXVAL, maxval); + + *transparentP = 1; + } else + *transparentP = -1; + } +} + + + +static void +determineBackground(struct cmdlineInfo const cmdline, + xelval const maxval, + xel * const backColorP) { + + if (cmdline.background) + PPM_DEPTH(*backColorP, + ppm_parsecolor(cmdline.background, PNM_OVERALLMAXVAL), + PNM_OVERALLMAXVAL, maxval);; +} + + + +static bool +hasColor(FILE * const ifP, + unsigned int const cols, + unsigned int const rows, + xelval const maxval, + int const format, + pm_filepos const rasterPos) { +/*---------------------------------------------------------------------------- + The image contains colors other than black, white, and gray. +-----------------------------------------------------------------------------*/ + bool retval; + + if (PNM_FORMAT_TYPE(format) == PPM_TYPE) { + unsigned int row; + xel * xelrow; /* malloc'ed */ + /* The row of the input image currently being analyzed */ + bool isGray; + + xelrow = pnm_allocrow(cols); + + pm_seek2(ifP, &rasterPos, sizeof(rasterPos)); + + for (row = 0, isGray = true; row < rows && isGray; ++row) { + unsigned int col; + + pnm_readpnmrow(ifP, xelrow, cols, maxval, format); + + for (col = 0; col < cols && isGray; ++col) { + xel const p = xelrow[col]; + if (PPM_GETR(p) != PPM_GETG(p) || PPM_GETG(p) != PPM_GETB(p)) + isGray = FALSE; + } + } + + pnm_freerow(xelrow); + + retval = !isGray; + } else + retval = false; + + return retval; +} + + + static void findRedundantBits(FILE * const ifp, int const rasterPos, @@ -1574,7 +1737,7 @@ makeOneColorTransparentInPalette(xel const transColor, *transSizeP = 1; if (verbose) { pixel const p = palette_pnm[0]; - pm_message("Making all occurences of color (%u, %u, %u) " + pm_message("Making all occurrences of color (%u, %u, %u) " "transparent.", PPM_GETR(p), PPM_GETG(p), PPM_GETB(p)); } @@ -1739,10 +1902,10 @@ tryAlphaPalette(FILE * const ifP, palette_pnm, trans_pnm, paletteSizeP, transSizeP, &tooBig); if (tooBig) { - asprintfN(impossibleReasonP, - "too many color/transparency pairs " - "(more than the PNG maximum of %u", - MAXPALETTEENTRIES); + pm_asprintf(impossibleReasonP, + "too many color/transparency pairs " + "(more than the PNG maximum of %u", + MAXPALETTEENTRIES); } else *impossibleReasonP = NULL; } @@ -1750,19 +1913,19 @@ tryAlphaPalette(FILE * const ifP, static void -computePixelWidth(int const pnm_type, - unsigned int const pnm_meaningful_bits, +computePixelWidth(bool const colorPng, + unsigned int const pnmMeaningfulBitCt, bool const alpha, unsigned int * const bitsPerSampleP, unsigned int * const bitsPerPixelP) { unsigned int bitsPerSample, bitsPerPixel; - if (pnm_type == PPM_TYPE || alpha) { + if (colorPng || alpha) { /* PNG allows only depths of 8 and 16 for a truecolor image and for a grayscale image with an alpha channel. */ - if (pnm_meaningful_bits > 8) + if (pnmMeaningfulBitCt > 8) bitsPerSample = 16; else bitsPerSample = 8; @@ -1770,24 +1933,24 @@ computePixelWidth(int const pnm_type, /* A grayscale, non-colormapped, no-alpha PNG may have any bit depth from 1 to 16 */ - if (pnm_meaningful_bits > 8) + if (pnmMeaningfulBitCt > 8) bitsPerSample = 16; - else if (pnm_meaningful_bits > 4) + else if (pnmMeaningfulBitCt > 4) bitsPerSample = 8; - else if (pnm_meaningful_bits > 2) + else if (pnmMeaningfulBitCt > 2) bitsPerSample = 4; - else if (pnm_meaningful_bits > 1) + else if (pnmMeaningfulBitCt > 1) bitsPerSample = 2; else bitsPerSample = 1; } if (alpha) { - if (pnm_type == PPM_TYPE) + if (colorPng) bitsPerPixel = 4 * bitsPerSample; else bitsPerPixel = 2 * bitsPerSample; } else { - if (pnm_type == PPM_TYPE) + if (colorPng) bitsPerPixel = 3 * bitsPerSample; else bitsPerPixel = bitsPerSample; @@ -1835,7 +1998,7 @@ computeColorMap(FILE * const ifP, int const cols, int const rows, xelval const maxval, - int const pnmType, + bool const colorPng, int const format, bool const force, FILE * const pfP, @@ -1868,29 +2031,35 @@ computeColorMap(FILE * const ifP, palette_pnm[] and trans_pnm[], allocated by Caller, with sizes *paletteSizeP and *transSizeP. + 'pfP' is a handle to the file that the user requested be used for the + palette (it's a Netpbm image whose colors are the colors of the palette). + 'pfP' is null if the user did not request a particular palette. + 'background' means the image is to have a background color, and that color is 'backcolor'. 'backcolor' is meaningless when 'background' is false. If the image is to have a background color, we return the palette index of that color as *backgroundIndexP. + + 'colorPng' means the PNG will be of the RGB variety. -------------------------------------------------------------------------- */ if (force) - asprintfN(noColormapReasonP, "You requested no color map"); + pm_asprintf(noColormapReasonP, "You requested no color map"); else if (maxval > PALETTEMAXVAL) - asprintfN(noColormapReasonP, "The maxval of the input image (%u) " - "exceeds the PNG palette maxval (%u)", - maxval, PALETTEMAXVAL); + pm_asprintf(noColormapReasonP, "The maxval of the input image (%u) " + "exceeds the PNG palette maxval (%u)", + maxval, PALETTEMAXVAL); else { unsigned int bitsPerPixel; - computePixelWidth(pnmType, pnm_meaningful_bits, alpha, + computePixelWidth(colorPng, pnm_meaningful_bits, alpha, NULL, &bitsPerPixel); if (!pfP && bitsPerPixel == 1) /* No palette can beat 1 bit per pixel -- no need to waste time counting the colors. */ - asprintfN(noColormapReasonP, "pixel is already only 1 bit"); + pm_asprintf(noColormapReasonP, "pixel is already only 1 bit"); else { /* We'll have to count the colors ('colors') to know if a palette is possible and desirable. Along the way, we'll @@ -1904,16 +2073,16 @@ computeColorMap(FILE * const ifP, &chv, &colors); if (chv == NULL) { - asprintfN(noColormapReasonP, - "More than %u colors found -- too many for a " - "colormapped PNG", MAXCOLORS); + pm_asprintf(noColormapReasonP, + "More than %u colors found -- too many for a " + "colormapped PNG", MAXCOLORS); } else { /* There are few enough colors that a palette is possible */ if (bitsPerPixel <= paletteIndexBits(colors) && !pfP) - asprintfN(noColormapReasonP, - "palette index for %u colors would be " - "no smaller than the indexed value (%u bits)", - colors, bitsPerPixel); + pm_asprintf(noColormapReasonP, + "palette index for %u colors would be " + "no smaller than the indexed value (%u bits)", + colors, bitsPerPixel); else { unsigned int paletteSize; unsigned int transSize; @@ -1996,9 +2165,9 @@ static void computeColorMapLookupTable( static void computeRasterWidth(bool const colorMapped, - unsigned int const palette_size, - int const pnm_type, - unsigned int const pnm_meaningful_bits, + unsigned int const paletteSize, + bool const colorPng, + unsigned int const pnmMeaningfulBitCt, bool const alpha, unsigned int * const bitsPerSampleP, unsigned int * const bitsPerPixelP) { @@ -2009,24 +2178,24 @@ computeRasterWidth(bool const colorMapped, -----------------------------------------------------------------------------*/ if (colorMapped) { /* The raster element is a palette index */ - if (palette_size <= 2) + if (paletteSize <= 2) *bitsPerSampleP = 1; - else if (palette_size <= 4) + else if (paletteSize <= 4) *bitsPerSampleP = 2; - else if (palette_size <= 16) + else if (paletteSize <= 16) *bitsPerSampleP = 4; else *bitsPerSampleP = 8; *bitsPerPixelP = *bitsPerSampleP; if (verbose) - pm_message("Writing %d-bit color indexes", *bitsPerSampleP); + pm_message("Writing %u-bit color indexes", *bitsPerSampleP); } else { /* The raster element is an explicit pixel -- color and transparency */ - computePixelWidth(pnm_type, pnm_meaningful_bits, alpha, + computePixelWidth(colorPng, pnmMeaningfulBitCt, alpha, bitsPerSampleP, bitsPerPixelP); if (verbose) - pm_message("Writing %d bits per component per pixel", + pm_message("Writing %u bits per component per pixel", *bitsPerSampleP); } } @@ -2068,41 +2237,28 @@ createPngPalette(pixel palette_pnm[], static void -setCompressionSize(png_struct * const png_ptr, - int const buffer_size) { - -#if PNG_LIBPNG_VER >= 10009 - png_set_compression_buffer_size(png_ptr, buffer_size); -#else - pm_error("Your PNG library cannot set the compression buffer size. " - "You need at least Version 1.0.9 of Libpng; you have Version %s", - PNG_LIBPNG_VER_STRING); -#endif -} - - - -static void -setZlibCompression(png_struct * const png_ptr, +setZlibCompression(struct pngx * const pngxP, struct zlibCompression const zlibCompression) { if (zlibCompression.levelSpec) - png_set_compression_level(png_ptr, zlibCompression.level); + png_set_compression_level(pngxP->png_ptr, zlibCompression.level); if (zlibCompression.memLevelSpec) - png_set_compression_mem_level(png_ptr, zlibCompression.mem_level); + png_set_compression_mem_level(pngxP->png_ptr, + zlibCompression.mem_level); if (zlibCompression.strategySpec) - png_set_compression_strategy(png_ptr, zlibCompression.strategy); + png_set_compression_strategy(pngxP->png_ptr, zlibCompression.strategy); if (zlibCompression.windowBitsSpec) - png_set_compression_window_bits(png_ptr, zlibCompression.window_bits); + png_set_compression_window_bits(pngxP->png_ptr, + zlibCompression.window_bits); if (zlibCompression.methodSpec) - png_set_compression_method(png_ptr, zlibCompression.method); + png_set_compression_method(pngxP->png_ptr, zlibCompression.method); if (zlibCompression.bufferSizeSpec) { - setCompressionSize(png_ptr, zlibCompression.buffer_size); + pngx_setCompressionSize(pngxP, zlibCompression.buffer_size); } } @@ -2117,7 +2273,7 @@ makePngLine(png_byte * const line, gray * const alpha_mask, colorhash_table const cht, coloralphahash_table const caht, - png_info * const info_ptr, + struct pngx * const pngxP, xelval const png_maxval, unsigned int const depth) { @@ -2129,20 +2285,20 @@ makePngLine(png_byte * const line, xel p_png; xel const p = xelrow[col]; PPM_DEPTH(p_png, p, maxval, png_maxval); - if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY || - info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { + if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_GRAY || + pngx_colorType(pngxP) == PNG_COLOR_TYPE_GRAY_ALPHA) { if (depth == 16) *pp++ = PNM_GET1(p_png) >> 8; *pp++ = PNM_GET1(p_png) & 0xff; - } else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { + } else if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_PALETTE) { unsigned int paletteIndex; if (alpha) paletteIndex = lookupColorAlpha(caht, &p, &alpha_mask[col]); else paletteIndex = ppm_lookupcolor(cht, &p); *pp++ = paletteIndex; - } else if (info_ptr->color_type == PNG_COLOR_TYPE_RGB || - info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { + } else if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_RGB || + pngx_colorType(pngxP) == PNG_COLOR_TYPE_RGB_ALPHA) { if (depth == 16) *pp++ = PPM_GETR(p_png) >> 8; *pp++ = PPM_GETR(p_png) & 0xff; @@ -2155,7 +2311,7 @@ makePngLine(png_byte * const line, } else pm_error("INTERNAL ERROR: undefined color_type"); - if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) { + if (pngx_colorType(pngxP) & PNG_COLOR_MASK_ALPHA) { int const png_alphaval = (int) alpha_mask[col] * (float) png_maxval / maxval + 0.5; if (depth == 16) @@ -2168,8 +2324,7 @@ makePngLine(png_byte * const line, static void -writeRaster(png_struct * const png_ptr, - png_info * const info_ptr, +writeRaster(struct pngx * const pngxP, FILE * const ifP, pm_filepos const rasterPos, unsigned int const cols, @@ -2177,14 +2332,14 @@ writeRaster(png_struct * const png_ptr, xelval const maxval, int const format, xelval const png_maxval, - unsigned const int depth, + unsigned int const depth, bool const alpha, gray ** const alpha_mask, colorhash_table const cht, coloralphahash_table const caht ) { /*---------------------------------------------------------------------------- - Write the PNG raster via compressor *png_ptr, reading the PNM raster + Write the PNG raster via compressor *pngxP, reading the PNM raster from file *ifP, position 'rasterPos'. The PNG raster consists of IDAT chunks. @@ -2202,7 +2357,7 @@ writeRaster(png_struct * const png_ptr, if (line == NULL) pm_error("out of memory allocating PNG row buffer"); - for (pass = 0; pass < png_set_interlace_handling(png_ptr); ++pass) { + for (pass = 0; pass < pngxP->numPassesRequired; ++pass) { unsigned int row; pm_seek2(ifP, &rasterPos, sizeof(rasterPos)); for (row = 0; row < rows; ++row) { @@ -2212,9 +2367,9 @@ writeRaster(png_struct * const png_ptr, makePngLine(line, xelrow, cols, maxval, alpha, alpha ? alpha_mask[row] : NULL, - cht, caht, info_ptr, png_maxval, depth); + cht, caht, pngxP, png_maxval, depth); - png_write_row(png_ptr, line); + pngx_writeRow(pngxP, line); } } pnm_freerow(xelrow); @@ -2223,78 +2378,212 @@ writeRaster(png_struct * const png_ptr, static void -doGamaChunk(struct cmdlineInfo const cmdline, - png_info * const info_ptr) { +doHistChunk(struct pngx * const pngxP, + bool const histRequested, + pixel const palettePnm[], + FILE * const ifP, + pm_filepos const rasterPos, + unsigned int const cols, + unsigned int const rows, + xelval const maxval, + int const format, + bool const verbose) { + + if (histRequested) { + colorhist_vector chv; + unsigned int colorCt; + colorhash_table cht; + + getChv(ifP, rasterPos, cols, rows, maxval, format, MAXCOLORS, + &chv, &colorCt); + + cht = ppm_colorhisttocolorhash(chv, colorCt); + + { + png_uint_16 * histogram; /* malloc'ed */ + + MALLOCARRAY(histogram, MAXCOLORS); + + if (!histogram) + pm_error("Failed to allocate memory for %u-color histogram", + MAXCOLORS); + else { + unsigned int i; + for (i = 0 ; i < MAXCOLORS; ++i) { + int const chvIndex = ppm_lookupcolor(cht, &palettePnm[i]); + if (chvIndex == -1) + histogram[i] = 0; + else + histogram[i] = chv[chvIndex].value; + } - if (cmdline.gammaSpec) { - /* gAMA chunk */ - info_ptr->valid |= PNG_INFO_gAMA; - info_ptr->gamma = cmdline.gamma; + pngx_setHist(pngxP, histogram); + + if (verbose) + pm_message("histogram created in PNG stream"); + } + } + ppm_freecolorhash(cht); } } +static void +doIhdrChunk(struct pngx * const pngxP, + unsigned int const width, + unsigned int const height, + unsigned int const depth, + bool const colorMapped, + bool const colorPng, + bool const alpha) { + + int colorType; + + if (colorMapped) + colorType = PNG_COLOR_TYPE_PALETTE; + else if (colorPng) + colorType = PNG_COLOR_TYPE_RGB; + else + colorType = PNG_COLOR_TYPE_GRAY; + + if (alpha && colorType != PNG_COLOR_TYPE_PALETTE) + colorType |= PNG_COLOR_MASK_ALPHA; + + pngx_setIhdr(pngxP, width, height, depth, colorType, 0, 0, 0); +} + + + +static void +doGamaChunk(struct cmdlineInfo const cmdline, + struct pngx * const pngxP) { + + if (cmdline.gammaSpec) + pngx_setGama(pngxP, cmdline.gamma); +} + + + static void doChrmChunk(struct cmdlineInfo const cmdline, - png_info * const info_ptr) { - - if (cmdline.rgbSpec) { - /* cHRM chunk */ - info_ptr->valid |= PNG_INFO_cHRM; - - info_ptr->x_white = cmdline.rgb.wx; - info_ptr->y_white = cmdline.rgb.wy; - info_ptr->x_red = cmdline.rgb.rx; - info_ptr->y_red = cmdline.rgb.ry; - info_ptr->x_green = cmdline.rgb.gx; - info_ptr->y_green = cmdline.rgb.gy; - info_ptr->x_blue = cmdline.rgb.bx; - info_ptr->y_blue = cmdline.rgb.by; - } + struct pngx * const pngxP) { + + if (cmdline.rgbSpec) + pngx_setChrm(pngxP, cmdline.rgb); } static void doPhysChunk(struct cmdlineInfo const cmdline, - png_info * const info_ptr) { + struct pngx * const pngxP) { - if (cmdline.sizeSpec) { - /* pHYS chunk */ - info_ptr->valid |= PNG_INFO_pHYs; + if (cmdline.sizeSpec) + pngx_setPhys(pngxP, cmdline.size); +} - info_ptr->x_pixels_per_unit = cmdline.size.x; - info_ptr->y_pixels_per_unit = cmdline.size.y; - info_ptr->phys_unit_type = cmdline.size.unit; - } + + +static void +doTimeChunk(struct cmdlineInfo const cmdline, + struct pngx * const pngxP) { + + if (cmdline.modtimeSpec) + pngx_setTime(pngxP, cmdline.modtime); } +static void +reportTrans(struct pngx * const pngxP) { + + if (pngx_chunkIsPresent(pngxP, PNG_INFO_tRNS)) { + struct pngx_trns const transInfo = pngx_trns(pngxP); + + pm_message("%u transparency values", transInfo.numTrans); + + pm_message("Transparent color {gray, red, green, blue} = " + "{%d, %d, %d, %d}", + transInfo.transColor.gray, + transInfo.transColor.red, + transInfo.transColor.green, + transInfo.transColor.blue); + } else + pm_message("No transparent color"); +} + static void -doTimeChunk(struct cmdlineInfo const cmdline, - png_info * const info_ptr) { +doTrnsChunk(struct pngx * const pngxP, + png_byte const transPalette[], + unsigned int const transPaletteSize, + int const transparent, + pixel const transColor, + xelval const maxval, + xelval const pngMaxval) { + + switch (pngx_colorType(pngxP)) { + case PNG_COLOR_TYPE_PALETTE: + if (transPaletteSize > 0) + pngx_setTrnsPalette(pngxP, transPalette, + transPaletteSize /* omit opaque values */); + break; + case PNG_COLOR_TYPE_GRAY: + case PNG_COLOR_TYPE_RGB: + if (transparent > 0) + pngx_setTrnsValue(pngxP, + xelToPngColor_16(transColor, maxval, pngMaxval)); + break; + default: + /* This is PNG_COLOR_MASK_ALPHA. Transparency will be handled + by the alpha channel, not a transparency color. + */ + {} + } + if (verbose) + reportTrans(pngxP); +} + - if (cmdline.modtimeSpec) { - /* tIME chunk */ - info_ptr->valid |= PNG_INFO_tIME; - png_convert_from_time_t(&info_ptr->mod_time, cmdline.modtime); +static void +doBkgdChunk(struct pngx * const pngxP, + bool const bkgdRequested, + unsigned int const backgroundIndex, + pixel const backColor, + xelval const maxval, + xelval const pngMaxval, + bool const verbose) { + + if (bkgdRequested) { + if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_PALETTE) + pngx_setBkgdPalette(pngxP, backgroundIndex); + else { + png_color_16 const pngBackground = + xelToPngColor_16(backColor, maxval, pngMaxval); + pngx_setBkgdRgb(pngxP, pngBackground); + if (verbose) + pm_message("Writing bKGD chunk with background color " + " {gray, red, green, blue} = {%d, %d, %d, %d}", + pngBackground.gray, + pngBackground.red, + pngBackground.green, + pngBackground.blue ); + } } } static void -doSbitChunk(png_info * const pngInfoP, - xelval const pngMaxval, - xelval const maxval, - bool const alpha, - xelval const alphaMaxval) { +doSbitChunk(struct pngx * const pngxP, + xelval const pngMaxval, + xelval const maxval, + bool const alpha, + xelval const alphaMaxval) { - if (pngInfoP->color_type != PNG_COLOR_TYPE_PALETTE && + if (pngx_colorType(pngxP) != PNG_COLOR_TYPE_PALETTE && (pngMaxval > maxval || (alpha && pngMaxval > alphaMaxval))) { /* We're writing in a bit depth that doesn't match the maxval @@ -2313,38 +2602,55 @@ doSbitChunk(png_info * const pngInfoP, sBIT chunk. */ - pngInfoP->valid |= PNG_INFO_sBIT; - { int const sbitval = pm_maxvaltobits(MIN(maxval, pngMaxval)); - if (pngInfoP->color_type & PNG_COLOR_MASK_COLOR) { - pngInfoP->sig_bit.red = sbitval; - pngInfoP->sig_bit.green = sbitval; - pngInfoP->sig_bit.blue = sbitval; + png_color_8 sbit; + + if (pngx_colorType(pngxP) & PNG_COLOR_MASK_COLOR) { + sbit.red = sbitval; + sbit.green = sbitval; + sbit.blue = sbitval; } else - pngInfoP->sig_bit.gray = sbitval; + sbit.gray = sbitval; if (verbose) pm_message("Writing sBIT chunk with bits = %d", sbitval); - } - if (pngInfoP->color_type & PNG_COLOR_MASK_ALPHA) { - pngInfoP->sig_bit.alpha = - pm_maxvaltobits(MIN(alphaMaxval, pngMaxval)); - if (verbose) - pm_message(" alpha bits = %d", pngInfoP->sig_bit.alpha); + + if (pngx_colorType(pngxP) & PNG_COLOR_MASK_ALPHA) { + sbit.alpha = pm_maxvaltobits(MIN(alphaMaxval, pngMaxval)); + if (verbose) + pm_message(" alpha bits = %d", sbit.alpha); + } + + pngx_setSbit(pngxP, sbit); } } } +static void +addSrgbChunk(struct pngx * const pngxP, + pngx_srgbIntent const srgbIntent) { + + pngx_setSrgb(pngxP, srgbIntent); + + if (verbose) { + pm_message("writing sRGB chunk with intent value %s", + pngx_srgbIntentDesc(srgbIntent)); + } +} + + + static void convertpnm(struct cmdlineInfo const cmdline, - FILE * const ifp, - FILE * const afp, - FILE * const pfp, - FILE * const tfp, + FILE * const ifP, + FILE * const ofP, + FILE * const afP, + FILE * const pfP, + FILE * const tfP, int * const errorLevelP ) { /*---------------------------------------------------------------------------- @@ -2353,439 +2659,238 @@ convertpnm(struct cmdlineInfo const cmdline, lazy -- it takes a great deal of work to carry all that information as separate arguments -- and it's only a very small violation. -----------------------------------------------------------------------------*/ - xel p; - int rows, cols, format; - xelval maxval; - /* The maxval of the input image */ - xelval png_maxval; - /* The maxval of the samples in the PNG output - (must be 1, 3, 7, 15, 255, or 65535) - */ - pixel transcolor; - /* The color that is to be transparent, with maxval equal to that - of the input image. - */ - int transexact; - /* boolean: the user wants only the exact color he specified to be - transparent; not just something close to it. - */ - int transparent; - bool alpha; - /* There will be an alpha mask */ - unsigned int pnm_meaningful_bits; - pixel backcolor; - /* The background color, with maxval equal to that of the input - image. - */ - png_struct *png_ptr; - png_info *info_ptr; - - bool colorMapped; - pixel palette_pnm[MAXCOLORS]; - png_color palette[MAXCOLORS]; - /* The color part of the color/alpha palette passed to the PNG - compressor - */ - unsigned int palette_size; - - gray trans_pnm[MAXCOLORS]; - png_byte trans[MAXCOLORS]; - /* The alpha part of the color/alpha palette passed to the PNG - compressor - */ - unsigned int trans_size; - - colorhash_table cht; - coloralphahash_table caht; - - unsigned int background_index; - /* Index into palette[] of the background color. */ - - png_uint_16 histogram[MAXCOLORS]; - gray alpha_maxval; - int alpha_rows; - int alpha_cols; - const char * noColormapReason; - /* The reason that we shouldn't make a colormapped PNG, or NULL if - we should. malloc'ed null-terminated string. - */ - unsigned int depth; - /* The number of bits per sample in the (uncompressed) png - raster -- if the raster contains palette indices, this is the - number of bits in the index. - */ - unsigned int fulldepth; - /* The total number of bits per pixel in the (uncompressed) png - raster, including all channels. - */ - pm_filepos rasterPos; - /* file position in input image file of start of image (i.e. after - the header) - */ - xel *xelrow; /* malloc'ed */ - /* The row of the input image currently being processed */ - - int pnm_type; - xelval maxmaxval; - gray ** alpha_mask; - - /* these guys are initialized to quiet compiler warnings: */ - maxmaxval = 255; - alpha_mask = NULL; - depth = 0; - errorlevel = 0; - - png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, - &pnmtopng_jmpbuf_struct, pnmtopng_error_handler, NULL); - if (png_ptr == NULL) { - pm_closer (ifp); - pm_error ("cannot allocate main libpng structure (png_ptr)"); - } - - info_ptr = png_create_info_struct (png_ptr); - if (info_ptr == NULL) { - png_destroy_write_struct (&png_ptr, (png_infopp)NULL); - pm_closer (ifp); - pm_error ("cannot allocate libpng info structure (info_ptr)"); - } - - if (setjmp (pnmtopng_jmpbuf_struct.jmpbuf)) { - png_destroy_write_struct (&png_ptr, &info_ptr); - pm_closer (ifp); - pm_error ("setjmp returns error condition (1)"); - } - - pnm_readpnminit (ifp, &cols, &rows, &maxval, &format); - pm_tell2(ifp, &rasterPos, sizeof(rasterPos)); - pnm_type = PNM_FORMAT_TYPE (format); - - xelrow = pnm_allocrow(cols); - - if (verbose) { - if (pnm_type == PBM_TYPE) - pm_message ("reading a PBM file (maxval=%d)", maxval); - else if (pnm_type == PGM_TYPE) - pm_message ("reading a PGM file (maxval=%d)", maxval); - else if (pnm_type == PPM_TYPE) - pm_message ("reading a PPM file (maxval=%d)", maxval); - } - - if (pnm_type == PGM_TYPE) - maxmaxval = PGM_OVERALLMAXVAL; - else if (pnm_type == PPM_TYPE) - maxmaxval = PPM_OVERALLMAXVAL; - - if (cmdline.transparent) { - const char * transstring2; - /* The -transparent value, but with possible leading '=' removed */ - if (cmdline.transparent[0] == '=') { - transexact = 1; - transstring2 = &cmdline.transparent[1]; - } else { - transexact = 0; - transstring2 = cmdline.transparent; - } - /* We do this funny PPM_DEPTH thing instead of just passing 'maxval' - to ppm_parsecolor() because ppm_parsecolor() does a cheap maxval - scaling, and this is more precise. - */ - PPM_DEPTH(transcolor, ppm_parsecolor(transstring2, maxmaxval), - maxmaxval, maxval); - } - if (cmdline.alpha) { - pixel alpha_transcolor; - bool alpha_can_be_transparency_index; - bool all_opaque; + int rows, cols, format; + xelval maxval; + /* The maxval of the input image */ + xelval pngMaxval; + /* The maxval of the samples in the PNG output + (must be 1, 3, 7, 15, 255, or 65535) + */ + pixel transcolor; + /* The color that is to be transparent, with maxval equal to that + of the input image. + */ + bool transExact; + /* boolean: the user wants only the exact color he specified to be + transparent; not just something close to it. + */ + int transparent; + bool alpha; + /* There will be an alpha mask */ + unsigned int pnmMeaningfulBitCt; + pixel backColor; + /* The background color, with maxval equal to that of the input + image. + */ + jmp_buf jmpbuf; + struct pngx * pngxP; + + bool colorMapped; + pixel palettePnm[MAXCOLORS]; + png_color palette[MAXCOLORS]; + /* The color part of the color/alpha palette passed to the PNG + compressor + */ + unsigned int paletteSize; + + gray transPnm[MAXCOLORS]; + png_byte trans[MAXCOLORS]; + /* The alpha part of the color/alpha palette passed to the PNG + compressor + */ + unsigned int transSize; + + colorhash_table cht; + coloralphahash_table caht; + + unsigned int backgroundIndex; + /* Index into palette[] of the background color. */ + + gray alphaMaxval; + const char * noColormapReason; + /* The reason that we shouldn't make a colormapped PNG, or NULL if + we should. malloc'ed null-terminated string. + */ + unsigned int depth; + /* The number of bits per sample in the (uncompressed) png + raster -- if the raster contains palette indices, this is the + number of bits in the index. + */ + unsigned int fulldepth; + /* The total number of bits per pixel in the (uncompressed) png + raster, including all channels. + */ + pm_filepos rasterPos; + /* file position in input image file of start of image (i.e. after + the header) + */ + xel * xelrow; /* malloc'ed */ + /* The row of the input image currently being processed */ + + gray ** alpha_mask; + + bool colorPng; + /* The PNG shall be of the color (RGB) variety */ + + /* We initialize these guys to quiet compiler warnings: */ + depth = 0; + + errorlevel = 0; + + if (setjmp(jmpbuf)) + pm_error ("setjmp returns error condition"); + + pngx_create(&pngxP, PNGX_WRITE, &jmpbuf); + + pnm_readpnminit(ifP, &cols, &rows, &maxval, &format); + pm_tell2(ifP, &rasterPos, sizeof(rasterPos)); + + xelrow = pnm_allocrow(cols); if (verbose) - pm_message ("reading alpha-channel image..."); - alpha_mask = pgm_readpgm (afp, &alpha_cols, &alpha_rows, &alpha_maxval); + reportInputType(format, maxval); + + determineTransparency(cmdline, ifP, rasterPos, cols, rows, maxval, format, + afP, + &alpha, &transparent, &transcolor, &transExact, + &alpha_mask, &alphaMaxval); - if (alpha_cols != cols || alpha_rows != rows) { - png_destroy_write_struct (&png_ptr, &info_ptr); - pm_closer (ifp); - pm_error ("dimensions for image and alpha mask do not agree"); + determineBackground(cmdline, maxval, &backColor); + + if (cmdline.force) + colorPng = (PNM_FORMAT_TYPE(format) == PPM_TYPE); + else { + if (PNM_FORMAT_TYPE(format) == PPM_TYPE) { + colorPng = hasColor(ifP, cols, rows, maxval, format, rasterPos); + } else + colorPng = false; } - analyzeAlpha(ifp, rasterPos, cols, rows, maxval, format, - alpha_mask, alpha_maxval, &all_opaque, - &alpha_can_be_transparency_index, &alpha_transcolor); - - if (alpha_can_be_transparency_index && !cmdline.force) { - if (verbose) - pm_message ("converting alpha mask to transparency index"); - alpha = FALSE; - transparent = 2; - transcolor = alpha_transcolor; - } else if (all_opaque) { - alpha = FALSE; - transparent = -1; - } else { - alpha = TRUE; - transparent = -1; + + + /* handle `odd' maxvalues */ + + if (maxval > 65535 && !cmdline.downscale) { + pm_error("can only handle files up to 16-bit " + "(use -downscale to override"); } - } else { - /* Though there's no alpha_mask, we still need an alpha_maxval for - use with trans[], which can have stuff in it if the user specified - a transparent color. - */ - alpha = FALSE; - alpha_maxval = 255; - transparent = cmdline.transparent ? 1 : -1; - } - if (cmdline.background) - PPM_DEPTH(backcolor, ppm_parsecolor(cmdline.background, maxmaxval), - maxmaxval, maxval);; - - /* first of all, check if we have a grayscale image written as PPM */ - - if (pnm_type == PPM_TYPE && !cmdline.force) { - unsigned int row; - bool isgray; - - isgray = TRUE; /* initial assumption */ - pm_seek2(ifp, &rasterPos, sizeof(rasterPos)); - for (row = 0; row < rows && isgray; ++row) { - unsigned int col; - pnm_readpnmrow(ifp, xelrow, cols, maxval, format); - for (col = 0; col < cols && isgray; ++col) { - p = xelrow[col]; - if (PPM_GETR(p) != PPM_GETG(p) || PPM_GETG(p) != PPM_GETB(p)) - isgray = FALSE; - } - } - if (isgray) - pnm_type = PGM_TYPE; - } - - /* handle `odd' maxvalues */ - - if (maxval > 65535 && !cmdline.downscale) { - png_destroy_write_struct(&png_ptr, &info_ptr); - pm_closer(ifp); - pm_error("can only handle files up to 16-bit " - "(use -downscale to override"); - } - - findRedundantBits(ifp, rasterPos, cols, rows, maxval, format, alpha, - cmdline.force, &pnm_meaningful_bits); + + findRedundantBits(ifP, rasterPos, cols, rows, maxval, format, alpha, + cmdline.force, &pnmMeaningfulBitCt); - computeColorMap(ifp, rasterPos, cols, rows, maxval, pnm_type, format, - cmdline.force, pfp, - alpha, transparent >= 0, transcolor, transexact, - !!cmdline.background, backcolor, - alpha_mask, alpha_maxval, pnm_meaningful_bits, - palette_pnm, &palette_size, trans_pnm, &trans_size, - &background_index, &noColormapReason); - - if (noColormapReason) { - if (pfp) - pm_error("You specified a particular palette, but this image " - "cannot be represented by any palette. %s", - noColormapReason); - if (verbose) - pm_message("Not using color map. %s", noColormapReason); - strfree(noColormapReason); - colorMapped = FALSE; - } else - colorMapped = TRUE; + computeColorMap(ifP, rasterPos, cols, rows, maxval, colorPng, format, + cmdline.force, pfP, + alpha, transparent >= 0, transcolor, transExact, + !!cmdline.background, backColor, + alpha_mask, alphaMaxval, pnmMeaningfulBitCt, + palettePnm, &paletteSize, transPnm, &transSize, + &backgroundIndex, &noColormapReason); + + if (noColormapReason) { + if (pfP) + pm_error("You specified a particular palette, but this image " + "cannot be represented by any palette. %s", + noColormapReason); + if (verbose) + pm_message("Not using color map. %s", noColormapReason); + pm_strfree(noColormapReason); + colorMapped = FALSE; + } else + colorMapped = TRUE; - computeColorMapLookupTable(colorMapped, palette_pnm, palette_size, - trans_pnm, trans_size, alpha, alpha_maxval, - &cht, &caht); - - computeRasterWidth(colorMapped, palette_size, pnm_type, - pnm_meaningful_bits, alpha, - &depth, &fulldepth); - if (verbose) - pm_message ("writing a%s %d-bit %s%s file%s", - fulldepth == 8 ? "n" : "", fulldepth, - colorMapped ? "palette": - (pnm_type == PPM_TYPE ? "RGB" : "gray"), - alpha ? (colorMapped ? "+transparency" : "+alpha") : "", - cmdline.interlace ? " (interlaced)" : ""); - - /* now write the file */ - - png_maxval = pm_bitstomaxval(depth); - - if (setjmp (pnmtopng_jmpbuf_struct.jmpbuf)) { - png_destroy_write_struct (&png_ptr, &info_ptr); - pm_closer (ifp); - pm_error ("setjmp returns error condition (2)"); - } - - png_init_io (png_ptr, stdout); - info_ptr->width = cols; - info_ptr->height = rows; - info_ptr->bit_depth = depth; - - if (colorMapped) - info_ptr->color_type = PNG_COLOR_TYPE_PALETTE; - else if (pnm_type == PPM_TYPE) - info_ptr->color_type = PNG_COLOR_TYPE_RGB; - else - info_ptr->color_type = PNG_COLOR_TYPE_GRAY; - - if (alpha && info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) - info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; - - info_ptr->interlace_type = cmdline.interlace; - - doGamaChunk(cmdline, info_ptr); - - doChrmChunk(cmdline, info_ptr); - - doPhysChunk(cmdline, info_ptr); - - if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { - - /* creating PNG palette (PLTE and tRNS chunks) */ - - createPngPalette(palette_pnm, palette_size, maxval, - trans_pnm, trans_size, alpha_maxval, - palette, trans); - info_ptr->valid |= PNG_INFO_PLTE; - info_ptr->palette = palette; - info_ptr->num_palette = palette_size; - if (trans_size > 0) { - info_ptr->valid |= PNG_INFO_tRNS; - info_ptr->TRANS_ALPHA = trans; - info_ptr->num_trans = trans_size; /* omit opaque values */ - } - /* creating hIST chunk */ - if (cmdline.hist) { - colorhist_vector chv; - unsigned int colors; - colorhash_table cht; - - getChv(ifp, rasterPos, cols, rows, maxval, format, MAXCOLORS, - &chv, &colors); + computeColorMapLookupTable(colorMapped, palettePnm, paletteSize, + transPnm, transSize, alpha, alphaMaxval, + &cht, &caht); - cht = ppm_colorhisttocolorhash (chv, colors); - - { - unsigned int i; - for (i = 0 ; i < MAXCOLORS; ++i) { - int const chvIndex = ppm_lookupcolor(cht, &palette_pnm[i]); - if (chvIndex == -1) - histogram[i] = 0; - else - histogram[i] = chv[chvIndex].value; - } - } + computeRasterWidth(colorMapped, paletteSize, colorPng, + pnmMeaningfulBitCt, alpha, + &depth, &fulldepth); + if (verbose) + pm_message ("writing a%s %d-bit %s%s file%s", + fulldepth == 8 ? "n" : "", fulldepth, + colorMapped ? "palette": + colorPng ? "RGB" : "gray", + alpha ? (colorMapped ? "+transparency" : "+alpha") : "", + cmdline.interlace ? " (interlaced)" : ""); - ppm_freecolorhash(cht); + /* now write the file */ - info_ptr->valid |= PNG_INFO_hIST; - info_ptr->hist = histogram; - if (verbose) - pm_message("histogram created"); - } - } else { /* color_type != PNG_COLOR_TYPE_PALETTE */ - if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY || - info_ptr->color_type == PNG_COLOR_TYPE_RGB) { - if (transparent > 0) { - info_ptr->valid |= PNG_INFO_tRNS; - info_ptr->trans_values = - xelToPngColor_16(transcolor, maxval, png_maxval); - } - } else { - /* This is PNG_COLOR_MASK_ALPHA. Transparency will be handled - by the alpha channel, not a transparency color. - */ + pngMaxval = pm_bitstomaxval(depth); + + if (setjmp (pnmtopng_jmpbuf_struct.jmpbuf)) { + pm_error ("setjmp returns error condition (2)"); } - if (verbose) { - if (info_ptr->valid && PNG_INFO_tRNS) - pm_message("Transparent color {gray, red, green, blue} = " - "{%d, %d, %d, %d}", - info_ptr->trans_values.gray, - info_ptr->trans_values.red, - info_ptr->trans_values.green, - info_ptr->trans_values.blue); - else - pm_message("No transparent color"); + + doIhdrChunk(pngxP, cols, rows, depth, colorMapped, colorPng, alpha); + + if (cmdline.interlace) + pngx_setInterlaceHandling(pngxP); + + doGamaChunk(cmdline, pngxP); + + doChrmChunk(cmdline, pngxP); + + doPhysChunk(cmdline, pngxP); + + if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_PALETTE) { + + /* creating PNG palette (Not counting the transparency palette) */ + + createPngPalette(palettePnm, paletteSize, maxval, + transPnm, transSize, alphaMaxval, + palette, trans); + pngx_setPlte(pngxP, palette, paletteSize); + + doHistChunk(pngxP, cmdline.hist, palettePnm, ifP, rasterPos, + cols, rows, maxval, format, cmdline.verbose); } - } - - /* bKGD chunk */ - if (cmdline.background) { - info_ptr->valid |= PNG_INFO_bKGD; - if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { - info_ptr->background.index = background_index; - } else { - info_ptr->background = - xelToPngColor_16(backcolor, maxval, png_maxval); - if (verbose) - pm_message("Writing bKGD chunk with background color " - " {gray, red, green, blue} = {%d, %d, %d, %d}", - info_ptr->background.gray, - info_ptr->background.red, - info_ptr->background.green, - info_ptr->background.blue ); - } - } - - doSbitChunk(info_ptr, png_maxval, maxval, alpha, alpha_maxval); - - /* tEXT and zTXT chunks */ - if (cmdline.text || cmdline.ztxt) - pnmpng_read_text(info_ptr, tfp, !!cmdline.ztxt, cmdline.verbose); - - doTimeChunk(cmdline, info_ptr); - - if (cmdline.filterSet != 0) - png_set_filter(png_ptr, 0, cmdline.filterSet); - - setZlibCompression(png_ptr, cmdline.zlibCompression); - - /* write the png-info struct */ - png_write_info(png_ptr, info_ptr); - - if (cmdline.text || cmdline.ztxt) - /* prevent from being written twice with png_write_end */ - info_ptr->num_text = 0; - - if (cmdline.modtime) - /* prevent from being written twice with png_write_end */ - info_ptr->valid &= ~PNG_INFO_tIME; - - /* let libpng take care of, e.g., bit-depth conversions */ - png_set_packing (png_ptr); - - writeRaster(png_ptr, info_ptr, ifp, rasterPos, cols, rows, maxval, format, - png_maxval, depth, alpha, alpha_mask, cht, caht); - - png_write_end (png_ptr, info_ptr); - - -#if 0 - /* The following code may be intended to solve some segfault problem - that arises with png_destroy_write_struct(). The latter is the - method recommended in the libpng documentation and this program - will not compile under Cygwin because the Windows DLL for libpng - does not contain png_write_destroy() at all. Since the author's - comment below does not make it clear what the segfault issue is, - we cannot consider it. -Bryan 00.09.15 -*/ - png_write_destroy (png_ptr); - /* flush first because free(png_ptr) can segfault due to jmpbuf problems - in png_write_destroy */ - fflush (stdout); - free (png_ptr); - free (info_ptr); -#else - png_destroy_write_struct(&png_ptr, &info_ptr); -#endif + doTrnsChunk(pngxP, trans, transSize, + transparent, transcolor, maxval, pngMaxval); - pnm_freerow(xelrow); + doBkgdChunk(pngxP, !!cmdline.background, + backgroundIndex, backColor, + maxval, pngMaxval, cmdline.verbose); - if (cht) - ppm_freecolorhash(cht); - if (caht) - freecoloralphahash(caht); + doSbitChunk(pngxP, pngMaxval, maxval, alpha, alphaMaxval); + + if (cmdline.srgbintentSpec) + addSrgbChunk(pngxP, cmdline.srgbintent); + + /* tEXT and zTXT chunks */ + if (cmdline.text || cmdline.ztxt) + pngtxt_addChunk(pngxP, tfP, !!cmdline.ztxt, false, cmdline.verbose); + + doTimeChunk(cmdline, pngxP); + + if (cmdline.filterSet != 0) + pngx_setFilter(pngxP, cmdline.filterSet); + + setZlibCompression(pngxP, cmdline.zlibCompression); + + png_init_io(pngxP->png_ptr, ofP); + + /* write the png-info struct */ + pngx_writeInfo(pngxP); + + /* let libpng take care of, e.g., bit-depth conversions */ + pngx_setPacking(pngxP); + + writeRaster(pngxP, ifP, rasterPos, + cols, rows, maxval, format, + pngMaxval, depth, alpha, alpha_mask, cht, caht); + + pngx_writeEnd(pngxP); + + pngx_destroy(pngxP); + + pnm_freerow(xelrow); + + if (cht) + ppm_freecolorhash(cht); + if (caht) + freecoloralphahash(caht); - *errorLevelP = errorlevel; + *errorLevelP = errorlevel; } @@ -2795,20 +2900,33 @@ displayVersion() { fprintf(stderr,"Pnmtopng version %s.\n", NETPBM_VERSION); - /* We'd like to display the version of libpng with which we're - linked, as we do for zlib, but it isn't practical. - While libpng is capable of telling you what it's level - is, different versions of it do it two different ways: with - png_libpng_ver or with png_get_header_ver. So we have to be - compiled for a particular version just to find out what - version it is! It's not worth having a link failure, much - less a compile failure, if we choose wrong. - png_get_header_ver is not in anything older than libpng 1.0.2a - (Dec 1998). png_libpng_ver is not there in libraries built - without USE_GLOBAL_ARRAYS. Cygwin versions are normally built - without USE_GLOBAL_ARRAYS. -bjh 2002.06.17. + /* We'd like to display the version of libpng with which we're _linked_ as + well as the one with which we're compiled, but it isn't practical. + While libpng is capable of telling you what it's level is, different + versions of it do it two different ways: with png_libpng_ver or with + png_get_header_ver. So we have to be compiled for a particular version + just to find out what version it is! It's not worth having a link + failure, much less a compile failure, if we choose wrong. + png_get_header_ver is not in anything older than libpng 1.0.2a (Dec + 1998). png_libpng_ver is not there in libraries built without + USE_GLOBAL_ARRAYS. Cygwin versions are normally built without + USE_GLOBAL_ARRAYS. -bjh 2002.06.17. + + We'd also like to display the version of libz with which we're linked, + with zlib_version (which nowadays is a macro for zlibVersion), but we + can't for reasons of modularity: We don't really link libz. libpng + does. It's none of our business whether libz is even present. And at + least on Mac OS X, we can't access libz's symbols from here -- we get + undefined reference to zlibVersion. We would have to explicitly link + libz just to find out its version. The right way to do this is for a + subroutine in libpng to give us the information. Until 10.07.08, we + did display zlib_version, but for years Mac OS X build was failing (and + we erroneously thought it was a libpng-config --ldflags bug). + + We _do_ use the compile-time part of libpng (), because it's + part of the interface to libpng. */ - fprintf(stderr, " Compiled with libpng %s.\n", + fprintf(stderr, " Pnmtopng Compiled with libpng %s.\n", PNG_LIBPNG_VER_STRING); fprintf(stderr, " Pnmtopng (not libpng) compiled with zlib %s.\n", ZLIB_VERSION); @@ -2818,7 +2936,7 @@ displayVersion() { int -main(int argc, char *argv[]) { +main(int argc, const char * argv[]) { struct cmdlineInfo cmdline; FILE * ifP; @@ -2828,7 +2946,7 @@ main(int argc, char *argv[]) { int errorlevel; - pnm_init(&argc, argv); + pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); @@ -2838,7 +2956,7 @@ main(int argc, char *argv[]) { } verbose = cmdline.verbose; - ifP = pm_openr_seekable(cmdline.inputFilename); + ifP = pm_openr_seekable(cmdline.inputFileName); if (cmdline.alpha) afP = pm_openr(cmdline.alpha); @@ -2857,7 +2975,7 @@ main(int argc, char *argv[]) { else tfP = NULL; - convertpnm(cmdline, ifP, afP, pfP, tfP, &errorlevel); + convertpnm(cmdline, ifP, stdout, afP, pfP, tfP, &errorlevel); if (afP) pm_close(afP); diff --git a/converter/other/pnmtops.c b/converter/other/pnmtops.c index 20395952..c1dadc3e 100644 --- a/converter/other/pnmtops.c +++ b/converter/other/pnmtops.c @@ -7,15 +7,19 @@ 1) Use built in Postscript filters /ASCII85Decode, /ASCIIHexDecode, /RunLengthDecode, and /FlateDecode; - We use methods we learned from Dirk Krause's program Bmeps and - raster encoding code copied almost directly from Bmeps. + We use methods we learned from Dirk Krause's program Bmeps. + Previous versions used raster encoding code based on Bmeps + code. This program does not used any code from Bmeps. 2) Use our own filters and redefine /readstring . This is aboriginal - Netpbm code, from when Postscript was young. + Netpbm code, from when Postscript was young. The filters are + nearly identical to /ASCIIHexDecode and /RunLengthDecode. We + use the same raster encoding code with slight modifications. - (2) is the default, because it's been working for ages and we have - more confidence in it. But (1) gives more options. The user - selects (1) with the -psfilter option. + (2) is the default. (1) gives more options, but relies on features + introduced in Postscript Level 2, which appeared in 1991. Postcript + devices made before 1991 can't handle them. The user selects (1) + with the -psfilter option. We also do a few other bold new things only when the user specifies -psfilter, because we're not sure they work for everyone. @@ -31,23 +35,63 @@ #define _BSD_SOURCE /* Make sure string.h contains strdup() */ #define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */ - -#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#ifndef NOFLATE +#include +#endif #include "pm_c_util.h" #include "pam.h" #include "mallocvar.h" #include "shhopt.h" #include "nstring.h" -#include "bmepsoe.h" +#include "runlength.h" + + + +static void +setSignals() { +/*---------------------------------------------------------------------------- + Set up the process-global signal-related state. + + Note that we can't rely on defaults, because much of this is inherited + from the process that forked and exec'ed this program. +-----------------------------------------------------------------------------*/ + /* See waitForChildren() for why we do this to SIGCHLD */ + + struct sigaction sigchldAction; + int rc; + sigset_t emptySet; + + sigemptyset(&emptySet); + + sigchldAction.sa_handler = SIG_DFL; + sigchldAction.sa_mask = emptySet; + sigchldAction.sa_flags = SA_NOCLDSTOP; + + rc = sigaction(SIGCHLD, &sigchldAction, NULL); + + if (rc != 0) + pm_error("sigaction() to set up signal environment failed, " + "errno = %d (%s)", errno, strerror(errno)); +} + + struct cmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ const char * inputFileName; /* Filespecs of input file */ - float scale; + float scale; unsigned int dpiX; /* horiz component of DPI option */ unsigned int dpiY; /* vert component of DPI option */ unsigned int width; /* in 1/72 inch */ @@ -59,6 +103,8 @@ struct cmdlineInfo { unsigned int imagewidth; /* in 1/72 inch; zero if unspec */ unsigned int imageheight; /* in 1/72 inch; zero if unspec */ unsigned int equalpixels; + unsigned int bitspersampleSpec; + unsigned int bitspersample; unsigned int setpage; bool showpage; unsigned int level; @@ -69,24 +115,29 @@ struct cmdlineInfo { unsigned int dict; unsigned int vmreclaim; unsigned int verbose; + unsigned int debug; }; - +static bool debug; static bool verbose; + static void parseDpi(const char * const dpiOpt, unsigned int * const dpiXP, unsigned int * const dpiYP) { char *dpistr2; - unsigned int dpiX, dpiY; + unsigned long int dpiX, dpiY; dpiX = strtol(dpiOpt, &dpistr2, 10); - if (dpistr2 == dpiOpt) + if (dpistr2 == dpiOpt) pm_error("Invalid value for -dpi: '%s'. Must be either number " "or NxN ", dpiOpt); + else if (dpiX > INT_MAX) + pm_error("Invalid value for -dpi: '%s'. " + "Value too large for computation", dpiOpt); else { if (*dpistr2 == '\0') { *dpiXP = dpiX; @@ -95,8 +146,11 @@ parseDpi(const char * const dpiOpt, char * dpistr3; dpistr2++; /* Move past 'x' */ - dpiY = strtol(dpistr2, &dpistr3, 10); - if (dpistr3 != dpistr2 && *dpistr3 == '\0') { + dpiY = strtol(dpistr2, &dpistr3, 10); + if (dpiY > INT_MAX) + pm_error("Invalid value for -dpi: '%s'. " + "Value too large for computation", dpiOpt); + else if (dpistr3 != dpistr2 && *dpistr3 == '\0') { *dpiXP = dpiX; *dpiYP = dpiY; } else { @@ -110,7 +164,50 @@ parseDpi(const char * const dpiOpt, static void -parseCommandLine(int argc, char ** argv, +validateBps_1_2_4_8_12(unsigned int const bitsPerSample) { + + switch (bitsPerSample) { + case 1: + case 2: + case 4: + case 8: + case 12: + break; + default: + pm_error("Invalid -bitspersample value: %u. Must be " + "1, 2, 4, 8, or 12", bitsPerSample); + } +} + + + +static void +validateCompDimension(unsigned int const value, + unsigned int const scaleFactor, + const char * const vname) { +/*---------------------------------------------------------------------------- + Validate that the image dimension (width or height) 'value' isn't so big + that in this program's calculations, involving scale factor 'scaleFactor', + it would cause a register overflow. If it is, abort the program and refer + to the offending dimension as 'vname' in the error message. + + Note that this early validation approach (calling this function) means + the actual computations don't have to be complicated with arithmetic + overflow checks, so they're easier to read. +-----------------------------------------------------------------------------*/ + if (value > 0) { + unsigned int const maxWidthHeight = INT_MAX - 2; + unsigned int const maxScaleFactor = maxWidthHeight / value; + + if (scaleFactor > maxScaleFactor) + pm_error("%s is too large for compuations: %u", vname, value); + } +} + + + +static void +parseCommandLine(int argc, const char ** argv, struct cmdlineInfo * const cmdlineP) { unsigned int imagewidthSpec, imageheightSpec; @@ -120,19 +217,19 @@ parseCommandLine(int argc, char ** argv, float width, height; unsigned int noturn; unsigned int showpage, noshowpage; - const char *dpiOpt; - unsigned int dpiSpec; + const char * dpiOpt; + unsigned int dpiSpec, scaleSpec, widthSpec, heightSpec; optStruct3 opt; unsigned int option_def_index = 0; - optEntry *option_def; + optEntry * option_def; MALLOCARRAY_NOFAIL(option_def, 100); - OPTENT3(0, "scale", OPT_FLOAT, &cmdlineP->scale, NULL, 0); + OPTENT3(0, "scale", OPT_FLOAT, &cmdlineP->scale, &scaleSpec, 0); OPTENT3(0, "dpi", OPT_STRING, &dpiOpt, &dpiSpec, 0); - OPTENT3(0, "width", OPT_FLOAT, &width, NULL, 0); - OPTENT3(0, "height", OPT_FLOAT, &height, NULL, 0); + OPTENT3(0, "width", OPT_FLOAT, &width, &widthSpec, 0); + OPTENT3(0, "height", OPT_FLOAT, &height, &heightSpec, 0); OPTENT3(0, "psfilter", OPT_FLAG, NULL, &cmdlineP->psfilter, 0); OPTENT3(0, "turn", OPT_FLAG, NULL, &cmdlineP->mustturn, 0); OPTENT3(0, "noturn", OPT_FLAG, NULL, ¬urn, 0); @@ -144,6 +241,8 @@ parseCommandLine(int argc, char ** argv, OPTENT3(0, "equalpixels", OPT_FLAG, NULL, &cmdlineP->equalpixels, 0); OPTENT3(0, "imagewidth", OPT_FLOAT, &imagewidth, &imagewidthSpec, 0); OPTENT3(0, "imageheight", OPT_FLOAT, &imageheight, &imageheightSpec, 0); + OPTENT3(0, "bitspersample", OPT_UINT, &cmdlineP->bitspersample, + &cmdlineP->bitspersampleSpec, 0); OPTENT3(0, "nosetpage", OPT_FLAG, NULL, &nosetpage, 0); OPTENT3(0, "setpage", OPT_FLAG, NULL, &cmdlineP->setpage, 0); OPTENT3(0, "noshowpage", OPT_FLAG, NULL, &noshowpage, 0); @@ -152,19 +251,15 @@ parseCommandLine(int argc, char ** argv, OPTENT3(0, "vmreclaim", OPT_FLAG, NULL, &cmdlineP->vmreclaim, 0); OPTENT3(0, "showpage", OPT_FLAG, NULL, &showpage, 0); OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); + OPTENT3(0, "debug", OPT_FLAG, NULL, &cmdlineP->debug, 0); OPTENT3(0, "level", OPT_UINT, &cmdlineP->level, &cmdlineP->levelSpec, 0); - /* DEFAULTS */ - cmdlineP->scale = 1.0; - width = 8.5; - height = 11.0; - opt.opt_table = option_def; opt.short_allowed = FALSE; opt.allowNegNum = FALSE; - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); if (cmdlineP->mustturn && noturn) pm_error("You cannot specify both -turn and -noturn"); @@ -175,6 +270,15 @@ parseCommandLine(int argc, char ** argv, if (cmdlineP->setpage && nosetpage) pm_error("You cannot specify both -setpage and -nosetpage"); + if (!scaleSpec) + cmdlineP->scale = 1.0; + + if (!widthSpec) + width = 8.5; + + if (!heightSpec) + height = 11.0; + if (dpiSpec) parseDpi(dpiOpt, &cmdlineP->dpiX, &cmdlineP->dpiY); else { @@ -185,16 +289,23 @@ parseCommandLine(int argc, char ** argv, cmdlineP->center = !nocenter; cmdlineP->canturn = !noturn; cmdlineP->showpage = !noshowpage; + + validateCompDimension(width, 72, "-width value"); + validateCompDimension(height, 72, "-height value"); cmdlineP->width = width * 72; cmdlineP->height = height * 72; - if (imagewidthSpec) + if (imagewidthSpec) { + validateCompDimension(imagewidth, 72, "-imagewidth value"); cmdlineP->imagewidth = imagewidth * 72; + } else cmdlineP->imagewidth = 0; - if (imageheightSpec) + if (imageheightSpec) { + validateCompDimension(imagewidth, 72, "-imageheight value"); cmdlineP->imageheight = imageheight * 72; + } else cmdlineP->imageheight = 0; @@ -203,6 +314,9 @@ parseCommandLine(int argc, char ** argv, pm_error("You must specify -psfilter in order to specify " "-flate or -ascii85"); + if (cmdlineP->bitspersampleSpec) + validateBps_1_2_4_8_12(cmdlineP->bitspersample); + if (argc-1 == 0) cmdlineP->inputFileName = "-"; else if (argc-1 != 1) @@ -211,320 +325,715 @@ parseCommandLine(int argc, char ** argv, else cmdlineP->inputFileName = argv[1]; + free(option_def); } -/*=========================================================================== - The native output encoder. This is archaic and uses global variables. - It is probably obsoleted by the bmeps output encoder; we just haven't - had a chance to verify that yet. -===========================================================================*/ +static bool +progIsFlateCapable(void) { + + return +#ifdef NOFLATE + false +#else + true +#endif + ; +} + + + +static const char * +basebasename(const char * const filespec) { /*---------------------------------------------------------------------------- - The following global variables are the native output encoder state. + Return filename up to first period -----------------------------------------------------------------------------*/ -static unsigned int itemsinline; - /* The number of items in the line we are currently building */ -static unsigned int bitsinitem; - /* The number of bits filled so far in the item we are currently - building - */ -static unsigned int rlebitsinitem; - /* The number of bits filled so far in the item we are currently - building - */ -static unsigned int bitspersample; -static unsigned int item, bitshift, items; -static unsigned int rleitem, rlebitshift; -static unsigned int repeat, itembuf[128], count, repeatitem, repeatcount; + char const dirsep = '/'; + const char * const lastSlashPos = strrchr(filespec, dirsep); + + char * name; + const char * filename; + + if (lastSlashPos) + filename = lastSlashPos + 1; + else + filename = filespec; + + name = strdup(filename); + if (name != NULL) { + char * const dotPosition = strchr(name, '.'); + + if (dotPosition) + *dotPosition = '\0'; + } + return name; +} static void -initNativeOutputEncoder(bool const rle, unsigned int const bitspersample) { -/*---------------------------------------------------------------------------- - Initialize the native output encoder. Call this once per - Postscript image that you will write with putitem(), before for the - first putitem(). +writeFile(const unsigned char * const buffer, + size_t const writeCt, + const char * const name, + FILE * const ofP) { - We initialize the item putter state variables, which are the - global variable defined above. ------------------------------------------------------------------------------*/ - itemsinline = 0; - items = 0; + size_t writtenCt; + + writtenCt = fwrite(buffer, 1, writeCt, ofP); + + if (writtenCt != writeCt) + pm_error("Error writing to %s output file", name); +} + + + +static void +writeFileChar(const char * const buffer, + size_t const writeCt, + const char * const name, + FILE * const ofP) { + + writeFile((const unsigned char *)buffer, writeCt, name, ofP); +} - if (rle) { - rleitem = 0; - rlebitsinitem = 0; - rlebitshift = 8 - bitspersample; - repeat = 1; - count = 0; - } else { - item = 0; - bitsinitem = 0; - bitshift = 8 - bitspersample; - } + +#define MAX_FILTER_CT 10 + /* The maximum number of filters this code is capable of applying */ + + + +static void +initPidList(pid_t * const pidList) { + + pidList[0] = (pid_t)0; /* end of list marker */ } static void -putitem(void) { - const char* const hexits = "0123456789abcdef"; +addToPidList(pid_t * const pidList, + pid_t const newPid) { + + unsigned int i; + + for (i = 0; i < MAX_FILTER_CT && pidList[i]; ++i); - if (itemsinline == 30) { - putchar('\n'); - itemsinline = 0; + assert(i < MAX_FILTER_CT); + + pidList[i] = newPid; + pidList[i+1] = (pid_t)0; /* end of list marker */ +} + + + +/*=========================================================================== + The output encoder + ===========================================================================*/ + +enum OutputType {AsciiHex, Ascii85}; + +typedef struct { + enum OutputType outputType; + bool compressRle; + bool compressFlate; + unsigned int runlengthRefresh; +} OutputEncoder; + + + +static unsigned int +bytesPerRow (unsigned int const cols, + unsigned int const bitsPerSample) { +/*---------------------------------------------------------------------------- + Size of row buffer, padded up to byte boundary, given that the image + has 'cols' samples per row, 'bitsPerSample' bits per sample. +-----------------------------------------------------------------------------*/ + unsigned int retval; + + assert(bitsPerSample==1 || bitsPerSample==2 || bitsPerSample==4 || + bitsPerSample==8 || bitsPerSample==12); + + switch (bitsPerSample) { + case 1: + case 2: + case 4: + retval = cols / (8/bitsPerSample) + + (cols % (8/bitsPerSample) > 0 ? 1 : 0); + /* A more straightforward calculation would be + (cols * bitsPerSample + 7) / 8 , + but this overflows when icols is large. + */ + break; + case 8: + retval = cols; + break; + case 12: + retval = cols + (cols+1)/2; + break; } - assert(item >> 8 == 0); - putchar(hexits[item >> 4]); - putchar(hexits[item & 15]); - ++itemsinline; - ++items; - item = 0; - bitsinitem = 0; - bitshift = 8 - bitspersample; + + return retval; } static void -flushitem() { - if (bitsinitem > 0) - putitem(); +initOutputEncoder(OutputEncoder * const oeP, + unsigned int const icols, + unsigned int const bitsPerSample, + bool const rle, + bool const flate, + bool const ascii85, + bool const psFilter) { + + oeP->outputType = ascii85 ? Ascii85 : AsciiHex; + + if (rle) { + oeP->compressRle = true; + oeP->runlengthRefresh = + psFilter ? 1024*1024*16 : bytesPerRow(icols, bitsPerSample); + } else + oeP->compressRle = false; + + if (flate) { + assert(psFilter); + oeP->compressFlate = true; + } else + oeP->compressFlate = false; + + if (ascii85) { + assert(psFilter); + oeP->outputType = Ascii85; + } else + oeP->outputType = AsciiHex; } +typedef void FilterFn(FILE * const ifP, + FILE * const ofP, + OutputEncoder * const oeP); + /* This is a function that can be run in a separate process to do + arbitrary modifications of the raster data stream. + */ + + + +#ifndef NOFLATE +static void +initZlib(z_stream * const strmP) { + + int const level = 9; /* maximum compression. see zlib.h */ + + int ret; + + /* allocate deflate state */ + strmP->zalloc = Z_NULL; + strmP->zfree = Z_NULL; + strmP->opaque = Z_NULL; + + ret = deflateInit(strmP, level); + if (ret != Z_OK) + pm_error("Failed to initialize zlib."); +} +#endif + + + +static FilterFn flateFilter; + static void -putxelval(xelval const xv) { - if (bitsinitem == 8) - putitem(); - item += xv << bitshift; - bitsinitem += bitspersample; - bitshift -= bitspersample; +flateFilter(FILE * const ifP, + FILE * const ofP, + OutputEncoder * const oeP) { + +#ifndef NOFLATE + + /* This code is based on def() in zpipe.c. zpipe is an example program + which comes with the zlib source package. zpipe.c is public domain and + is available from the Zlib website: http://www.zlib.net/ + + See zlib.h for details on zlib parameters Z_NULL, Z_OK, etc. + */ + unsigned int const chunkSz = 128*1024; + /* 128K recommended in zpipe.c. 4096 is not efficient but works. */ + + int flush; + z_stream strm; + unsigned char * in; + unsigned char * out; + + in = pm_allocrow(chunkSz, 1); + out = pm_allocrow(chunkSz, 1); + + initZlib(&strm); + + /* compress until end of file */ + do { + strm.avail_in = fread(in, 1, chunkSz, ifP); + if (ferror(ifP)) { + deflateEnd(&strm); + pm_error("Error reading from internal pipe during " + "flate compression."); + } + flush = feof(ifP) ? Z_FINISH : Z_NO_FLUSH; + strm.next_in = in; + + /* run deflate() on input until output buffer not full, finish + compression if we have reached end of input. + */ + do { + unsigned int have; + + strm.avail_out = chunkSz; + strm.next_out = out; + deflate(&strm, flush); + have = chunkSz - strm.avail_out; + writeFile(out, have, "flate filter", ofP); + } while (strm.avail_out == 0); + assert(strm.avail_in == 0); /* all input is used */ + + /* done when last data in file processed */ + } while (flush != Z_FINISH); + + free(in); + free(out); + deflateEnd(&strm); + fclose(ifP); + fclose(ofP); +#else + assert(false); /* filter is never used */ +#endif } +/* Run length encoding + + In this simple run-length encoding scheme, compressed and uncompressed + strings follow a single index byte N. N 0-127 means the next N+1 + bytes are uncompressed; 129-255 means the next byte is to be repeated + 257-N times. + + In native (non-psfilter) mode, the run length filter must flush at + the end of every row. But the entire raster is sent to the run length + filter as one continuous stream. The run length filter learns the + refresh interval from oeP->runlengthRefresh. In ps-filter mode the + run length filter ignores row boundaries and flushes every 4096 bytes. +*/ + +static FilterFn rleFilter; + static void -rleputbuffer() { - if (repeat) { - item = 256 - count; - putitem(); - item = repeatitem; - putitem(); - } else { - unsigned int i; - - item = count - 1; - putitem(); - for (i = 0; i < count; ++i) { - item = itembuf[i]; - putitem(); - } +rleFilter (FILE * const ifP, + FILE * const ofP, + OutputEncoder * const oeP) { + + unsigned int const inSize = oeP->runlengthRefresh; + + bool eof; + unsigned char * inbuf; + unsigned char * outbuf; + size_t outSize; + + MALLOCARRAY(inbuf, inSize); + if (inbuf == NULL) + pm_error("Failed to allocate %u bytes of memory for RLE filter", + inSize); + pm_rlenc_allocoutbuf(&outbuf, inSize, PM_RLE_PACKBITS); + + for (eof = false; !eof; ) { + size_t const bytesRead = fread(inbuf, 1, inSize, ifP); + + if (feof(ifP)) + eof = true; + else if (ferror(ifP) || bytesRead == 0) + pm_error("Internal read error: RLE compression"); + + pm_rlenc_compressbyte(inbuf, outbuf, PM_RLE_PACKBITS, + bytesRead, &outSize); + writeFile(outbuf, outSize, "rlePutBuffer", ofP); } - repeat = 1; - count = 0; + + fclose(ifP); + fclose(ofP); } +static FilterFn asciiHexFilter; + static void -rleputitem() { - int i; +asciiHexFilter(FILE * const ifP, + FILE * const ofP, + OutputEncoder * const oeP) { - if ( count == 128 ) - rleputbuffer(); + char const hexits[16] = "0123456789abcdef"; - if ( repeat && count == 0 ) - { /* Still initializing a repeat buf. */ - itembuf[count] = repeatitem = rleitem; - ++count; - } - else if ( repeat ) - { /* Repeating - watch for end of run. */ - if ( rleitem == repeatitem ) - { /* Run continues. */ - itembuf[count] = rleitem; - ++count; - } - else - { /* Run ended - is it long enough to dump? */ - if ( count > 2 ) - { /* Yes, dump a repeat-mode buffer and start a new one. */ - rleputbuffer(); - itembuf[count] = repeatitem = rleitem; - ++count; - } - else - { /* Not long enough - convert to non-repeat mode. */ - repeat = 0; - itembuf[count] = repeatitem = rleitem; - ++count; - repeatcount = 1; + bool eof; + unsigned char inbuff[40], outbuff[81]; + + for (eof = false; !eof; ) { + size_t readCt; + + readCt = fread(inbuff, 1, 40, ifP); + + if (readCt == 0) + eof = true; + else { + unsigned int i; + + for (i = 0; i < readCt; ++i) { + int const item = inbuff[i]; + outbuff[i*2] = hexits[item >> 4]; + outbuff[i*2+1] = hexits[item & 15]; } + outbuff[readCt * 2] = '\n'; + writeFile(outbuff, readCt * 2 + 1, "asciiHex filter", ofP); } } - else - { /* Not repeating - watch for a run worth repeating. */ - if ( rleitem == repeatitem ) - { /* Possible run continues. */ - ++repeatcount; - if ( repeatcount > 3 ) - { /* Long enough - dump non-repeat part and start repeat. */ - count = count - ( repeatcount - 1 ); - rleputbuffer(); - count = repeatcount; - for ( i = 0; i < count; ++i ) - itembuf[i] = rleitem; + + fclose(ifP); + fclose(ofP); +} + + + +static FilterFn ascii85Filter; + +static void +ascii85Filter(FILE * const ifP, + FILE * const ofP, + OutputEncoder * const oeP) { + + bool eof; + char outbuff[5]; + unsigned long int value; /* requires 32 bits */ + int count; + int outcount; + + value = 0; /* initial value */ + count = 0; /* initial value */ + outcount = 0; /* initial value */ + + for (eof = false; !eof; ) { + int c; + + c = fgetc(ifP); + + if (c == EOF) + eof = true; + else { + value = value*256 + c; + ++count; + + if (value == 0 && count == 4) { + writeFileChar("z", 1, "ASCII 85 filter", ofP); + /* Ascii85 encoding z exception */ + ++outcount; + count = 0; + } else if (count == 4) { + outbuff[4] = value % 85 + 33; value/=85; + outbuff[3] = value % 85 + 33; value/=85; + outbuff[2] = value % 85 + 33; value/=85; + outbuff[1] = value % 85 + 33; + outbuff[0] = value / 85 + 33; + + writeFileChar(outbuff, count + 1, "ASCII 85 filter", ofP); + + count = value = 0; + outcount += 5; } - else - { /* Not long enough yet - continue as non-repeat buf. */ - itembuf[count] = rleitem; - ++count; + + if (outcount > 75) { + writeFileChar("\n", 1, "ASCII 85 filter", ofP); + outcount = 0; } } - else - { /* Broken run. */ - itembuf[count] = repeatitem = rleitem; - ++count; - repeatcount = 1; - } } - rleitem = 0; - rlebitsinitem = 0; - rlebitshift = 8 - bitspersample; -} + if (count > 0) { /* EOF, flush */ + assert (count < 4); + value <<= (4 - count) * 8; value/=85; + outbuff[3] = value % 85 + 33; value/=85; + outbuff[2] = value % 85 + 33; value/=85; + outbuff[1] = value % 85 + 33; + outbuff[0] = value / 85 + 33; + outbuff[count + 1] = '\n'; + writeFileChar(outbuff, count + 2, "ASCII 85 filter", ofP); + } -static void -rleputxelval(xelval const xv) { - if (rlebitsinitem == 8) - rleputitem(); - rleitem += xv << rlebitshift; - rlebitsinitem += bitspersample; - rlebitshift -= bitspersample; + fclose(ifP); + fclose(ofP); } static void -rleflush() { - if (rlebitsinitem > 0) - rleputitem(); - if (count > 0) - rleputbuffer(); +makePipe(int * const pipeFdArray) { + + int rc; + rc = pm_pipe(pipeFdArray); + if (rc == -1) + pm_error("pipe() failed, errno = %d (%s)", errno, strerror(errno)); } + static void -flushNativeOutput(bool const rle) { - if (rle) - rleflush(); - else - flushitem(); - printf("\n"); -} - -/*=========================================================================== - The BMEPS output encoder. -===========================================================================*/ +closeAllBut(int const saveFd0, + int const saveFd1, + int const saveFd2) { +/*---------------------------------------------------------------------------- + Close every file descriptor in this process except 'saveFd0', + 'saveFd1', and 'saveFd2'. -/* This code is just a wrapper around the output encoder that is part of - Bmeps, to give it better modularity. -*/ + This is helpful because even if this process doesn't touch other file + desriptors, its very existence will keep the files open. +-----------------------------------------------------------------------------*/ + + /* Unix provides no good way to do this; we just assume file descriptors + above 9 are not used in this program; Caller must ensure that is true. + */ + int fd; -struct bmepsoe { - Output_Encoder * oeP; - int * rleBuffer; - Byte * flateInBuffer; - Byte * flateOutBuffer; -}; + for (fd = 0; fd < 10; ++fd) { + if (fd != saveFd0 && fd != saveFd1 && fd != saveFd2) + close(fd); + } +} static void -createBmepsOutputEncoder(struct bmepsoe ** const bmepsoePP, - FILE * const ofP, - bool const rle, - bool const flate, - bool const ascii85) { - - unsigned int const FLATE_IN_SIZE = 16384; - unsigned int const FLATE_OUT_SIZE = 17408; - - struct bmepsoe * bmepsoeP; - int mode; - - MALLOCVAR_NOFAIL(bmepsoeP); - MALLOCVAR_NOFAIL(bmepsoeP->oeP); - MALLOCARRAY_NOFAIL(bmepsoeP->rleBuffer, 129); - MALLOCARRAY_NOFAIL(bmepsoeP->flateInBuffer, FLATE_IN_SIZE); - MALLOCARRAY_NOFAIL(bmepsoeP->flateOutBuffer, FLATE_OUT_SIZE); - - mode = 0; - if (rle) - mode |= OE_RL; - if (flate) - mode |= OE_FLATE; - if (ascii85) - mode |= OE_ASC85; +spawnFilter(FILE * const ofP, + FilterFn * const filterFn, + OutputEncoder * const oeP, + FILE ** const feedFilePP, + pid_t * const pidP) { +/*---------------------------------------------------------------------------- + Fork a child process to run filter function 'filterFn' and send its + output to *ofP. + + Create a pipe for feeding the filter and return as *feedFilePP the + stream to which Caller can write to push stuff into the filter. + + *oeP is the parameter to 'filterFn'. +-----------------------------------------------------------------------------*/ + int pipeFd[2]; + pid_t rc; + + makePipe(pipeFd); + + rc = fork(); + + if (rc == (pid_t)-1) + pm_error("fork() of filter process failed. errno=%d (%s)", + errno, strerror(errno)); + else if (rc == 0) { + /* This is the child process */ + + FILE * ifP; + + ifP = fdopen(pipeFd[0], "r"); + + if (!ifP) + pm_error("filter process failed to make " + "file stream (\"FILE\") " + "out of the file descriptor which is input to the " + "filter. errno=%d (%s)", + errno, strerror(errno)); + + closeAllBut(fileno(ifP), fileno(ofP), STDERR_FILENO); + + filterFn(ifP, ofP, oeP); + + exit(EXIT_SUCCESS); + } else { + /* This is the parent process */ + + pid_t const childPid = rc; + + close(pipeFd[0]); - oe_init(bmepsoeP->oeP, ofP, mode, 9, - bmepsoeP->rleBuffer, - bmepsoeP->flateInBuffer, FLATE_IN_SIZE, - bmepsoeP->flateOutBuffer, FLATE_OUT_SIZE); + *feedFilePP = fdopen(pipeFd[1], "w"); - *bmepsoePP = bmepsoeP; + *pidP = childPid; + } } static void -destroyBmepsOutputEncoder(struct bmepsoe * const bmepsoeP) { - - free(bmepsoeP->rleBuffer); - free(bmepsoeP->flateInBuffer); - free(bmepsoeP->flateOutBuffer); +addFilter(const char * const description, + FilterFn * const filter, + OutputEncoder * const oeP, + FILE ** const feedFilePP, + pid_t * const pidList) { +/*---------------------------------------------------------------------------- + Add a filter to the front of the chain. + + Spawn a process to do the filtering, by running function 'filter'. + + *feedFilePP is the present head of the chain. We make the new filter + process write its output to that and get its input from a new pipe. + We update *feedFilePP to the sending end of the new pipe. + + Add to the list pidList[] the PID of the process we spawn. +-----------------------------------------------------------------------------*/ + FILE * const oldFeedFileP = *feedFilePP; + + FILE * newFeedFileP; + pid_t pid; + + spawnFilter(oldFeedFileP, filter, oeP, &newFeedFileP, &pid); + + if (verbose) + pm_message("%s filter spawned: pid %u", + description, (unsigned)pid); - free(bmepsoeP); + if (debug) { + int const outFd = fileno(oldFeedFileP); + int const supplyFd = fileno(newFeedFileP); + pm_message("PID %u writes to FD %u, its supplier writes to FD %u", + (unsigned)pid, outFd, supplyFd); + } + fclose(oldFeedFileP); /* Child keeps this open now */ + + addToPidList(pidList, pid); + + *feedFilePP = newFeedFileP; } static void -outputBmepsSample(struct bmepsoe * const bmepsoeP, - unsigned int const sampleValue, - unsigned int const bitsPerSample) { +spawnFilters(FILE * const ofP, + OutputEncoder * const oeP, + FILE ** const feedFilePP, + pid_t * const pidList) { +/*---------------------------------------------------------------------------- + Get all the child processes for the filters running and connected. + Return at *feedFileP the file stream to which to write the raw data, + with the filtered data going to *ofP. - if (bitsPerSample == 8) - oe_byte_add(bmepsoeP->oeP, sampleValue); - else { - unsigned int m; + Filter according to *oeP. +-----------------------------------------------------------------------------*/ - for (m = 1 << (bitsPerSample-1); m != 0; m >>= 1) - /* depends on oe_bit_add accepting any value !=0 as 1 */ - oe_bit_add(bmepsoeP->oeP, sampleValue & m); - } + /* Build up the pipeline from the final to the initial stage. The + result is one of: + + FEED | convertRow | asciiHexFilter | *ofP + FEED | convertRow | ascii85Filter | *ofP + FEED | convertRow | rleFilter | asciiHexFilter | *ofP + FEED | convertRow | flateFilter | asciiHexFilter | *ofP + FEED | convertRow | flateFilter | rleFilter | asciiHexFilter | *ofP + */ + + FILE * feedFileP; + /* The current head of the filter chain; changes as we add filters */ + + initPidList(pidList); + + feedFileP = ofP; /* Initial state: no filter at all */ + + addFilter( + "output", + oeP->outputType == Ascii85 ? &ascii85Filter : asciiHexFilter, + oeP, + &feedFileP, + pidList); + + if (oeP->compressFlate) + addFilter("flate", flateFilter, oeP, &feedFileP, pidList); + + if (oeP->compressRle) + addFilter("rle", rleFilter, oeP, &feedFileP, pidList); + + *feedFilePP = feedFileP; } static void -flushBmepsOutput(struct bmepsoe * const bmepsoeP) { - oe_byte_flush(bmepsoeP->oeP); +waitForChildren(const pid_t * const pidList) { +/*---------------------------------------------------------------------------- + Wait for all child processes with PIDs in pidList[] to exit. + In pidList[], end-of-list is marked with a special zero value. +-----------------------------------------------------------------------------*/ + /* There's an odd behavior in Unix such that if you have set the + action for SIGCHLD to ignore the signal (even though ignoring the + signal is the default), the process' children do not become + zombies. Consequently, waitpid() always fails with ECHILD - but + nonetheless waits for the child to exit. + + We expect the process not to have the action for SIGCHLD set that + way. + */ + unsigned int i; + + for (i = 0; pidList[i]; ++i) { + pid_t rc; + int status; + + if (verbose) + pm_message("Waiting for PID %u to exit", (unsigned)pidList[i]); + + rc = waitpid(pidList[i], &status, 0); + if (rc == -1) + pm_error ("waitpid() for child %u failed, errno=%d (%s)", + i, errno, strerror(errno)); + else if (status != EXIT_SUCCESS) + pm_error ("Child process %u terminated abnormally", i); + } + if (verbose) + pm_message("All children have exited"); } + /*============================================================================ - END OF OUTPUT ENCODERS + END OF OUTPUT ENCODERS ============================================================================*/ + +static void +validateComputableBoundingBox(float const scols, + float const srows, + float const llx, + float const lly) { + + float const bbWidth = llx + scols + 0.5; + float const bbHeight = lly + srows + 0.5; + + if (bbHeight < INT_MIN || bbHeight > INT_MAX || + bbWidth < INT_MIN || bbWidth > INT_MAX) + pm_error("Bounding box dimensions %.1f x %.1f are too large " + "for computations. " + "This probably means input image width, height, " + "or scale factor is too large", bbWidth, bbHeight); +} + + + +static void +warnUserRescaling(float const scale) { + + const char * const baseMsg = "warning, image too large for page"; + + if (pm_have_float_format()) + pm_message("%s; rescaling to %g", baseMsg, scale); + else + pm_message("%s; rescaling", baseMsg); +} + + + static void computeImagePosition(int const dpiX, int const dpiY, @@ -545,39 +1054,41 @@ computeImagePosition(int const dpiX, float * const llyP, bool * const turnedP ) { /*---------------------------------------------------------------------------- - Determine where on the page the image is to go. This means position, - dimensions, and orientation. + Determine where on the page the image is to go. This means position, + dimensions, and orientation. - icols/irows are the dimensions of the PNM input in xels. + icols/irows are the dimensions of the PNM input in xels. - 'mustturn' means we are required to rotate the image. + 'mustturn' means we are required to rotate the image. - 'canturn' means we may rotate the image if it fits better, but don't - have to. + 'canturn' means we may rotate the image if it fits better, but don't + have to. - *scolsP, *srowsP are the dimensions of the image in 1/72 inch. + *scolsP, *srowsP are the dimensions of the image in 1/72 inch. - *llxP, *llyP are the coordinates, in 1/72 inch, of the lower left - corner of the image on the page. + *llxP, *llyP are the coordinates in the Postcript frame, of the lower left + corner of the image on the page. The Postscript frame is different from the + Neptbm frame: units are 1/72 inch (1 point) and (0,0) is the lower left + corner. - *turnedP is true iff the image is to be rotated 90 degrees on the page. + *turnedP is true iff the image is to be rotated 90 degrees on the page. - imagewidth/imageheight are the requested dimensions of the image on - the page, in 1/72 inch. Image will be as large as possible within - those dimensions. Zero means unspecified, so 'scale', 'pagewid', - 'pagehgt', 'irows', and 'icols' determine image size. + imagewidth/imageheight are the requested dimensions of the image on + the page, in 1/72 inch. Image will be as large as possible within + those dimensions. Zero means unspecified, so 'scale', 'pagewid', + 'pagehgt', 'irows', and 'icols' determine image size. - 'equalpixels' means the user wants one printed pixel per input pixel. - It is inconsistent with imagewidth or imageheight != 0 + 'equalpixels' means the user wants one printed pixel per input pixel. + It is inconsistent with imagewidth or imageheight != 0 - 'requestedScale' is meaningful only when imageheight/imagewidth == 0 - and equalpixels == FALSE. It tells how many inches the user wants - 72 pixels of input to occupy, if it fits on the page. + 'requestedScale' is meaningful only when imageheight/imagewidth == 0 + and equalpixels == FALSE. It tells how many inches the user wants + 72 pixels of input to occupy, if it fits on the page. -----------------------------------------------------------------------------*/ int cols, rows; - /* Number of columns, rows of input xels in the output, as - rotated if applicable - */ + /* Number of columns, rows of input xels in the output, as + rotated if applicable + */ bool shouldturn; /* The image fits the page better if we turn it */ if (icols > irows && pagehgt > pagewid) @@ -608,7 +1119,7 @@ computeImagePosition(int const dpiX, scale = (float) imagewidth/cols; else scale = MIN((float)imagewidth/cols, (float)imageheight/rows); - + *scolsP = cols*scale; *srowsP = rows*scale; } else { @@ -617,8 +1128,8 @@ computeImagePosition(int const dpiX, */ const int devpixX = dpiX / 72.0 + 0.5; const int devpixY = dpiY / 72.0 + 0.5; - /* How many device pixels make up 1/72 inch, rounded to - nearest integer */ + /* How many device pixels make up 1/72 inch, rounded to + nearest integer */ const float pixfacX = 72.0 / dpiX * devpixX; /* 1, approx. */ const float pixfacY = 72.0 / dpiY * devpixY; /* 1, approx. */ float scale; @@ -628,10 +1139,9 @@ computeImagePosition(int const dpiX, *scolsP = scale * cols * pixfacX; *srowsP = scale * rows * pixfacY; - + if (scale != requestedScale) - pm_message("warning, image too large for page, rescaling to %g", - scale ); + warnUserRescaling(scale); /* Before May 2001, Pnmtops enforced a 5% margin around the page. If the image would be too big to leave a 5% margin, Pnmtops would @@ -644,6 +1154,7 @@ computeImagePosition(int const dpiX, *llxP = (center) ? ( pagewid - *scolsP ) / 2 : 0; *llyP = (center) ? ( pagehgt - *srowsP ) / 2 : 0; + validateComputableBoundingBox( *scolsP, *srowsP, *llxP, *llyP); if (verbose) pm_message("Image will be %3.2f points wide by %3.2f points high, " @@ -677,7 +1188,7 @@ determineDictionaryRequirement(bool const userWantsDict, static void defineReadstring(bool const rle) { /*---------------------------------------------------------------------------- - Write to Standard Output Postscript statements to define /readstring. + Write to Standard Output Postscript statements to define /readstring. -----------------------------------------------------------------------------*/ if (rle) { printf("/rlestr1 1 string def\n"); @@ -692,7 +1203,7 @@ defineReadstring(bool const rle) { printf(" readhexstring pop\n"); /* s */ printf(" length\n"); /* nr */ printf(" } {\n"); /* c */ - printf(" 256 exch sub dup\n"); /* n n */ + printf(" 257 exch sub dup\n"); /* n n */ printf(" currentfile rlestr1 readhexstring pop\n");/* n n s1 */ printf(" 0 get\n"); /* n n c */ printf(" exch 0 exch 1 exch 1 sub {\n"); /* n c 0 1 n-1*/ @@ -725,13 +1236,14 @@ static void setupReadstringNative(bool const rle, bool const color, unsigned int const icols, - unsigned int const padright, - unsigned int const bps) { + unsigned int const bitsPerSample) { /*---------------------------------------------------------------------------- - Write to Standard Output statements to define /readstring and also - arguments for it (/picstr or /rpicstr, /gpicstr, and /bpicstr). + Write to Standard Output statements to define /readstring and also + arguments for it (/picstr or /rpicstr, /gpicstr, and /bpicstr). -----------------------------------------------------------------------------*/ - unsigned int const bytesPerRow = (icols + padright) * bps / 8; + unsigned int const bytesPerRow = icols / (8/bitsPerSample) + + (icols % (8/bitsPerSample) > 0 ? 1 : 0); + /* Size of row buffer, padded up to byte boundary. */ defineReadstring(rle); @@ -754,13 +1266,17 @@ putFilters(unsigned int const postscriptLevel, assert(postscriptLevel > 1); + /* We say to decode flate, then rle, so Caller must ensure it encodes + rel, then flate. + */ + if (ascii85) printf("/ASCII85Decode filter "); else printf("/ASCIIHexDecode filter "); if (flate) printf("/FlateDecode filter "); - if (rle) /* bmeps encodes rle before flate, so must decode after! */ + if (rle) printf("/RunLengthDecode filter "); } @@ -785,10 +1301,9 @@ putSetup(unsigned int const dictSize, bool const rle, bool const color, unsigned int const icols, - unsigned int const padright, - unsigned int const bps) { + unsigned int const bitsPerSample) { /*---------------------------------------------------------------------------- - Put the setup section in the Postscript program on Standard Output. + Put the setup section in the Postscript program on Standard Output. -----------------------------------------------------------------------------*/ printf("%%%%BeginSetup\n"); @@ -797,7 +1312,7 @@ putSetup(unsigned int const dictSize, printf("%u dict begin\n", dictSize); if (!psFilter) - setupReadstringNative(rle, color, icols, padright, bps); + setupReadstringNative(rle, color, icols, bitsPerSample); printf("%%%%EndSetup\n"); } @@ -808,8 +1323,8 @@ static void putImage(bool const psFilter, bool const color) { /*---------------------------------------------------------------------------- - Put the image/colorimage statement in the Postscript program on - Standard Output. + Put the image/colorimage statement in the Postscript program on + Standard Output. -----------------------------------------------------------------------------*/ if (color) { if (psFilter) @@ -864,8 +1379,7 @@ putInit(unsigned int const postscriptLevel, float const srows, float const llx, float const lly, - int const padright, - int const bps, + int const bitsPerSample, int const pagewid, int const pagehgt, bool const color, @@ -877,8 +1391,8 @@ putInit(unsigned int const postscriptLevel, bool const psFilter, unsigned int const dictSize) { /*---------------------------------------------------------------------------- - Write out to Standard Output the headers stuff for the Postscript - program (everything up to the raster). + Write out to Standard Output the headers stuff for the Postscript + program (everything up to the raster). -----------------------------------------------------------------------------*/ /* The numbers in the %! line often confuse people. They are NOT the PostScript language level. The first is the level of the DSC comment @@ -897,7 +1411,7 @@ putInit(unsigned int const postscriptLevel, (int) (llx + scols + 0.5), (int) (lly + srows + 0.5)); printf("%%%%EndComments\n"); - putSetup(dictSize, psFilter, rle, color, icols, padright, bps); + putSetup(dictSize, psFilter, rle, color, icols, bitsPerSample); printf("%%%%Page: 1 1\n"); if (setpage) @@ -908,7 +1422,7 @@ putInit(unsigned int const postscriptLevel, printf("%g %g scale\n", scols, srows); if (turned) printf("0.5 0.5 translate 90 rotate -0.5 -0.5 translate\n"); - printf("%d %d %d\n", icols, irows, bps); + printf("%d %d %d\n", icols, irows, bitsPerSample); printf("[ %d 0 0 -%d 0 %d ]\n", icols, irows, irows); if (psFilter) @@ -917,6 +1431,7 @@ putInit(unsigned int const postscriptLevel, putInitReadstringNative(color); printf("\n"); + fflush(stdout); } @@ -956,9 +1471,58 @@ putEnd(bool const showpage, +static void +validateBpsRequest(unsigned int const bitsPerSampleReq, + unsigned int const postscriptLevel, + bool const psFilter) { + + if (postscriptLevel < 2 && bitsPerSampleReq > 8) + pm_error("You requested %u bits per sample, but in Postscript " + "level 1, 8 is the maximum. You can get 12 with " + "-level 2 and -psfilter", bitsPerSampleReq); + else if (!psFilter && bitsPerSampleReq > 8) + pm_error("You requested %u bits per sample, but without " + "-psfilter, the maximum is 8", bitsPerSampleReq); +} + + + +static unsigned int +bpsFromInput(unsigned int const bitsRequiredByMaxval, + unsigned int const postscriptLevel, + bool const psFilter) { + + unsigned int retval; + + if (bitsRequiredByMaxval <= 1) + retval = 1; + else if (bitsRequiredByMaxval <= 2) + retval = 2; + else if (bitsRequiredByMaxval <= 4) + retval = 4; + else if (bitsRequiredByMaxval <= 8) + retval = 8; + else { + /* Post script level 2 defines a format with 12 bits per sample, + but I don't know the details of that format (both RLE and + non-RLE variations) and existing native raster generation code + simply can't handle bps > 8. But the built-in filters know + how to do 12 bps. + */ + if (postscriptLevel >= 2 && psFilter) + retval = 12; + else + retval = 8; + } + return retval; +} + + + static void warnUserAboutReducedDepth(unsigned int const bitsGot, unsigned int const bitsWanted, + bool const userRequested, unsigned int const postscriptLevel, bool const psFilter) { @@ -967,15 +1531,19 @@ warnUserAboutReducedDepth(unsigned int const bitsGot, "though the input has %u bits.", bitsGot, bitsWanted); - if (postscriptLevel < 2) - pm_message("Postscript level %u has a maximum depth of 8 bits. " - "You could get up to 12 with -level=2 and -psfilter.", - postscriptLevel); - else { - if (!psFilter) - pm_message("You can get up to 12 bits with -psfilter"); - else - pm_message("The Postscript maximum is 12."); + if (!userRequested) { + if (postscriptLevel < 2) + pm_message("Postscript level %u has a maximum depth of " + "8 bits. " + "You could get up to 12 with -level=2 " + "and -psfilter.", + postscriptLevel); + else { + if (!psFilter) + pm_message("You can get up to 12 bits with -psfilter"); + else + pm_message("The Postscript maximum is 12."); + } } } } @@ -986,76 +1554,237 @@ static void computeDepth(xelval const inputMaxval, unsigned int const postscriptLevel, bool const psFilter, - unsigned int * const bitspersampleP, - unsigned int * const psMaxvalP) { + unsigned int const bitsPerSampleReq, + unsigned int * const bitsPerSampleP) { /*---------------------------------------------------------------------------- - Figure out how many bits will represent each sample in the Postscript - program, and the maxval of the Postscript program samples. The maxval - is just the maximum value allowable in the number of bits. + Figure out how many bits will represent each sample in the Postscript + program, and the maxval of the Postscript program samples. The maxval + is just the maximum value allowable in the number of bits. + + 'bitsPerSampleReq' is the bits per sample that the user requests, or + zero if he made no request. -----------------------------------------------------------------------------*/ unsigned int const bitsRequiredByMaxval = pm_maxvaltobits(inputMaxval); - if (bitsRequiredByMaxval <= 1) - *bitspersampleP = 1; - else if (bitsRequiredByMaxval <= 2) - *bitspersampleP = 2; - else if (bitsRequiredByMaxval <= 4) - *bitspersampleP = 4; - else if (bitsRequiredByMaxval <= 8) - *bitspersampleP = 8; - else { - /* Post script level 2 defines a format with 12 bits per sample, - but I don't know the details of that format (both RLE and - non-RLE variations) and existing native raster generation code - simply can't handle bps > 8. But the built-in filters know - how to do 12 bps. - */ - if (postscriptLevel >= 2 && psFilter) - *bitspersampleP = 12; - else - *bitspersampleP = 8; + if (bitsPerSampleReq != 0) { + validateBpsRequest(bitsPerSampleReq, postscriptLevel, psFilter); + *bitsPerSampleP = bitsPerSampleReq; + } else { + *bitsPerSampleP = bpsFromInput(bitsRequiredByMaxval, + postscriptLevel, psFilter); } - - warnUserAboutReducedDepth(*bitspersampleP, bitsRequiredByMaxval, + warnUserAboutReducedDepth(*bitsPerSampleP, bitsRequiredByMaxval, + bitsPerSampleReq != 0, postscriptLevel, psFilter); - *psMaxvalP = pm_bitstomaxval(*bitspersampleP); - - if (verbose) + if (verbose) { + unsigned int const psMaxval = pm_bitstomaxval(*bitsPerSampleP); pm_message("Input maxval is %u. Postscript raster will have " "%u bits per sample, so maxval = %u", - inputMaxval, *bitspersampleP, *psMaxvalP); + inputMaxval, *bitsPerSampleP, psMaxval); + } } +/*=========================================================================== + The bit accumulator +===========================================================================*/ + +typedef struct { + unsigned int value; + unsigned int consumed; +} BitAccumulator; + + + static void -convertRowNative(struct pam * const pamP, - tuple * const tuplerow, - unsigned int const psMaxval, - bool const rle, - unsigned int const padright) { +ba_init(BitAccumulator * const baP) { + + baP->value = 0; + baP->consumed = 0; +} + + + +static void +ba_add12(BitAccumulator * const baP, + unsigned int const new12, + FILE * const fP) { +/*---------------------------------------------------------------------------- + Read a 12-bit string into the bit accumulator baP->value. + On every other call, combine two 12-bit strings and write out three bytes. +-----------------------------------------------------------------------------*/ + assert (baP->consumed == 12 || baP->consumed == 0); + + if (baP->consumed == 12){ + char const oldHi8 = (baP->value) >> 4; + char const oldLo4 = (baP->value) & 0x0f; + char const newHi4 = new12 >> 8; + char const newLo8 = new12 & 0xff; + + fputc(oldHi8, fP); + fputc((oldLo4 << 4) | newHi4 , fP); + fputc(newLo8, fP); + baP->value = 0; baP->consumed = 0; + } else { + baP->value = new12; baP->consumed = 12; + } +} + + + +static void +ba_add(BitAccumulator * const baP, + unsigned int const b, + unsigned int const bitsPerSample, + FILE * const fP) { +/*---------------------------------------------------------------------------- + Combine bit sequences that do not fit into a byte. + + Used when bitsPerSample =1, 2, 4. + Logic also works for bitsPerSample = 8, 16. + + The accumulator, baP->value is unsigned int (usually 32 bits), but + only 8 bits are used. +-----------------------------------------------------------------------------*/ + unsigned int const bufSize = 8; + + assert (bitsPerSample == 1 || bitsPerSample == 2 || bitsPerSample == 4); + + baP->value = (baP->value << bitsPerSample) | b ; + baP->consumed += bitsPerSample; + if (baP->consumed == bufSize) { + /* flush */ + fputc( baP->value, fP); + baP->value = 0; + baP->consumed = 0; + } +} + + + +static void +ba_flush(BitAccumulator * const baP, + FILE * const fP) { +/*---------------------------------------------------------------------------- + Flush partial bits in baP->consumed. +-----------------------------------------------------------------------------*/ + if (baP->consumed == 12) { + char const oldHi8 = (baP->value) >> 4; + char const oldLo4 = (baP->value) & 0x0f; + fputc(oldHi8, fP); + fputc(oldLo4 << 4, fP); + } else if (baP->consumed == 8) + fputc(baP->value , fP); + else if (baP->consumed > 0) { + unsigned int const leftShift = 8 - baP->consumed; + assert(baP->consumed <= 8); /* why? */ + baP->value <<= leftShift; + fputc(baP->value , fP); + } + baP->value = 0; + baP->consumed = 0; +} + + + +static void +outputSample(BitAccumulator * const baP, + unsigned int const sampleValue, + unsigned int const bitsPerSample, + FILE * const fP) { + + if (bitsPerSample == 8) + fputc(sampleValue, fP); + else if (bitsPerSample == 12) + ba_add12(baP, sampleValue, fP); + else + ba_add(baP, sampleValue, bitsPerSample, fP); +} + + + +static void +flushOutput(BitAccumulator * const baP, + FILE * const fP) { + ba_flush(baP, fP); +} + + + +/*---------------------------------------------------------------------- + Row converters + + convertRowPbm is a fast routine for PBM images. + It is used only when the input is PBM and the user does not specify + a -bitspersample value greater than 1. It is not used when the input + image is PGM or PPM and the output resolution is brought down to one + bit per pixel by -bitpersample=1 . + + convertRowNative and convertRowPsFilter are the general converters. + They are quite similar, the differences being: + (1) Native output separates the color planes: + (RRR...RRR GGG...GGG BBB...BBB), + whereas psFilter does not: + (RGB RGB RGB RGB ......... RGB). + (2) Native flushes the run-length encoder at the end of each row if + grayscale, at the end of each plane if color. + + Both convertRowNative and convertRowPsFilter can handle PBM, though we + don't use them. + + If studying the code, read convertRowPbm first. convertRowNative and + convertRowPsFilter are constructs that pack raster data into a form + similar to a binary PBM bitrow. + ----------------------------------------------------------------------*/ + +static void +convertRowPbm(struct pam * const pamP, + unsigned char * const bitrow, + bool const psFilter, + FILE * const fP) { +/*--------------------------------------------------------------------- + Feed PBM raster data directly to the output encoder. + Invert bits: 0 is "white" in PBM, 0 is "black" in postscript. +----------------------------------------------------------------------*/ + unsigned int colChar; + unsigned int const colChars = pbm_packed_bytes(pamP->width); + + pbm_readpbmrow_packed(pamP->file, bitrow, pamP->width, pamP->format); + + for (colChar = 0; colChar < colChars; ++colChar) + bitrow[colChar] = ~ bitrow[colChar]; + + /* Zero clear padding beyond right edge */ + pbm_cleanrowend_packed(bitrow, pamP->width); + writeFile(bitrow, colChars, "PBM reader", fP); +} + + + +static void +convertRowNative(struct pam * const pamP, + tuple * tuplerow, + unsigned int const bitsPerSample, + FILE * const fP) { + + unsigned int const psMaxval = pm_bitstomaxval(bitsPerSample); unsigned int plane; + BitAccumulator ba; + + ba_init(&ba); + + pnm_readpamrow(pamP, tuplerow); + pnm_scaletuplerow(pamP, tuplerow, tuplerow, psMaxval); for (plane = 0; plane < pamP->depth; ++plane) { unsigned int col; - for (col= 0; col < pamP->width; ++col) { - sample const scaledSample = - pnm_scalesample(tuplerow[col][plane], pamP->maxval, psMaxval); + for (col= 0; col < pamP->width; ++col) + outputSample(&ba, tuplerow[col][plane], bitsPerSample, fP); - if (rle) - rleputxelval(scaledSample); - else - putxelval(scaledSample); - } - for (col = 0; col < padright; ++col) - if (rle) - rleputxelval(0); - else - putxelval(0); - if (rle) - rleflush(); + flushOutput(&ba, fP); } } @@ -1063,34 +1792,27 @@ convertRowNative(struct pam * const pamP, static void convertRowPsFilter(struct pam * const pamP, - tuple * const tuplerow, - struct bmepsoe * const bmepsoeP, - unsigned int const psMaxval) { + tuple * tuplerow, + unsigned int const bitsPerSample, + FILE * const fP) { - unsigned int const bitsPerSample = pm_maxvaltobits(psMaxval); - unsigned int const stragglers = - (((bitsPerSample * pamP->depth) % 8) * pamP->width) % 8; - /* Number of bits at the right edge that don't fill out a - whole byte */ + unsigned int const psMaxval = pm_bitstomaxval(bitsPerSample); unsigned int col; - tuple scaledTuple; - - scaledTuple = pnm_allocpamtuple(pamP); + BitAccumulator ba; + + ba_init(&ba); + + pnm_readpamrow(pamP, tuplerow); + pnm_scaletuplerow(pamP, tuplerow, tuplerow, psMaxval); for (col = 0; col < pamP->width; ++col) { unsigned int plane; - pnm_scaletuple(pamP, scaledTuple, tuplerow[col], psMaxval); - for (plane = 0; plane < pamP->depth; ++plane) - outputBmepsSample(bmepsoeP, scaledTuple[plane], bitsPerSample); - } - if (stragglers > 0) { - unsigned int i; - for (i = stragglers; i < 8; ++i) - oe_bit_add(bmepsoeP->oeP, 0); + outputSample(&ba, tuplerow[col][plane], bitsPerSample, fP); } - pnm_freepamtuple(scaledTuple); + flushOutput(&ba, fP); + } @@ -1146,50 +1868,111 @@ selectPostscriptLevel(bool const levelIsGiven, static void -convertPage(FILE * const ifP, - int const turnflag, - int const turnokflag, - bool const psFilter, - bool const rle, - bool const flate, - bool const ascii85, - bool const setpage, - bool const showpage, - bool const center, - float const scale, - int const dpiX, - int const dpiY, - int const pagewid, - int const pagehgt, - int const imagewidth, - int const imageheight, - bool const equalpixels, - char const name[], - bool const dict, - bool const vmreclaim, - bool const levelIsGiven, +convertRaster(struct pam * const inpamP, + unsigned int const bitsPerSample, + bool const psFilter, + FILE * const fP) { +/*---------------------------------------------------------------------------- + Read the raster described by *inpamP, and write a bit stream of samples + to *fP. This stream has to be compressed and converted to text before it + can be part of a Postscript program. + + 'psFilter' means to do the conversion using built in Postscript filters, as + opposed to our own filters via /readstring. + + 'bitsPerSample' is how many bits each sample is to take in the Postscript + output. +-----------------------------------------------------------------------------*/ + if (PAM_FORMAT_TYPE(inpamP->format) == PBM_TYPE && bitsPerSample == 1) { + unsigned char * bitrow; + unsigned int row; + + bitrow = pbm_allocrow_packed(inpamP->width); + + for (row = 0; row < inpamP->height; ++row) + convertRowPbm(inpamP, bitrow, psFilter, fP); + + pbm_freerow(bitrow); + } else { + tuple *tuplerow; + unsigned int row; + + tuplerow = pnm_allocpamrow(inpamP); + + for (row = 0; row < inpamP->height; ++row) { + if (psFilter) + convertRowPsFilter(inpamP, tuplerow, bitsPerSample, fP); + else + convertRowNative(inpamP, tuplerow, bitsPerSample, fP); + } + pnm_freepamrow(tuplerow); + } +} + + + +/* FILE MANAGEMENT: File management is pretty hairy here. A filter, which + runs in its own process, needs to be able to cause its output file to + close because it might be an internal pipe and the next stage needs to + know output is done. So the forking process must close its copy of the + file descriptor. BUT: if the output of the filter is not an internal + pipe but this program's output, then we don't want it closed when the + filter terminates because we'll need it to be open for the next image + the program converts (with a whole new chain of filters). + + To prevent the progam output file from getting closed, we pass a + duplicate of it to spawnFilters() and keep the original open. +*/ + + + +static void +convertPage(FILE * const ifP, + int const turnflag, + int const turnokflag, + bool const psFilter, + bool const rle, + bool const flate, + bool const ascii85, + bool const setpage, + bool const showpage, + bool const center, + float const scale, + int const dpiX, + int const dpiY, + int const pagewid, + int const pagehgt, + int const imagewidth, + int const imageheight, + bool const equalpixels, + unsigned int const bitsPerSampleReq, + char const name[], + bool const dict, + bool const vmreclaim, + bool const levelIsGiven, unsigned int const levelGiven) { struct pam inpam; - tuple* tuplerow; - unsigned int padright; - /* Number of bits we must add to the right end of each Postscript - output line in order to have an integral number of bytes of output. - E.g. at 2 bits per sample with 10 columns, this would be 4. - */ - int row; - unsigned int psMaxval; - /* The maxval of the Postscript program */ float scols, srows; float llx, lly; bool turned; bool color; unsigned int postscriptLevel; - struct bmepsoe * bmepsoeP; - unsigned int dictSize; + unsigned int bitsPerSample; + unsigned int dictSize; /* Size of Postscript dictionary we should define */ + OutputEncoder oe; + pid_t filterPidList[MAX_FILTER_CT + 1]; + + FILE * feedFileP; + /* The file stream which is the head of the filter chain; we write to + this and filtered stuff comes out the other end. + */ + FILE * filterChainOfP; pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type)); + + validateCompDimension(inpam.width, 16, "Input image width"); if (!STRSEQ(inpam.tuple_type, PAM_PBM_TUPLETYPE) && !STRSEQ(inpam.tuple_type, PAM_PGM_TUPLETYPE) && @@ -1206,13 +1989,9 @@ convertPage(FILE * const ifP, if (color) pm_message("generating color Postscript program."); - computeDepth(inpam.maxval, postscriptLevel, psFilter, - &bitspersample, &psMaxval); - { - unsigned int const realBitsPerLine = inpam.width * bitspersample; - unsigned int const paddedBitsPerLine = ((realBitsPerLine + 7) / 8) * 8; - padright = (paddedBitsPerLine - realBitsPerLine) / bitspersample; - } + computeDepth(inpam.maxval, postscriptLevel, psFilter, bitsPerSampleReq, + &bitsPerSample); + /* In positioning/scaling the image, we treat the input image as if it has a density of 72 pixels per inch. */ @@ -1225,84 +2004,65 @@ convertPage(FILE * const ifP, determineDictionaryRequirement(dict, psFilter, &dictSize); putInit(postscriptLevel, name, inpam.width, inpam.height, - scols, srows, llx, lly, padright, bitspersample, + scols, srows, llx, lly, bitsPerSample, pagewid, pagehgt, color, turned, rle, flate, ascii85, setpage, psFilter, dictSize); - createBmepsOutputEncoder(&bmepsoeP, stdout, rle, flate, ascii85); - initNativeOutputEncoder(rle, bitspersample); + initOutputEncoder(&oe, inpam.width, bitsPerSample, + rle, flate, ascii85, psFilter); - tuplerow = pnm_allocpamrow(&inpam); - - for (row = 0; row < inpam.height; ++row) { - pnm_readpamrow(&inpam, tuplerow); - if (psFilter) - convertRowPsFilter(&inpam, tuplerow, bmepsoeP, psMaxval); - else - convertRowNative(&inpam, tuplerow, psMaxval, rle, padright); - } + fflush(stdout); + filterChainOfP = fdopen(dup(fileno(stdout)), "w"); + /* spawnFilters() closes this. See FILE MANAGEMENT above */ - pnm_freepamrow(tuplerow); + spawnFilters(filterChainOfP, &oe, &feedFileP, filterPidList); + + convertRaster(&inpam, bitsPerSample, psFilter, feedFileP); - if (psFilter) - flushBmepsOutput(bmepsoeP); - else - flushNativeOutput(rle); + fflush(feedFileP); + fclose(feedFileP); - destroyBmepsOutputEncoder(bmepsoeP); + waitForChildren(filterPidList); putEnd(showpage, psFilter, ascii85, dictSize, vmreclaim); } -static const char * -basebasename(const char * const filespec) { -/*---------------------------------------------------------------------------- - Return filename up to first period ------------------------------------------------------------------------------*/ - char const dirsep = '/'; - const char * const lastSlashPos = strrchr(filespec, dirsep); - - char * name; - const char * filename; - - if (lastSlashPos) - filename = lastSlashPos + 1; - else - filename = filespec; - - name = strdup(filename); - if (name != NULL) { - char * const dotPosition = strchr(name, '.'); - - if (dotPosition) - *dotPosition = '\0'; - } - return name; -} - - - int -main(int argc, char * argv[]) { +main(int argc, const char * argv[]) { - FILE* ifp; - const char *name; /* malloc'ed */ + FILE * ifP; + const char * name; /* malloc'ed */ struct cmdlineInfo cmdline; - pnm_init(&argc, argv); + pm_proginit(&argc, argv); + + setSignals(); parseCommandLine(argc, argv, &cmdline); - verbose = cmdline.verbose; + verbose = cmdline.verbose || cmdline.debug; + debug = cmdline.debug; - ifp = pm_openr(cmdline.inputFileName); + if (cmdline.flate && !progIsFlateCapable()) + pm_error("This program cannot do flate compression. " + "(There are other versions of the program that do, " + "though -- it's a build-time option"); + + ifP = pm_openr(cmdline.inputFileName); if (streq(cmdline.inputFileName, "-")) name = strdup("noname"); else name = basebasename(cmdline.inputFileName); + + /* This program manages file descriptors in a way that assumes + that new files will get file descriptor numbers less than 10, + so we close superfluous files now to make sure that's true. + */ + closeAllBut(fileno(ifP), fileno(stdout), fileno(stderr)); + { int eof; /* There are no more images in the input file */ unsigned int imageSeq; @@ -1320,7 +2080,7 @@ main(int argc, char * argv[]) { eof = FALSE; /* There is always at least one image */ for (imageSeq = 0; !eof; ++imageSeq) { - convertPage(ifp, cmdline.mustturn, cmdline.canturn, + convertPage(ifP, cmdline.mustturn, cmdline.canturn, cmdline.psfilter, cmdline.rle, cmdline.flate, cmdline.ascii85, cmdline.setpage, cmdline.showpage, @@ -1328,15 +2088,17 @@ main(int argc, char * argv[]) { cmdline.dpiX, cmdline.dpiY, cmdline.width, cmdline.height, cmdline.imagewidth, cmdline.imageheight, - cmdline.equalpixels, name, + cmdline.equalpixels, + cmdline.bitspersampleSpec ? cmdline.bitspersample : 0, + name, cmdline.dict, cmdline.vmreclaim, cmdline.levelSpec, cmdline.level); - pnm_nextimage(ifp, &eof); + pnm_nextimage(ifP, &eof); } } - strfree(name); + pm_strfree(name); - pm_close(ifp); + pm_close(ifP); return 0; } @@ -1357,4 +2119,9 @@ main(int argc, char * argv[]) { ** -nocenter option added November 1993 by Wolfgang Stuerzlinger, ** wrzl@gup.uni-linz.ac.at. ** +** July 2011 afu +** row convertors rewritten, fast PBM-only row convertor added, +** rle compression slightly modified, flate compression added +** ascii85 output end added. +** */ diff --git a/converter/other/pnmtorast.c b/converter/other/pnmtorast.c index 605e815c..e11d3cb7 100644 --- a/converter/other/pnmtorast.c +++ b/converter/other/pnmtorast.c @@ -19,103 +19,285 @@ static colormap_t * -alloc_pr_colormap(void) { - - colormap_t* pr_colormapP; - - MALLOCVAR(pr_colormapP); - if ( pr_colormapP == NULL ) - pm_error( "out of memory" ); - pr_colormapP->type = RMT_EQUAL_RGB; - pr_colormapP->length = MAXCOLORS; - MALLOCARRAY(pr_colormapP->map[0], MAXCOLORS); - MALLOCARRAY(pr_colormapP->map[1], MAXCOLORS); - MALLOCARRAY(pr_colormapP->map[2], MAXCOLORS); - if ( pr_colormapP->map[0] == NULL || - pr_colormapP->map[1] == NULL || - pr_colormapP->map[2] == NULL ) - pm_error( "out of memory" ); - - return pr_colormapP; +allocPrColormap(void) { + + colormap_t * prColormapP; + + MALLOCVAR(prColormapP); + if (prColormapP == NULL) + pm_error("out of memory"); + prColormapP->type = RMT_EQUAL_RGB; + prColormapP->length = MAXCOLORS; + MALLOCARRAY(prColormapP->map[0], MAXCOLORS); + MALLOCARRAY(prColormapP->map[1], MAXCOLORS); + MALLOCARRAY(prColormapP->map[2], MAXCOLORS); + if (prColormapP->map[0] == NULL || + prColormapP->map[1] == NULL || + prColormapP->map[2] == NULL) + pm_error("out of memory"); + + return prColormapP; } -static colormap_t* -make_pr_colormap(colorhist_vector const chv, - int const colors) { +static colormap_t * +makePrColormap(colorhist_vector const chv, + unsigned int const colors) { - colormap_t* pr_colormapP; - int i; + colormap_t * prColormapP; + unsigned int i; - pr_colormapP = alloc_pr_colormap( ); + prColormapP = allocPrColormap(); - for ( i = 0; i < colors; ++i ) - { - pr_colormapP->map[0][i] = PPM_GETR( chv[i].color ); - pr_colormapP->map[1][i] = PPM_GETG( chv[i].color ); - pr_colormapP->map[2][i] = PPM_GETB( chv[i].color ); + for (i = 0; i < colors; ++i) { + prColormapP->map[0][i] = PPM_GETR(chv[i].color); + prColormapP->map[1][i] = PPM_GETG(chv[i].color); + prColormapP->map[2][i] = PPM_GETB(chv[i].color); } - for ( ; i < MAXCOLORS; ++i ) - pr_colormapP->map[0][i] = pr_colormapP->map[1][i] = - pr_colormapP->map[2][i] = 0; - - return pr_colormapP; + for ( ; i < MAXCOLORS; ++i) { + prColormapP->map[0][i] = 0; + prColormapP->map[1][i] = 0; + prColormapP->map[2][i] = 0; + } + return prColormapP; } static colormap_t * -make_gray_pr_colormap(void) { +makeGrayPrColormap(void) { - colormap_t* pr_colormapP; - int i; + colormap_t * prColormapP; + unsigned int i; - pr_colormapP = alloc_pr_colormap( ); + prColormapP = allocPrColormap(); - for ( i = 0; i < MAXCOLORS; ++i ) - { - pr_colormapP->map[0][i] = i; - pr_colormapP->map[1][i] = i; - pr_colormapP->map[2][i] = i; + for (i = 0; i < MAXCOLORS; ++i) { + prColormapP->map[0][i] = i; + prColormapP->map[1][i] = i; + prColormapP->map[2][i] = i; + } + + return prColormapP; +} + + + +static void +doRowDepth1(const xel * const xelrow, + unsigned char * const rastRow, + unsigned int const cols, + int const format, + xelval const maxval, + colorhash_table const cht, + unsigned int * const lenP) { + + unsigned int col; + int bitcount; + unsigned int cursor; + + cursor = 0; + + rastRow[cursor] = 0; + bitcount = 7; + + for (col = 0; col < cols; ++col) { + switch (PNM_FORMAT_TYPE(format)) { + case PPM_TYPE: { + xel adjustedXel; + int color; + if (maxval != 255) + PPM_DEPTH(adjustedXel, xelrow[col], maxval, 255 ); + color = ppm_lookupcolor(cht, &adjustedXel); + if (color == -1) + pm_error("color not found?!? " + "col=%u r=%u g=%u b=%u", + col, + PPM_GETR(adjustedXel), + PPM_GETG(adjustedXel), + PPM_GETB(adjustedXel)); + if (color) + rastRow[cursor] |= 1 << bitcount; + } break; + + default: { + int const color = PNM_GET1(xelrow[col]); + if (!color) + rastRow[cursor] |= 1 << bitcount; + break; + } + } + --bitcount; + if (bitcount < 0) { + ++cursor; + rastRow[cursor] = 0; + bitcount = 7; + } + } + *lenP = cursor; +} + + + +static void +doRowDepth8(const xel * const xelrow, + unsigned char * const rastRow, + unsigned int const cols, + int const format, + xelval const maxval, + colorhash_table const cht, + unsigned int * const lenP) { + + unsigned int col; + unsigned int cursor; + + for (col = 0, cursor = 0; col < cols; ++col) { + int color; /* color index of pixel or -1 if not in 'cht' */ + + switch (PNM_FORMAT_TYPE(format)) { + case PPM_TYPE: { + xel adjustedXel; + + if (maxval == 255) + adjustedXel = xelrow[col]; + else + PPM_DEPTH(adjustedXel, xelrow[col], maxval, 255); + + color = ppm_lookupcolor(cht, &adjustedXel); + if (color == -1) + pm_error("color not found?!? " + "col=%u r=%u g=%u b=%u", + col, + PPM_GETR(adjustedXel), + PPM_GETG(adjustedXel), + PPM_GETB(adjustedXel)); + } break; + + case PGM_TYPE: { + int const rawColor = PNM_GET1(xelrow[col]); + + color = maxval == 255 ? rawColor : rawColor * 255 / maxval; + + } break; + + default: + color = PNM_GET1(xelrow[col]); + } + rastRow[cursor++] = color; } + *lenP = cursor; +} + - return pr_colormapP; + + +static void +doRowDepth24(const xel * const xelrow, + unsigned char * const rastRow, + unsigned int const cols, + int const format, + xelval const maxval, + unsigned int * const lenP) { + + /* Since depth is 24, we do NOT have a valid cht. */ + + unsigned int col; + unsigned int cursor; + + for (col = 0, cursor = 0; col < cols; ++col) { + xel adjustedXel; + + if (maxval == 255) + adjustedXel = xelrow[col]; + else + PPM_DEPTH(adjustedXel, xelrow[col], maxval, 255); + + rastRow[cursor++] = PPM_GETB(adjustedXel); + rastRow[cursor++] = PPM_GETG(adjustedXel); + rastRow[cursor++] = PPM_GETR(adjustedXel); + } + *lenP = cursor; +} + + + +static void +computeRaster(unsigned char * const rastRaster, + unsigned int const lineSize, + unsigned int const depth, + unsigned int const cols, + unsigned int const rows, + int const format, + xelval const maxval, + xel ** const xels, + colorhash_table const cht) { + + unsigned int row; + unsigned char * rastRow; + + for (row = 0, rastRow = &rastRaster[0]; row < rows; ++row) { + xel * const xelrow = xels[row]; + + unsigned int len; /* Number of bytes of rast data added to rastRow[] */ + + switch (depth) { + case 1: + doRowDepth1(xelrow, rastRow, cols, format, maxval, cht, &len); + break; + case 8: + doRowDepth8(xelrow, rastRow, cols, format, maxval, cht, &len); + break; + case 24: + doRowDepth24(xelrow, rastRow, cols, format, maxval, &len); + break; + default: + pm_error("INTERNAL ERROR: impossible depth %u", depth); + } + { + /* Pad out the line (which has a rounded size) with zeroes so + the resulting file is repeatable. + */ + unsigned int i; + for (i = len; i < lineSize; ++i) + rastRow[i] = 0; + } + rastRow += lineSize; + } } int -main(int argc, char ** argv) { +main(int argc, const char ** argv) { - FILE* ifp; - xel** xels; - xel* xelrow; + FILE * ifP; + xel ** xels; xel p; - register xel* xP; colorhist_vector chv; colorhash_table cht; - colormap_t* pr_colormapP; - int argn, pr_type, rows, cols, format, i; - int depth, colors, linesize, row; - register int col, bitcount; + colormap_t * prColormapP; + int argn; + int prType; + int rows, cols; + int format; + unsigned int depth; + int colorCt; xelval maxval; - struct pixrect* pr; - unsigned char* data; - register unsigned char* byteP; - const char* const usage = "[-standard|-rle] [pnmfile]"; + struct pixrect * prP; + const char * const usage = "[-standard|-rle] [pnmfile]"; - pnm_init( &argc, argv ); + pm_proginit(&argc, argv); argn = 1; - pr_type = RT_BYTE_ENCODED; + prType = RT_BYTE_ENCODED; while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) { if ( pm_keymatch( argv[argn], "-standard", 2 ) ) - pr_type = RT_STANDARD; + prType = RT_STANDARD; else if ( pm_keymatch( argv[argn], "-rle", 2 ) ) - pr_type = RT_BYTE_ENCODED; + prType = RT_BYTE_ENCODED; else pm_usage( usage ); ++argn; @@ -123,191 +305,96 @@ main(int argc, char ** argv) { if ( argn != argc ) { - ifp = pm_openr( argv[argn] ); + ifP = pm_openr( argv[argn] ); ++argn; } else - ifp = stdin; + ifP = stdin; if ( argn != argc ) pm_usage( usage ); - xels = pnm_readpnm( ifp, &cols, &rows, &maxval, &format ); + xels = pnm_readpnm(ifP, &cols, &rows, &maxval, &format); - pm_close( ifp ); + pm_close(ifP); /* Figure out the proper depth and colormap. */ - switch ( PNM_FORMAT_TYPE(format) ) - { + switch (PNM_FORMAT_TYPE(format)) { case PPM_TYPE: - pm_message( "computing colormap..." ); - chv = ppm_computecolorhist( xels, cols, rows, MAXCOLORS, &colors ); - if ( chv == (colorhist_vector) 0 ) - { + pm_message("computing colormap..."); + chv = ppm_computecolorhist(xels, cols, rows, MAXCOLORS, &colorCt); + if (!chv) { pm_message( - "Too many colors - proceeding to write a 24-bit non-mapped" ); + "Too many colors - proceeding to write a 24-bit non-mapped"); pm_message( "rasterfile. If you want 8 bits, try doing a 'pnmquant %d'.", - MAXCOLORS ); + MAXCOLORS); depth = 24; - pr_type = RT_STANDARD; - pr_colormapP = (colormap_t*) 0; - } - else - { - pm_message( "%d colors found", colors ); - - if ( maxval != 255 ) - for ( i = 0; i < colors; ++i ) - PPM_DEPTH( chv[i].color, chv[i].color, maxval, 255 ); - + prType = RT_STANDARD; + prColormapP = NULL; + } else { + pm_message("%u colors found", colorCt); + + if (maxval != 255) { + unsigned int i; + for (i = 0; i < colorCt; ++i) + PPM_DEPTH(chv[i].color, chv[i].color, maxval, 255); + } /* Force white to slot 0 and black to slot 1, if possible. */ - PPM_ASSIGN( p, 255, 255, 255 ); - ppm_addtocolorhist( chv, &colors, MAXCOLORS, &p, 0, 0 ); - PPM_ASSIGN( p, 0, 0, 0 ); - ppm_addtocolorhist( chv, &colors, MAXCOLORS, &p, 0, 1 ); - - if ( colors == 2 ) - { - /* Monochrome. */ + PPM_ASSIGN(p, 255, 255, 255); + ppm_addtocolorhist(chv, &colorCt, MAXCOLORS, &p, 0, 0); + PPM_ASSIGN(p, 0, 0, 0); + ppm_addtocolorhist(chv, &colorCt, MAXCOLORS, &p, 0, 1); + + if (colorCt == 2) { + /* Monochrome */ depth = 1; - pr_colormapP = (colormap_t*) 0; - } - else - { + prColormapP = NULL; + } else { /* Turn the ppm colormap into the appropriate Sun colormap. */ depth = 8; - pr_colormapP = make_pr_colormap( chv, colors ); + prColormapP = makePrColormap(chv, colorCt); } - cht = ppm_colorhisttocolorhash( chv, colors ); - ppm_freecolorhist( chv ); + cht = ppm_colorhisttocolorhash(chv, colorCt); + ppm_freecolorhist(chv); } break; case PGM_TYPE: depth = 8; - pr_colormapP = make_gray_pr_colormap( ); + prColormapP = makeGrayPrColormap(); break; default: depth = 1; - pr_colormapP = (colormap_t*) 0; + prColormapP = NULL; break; } - if ( maxval > 255 && depth != 1 ) + if (maxval > 255 && depth != 1) pm_message( - "maxval is not 255 - automatically rescaling colors" ); + "maxval is not 255 - automatically rescaling colors"); /* Allocate space for the Sun-format image. */ - if ( (pr = mem_create(cols, rows, depth)) == (struct pixrect*) 0 ) - pm_error( "unable to create new pixrect" ); - data = ( (struct mpr_data*) pr->pr_data )->md_image; - linesize = ( (struct mpr_data*) pr->pr_data )->md_linebytes; - - /* And compute the Sun image. The variables at this point are: - ** cht is null or not - ** depth is 1, 8, or 24 - */ - for ( row = 0; row < rows; ++row ) - { - xelrow = xels[row]; - byteP = data; - switch ( depth ) - { - case 1: - *byteP = 0; - bitcount = 7; - for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) - { - register int color; - - switch ( PNM_FORMAT_TYPE(format) ) - { - case PPM_TYPE: - if ( maxval != 255 ) - PPM_DEPTH( *xP, *xP, maxval, 255 ); - color = ppm_lookupcolor( cht, xP ); - if ( color == -1 ) - pm_error( - "color not found?!? row=%d col=%d r=%d g=%d b=%d", - row, col, PPM_GETR(*xP), PPM_GETG(*xP), - PPM_GETB(*xP) ); - if ( color ) - *byteP |= 1 << bitcount; - break; - - default: - color = PNM_GET1( *xP ); - if ( ! color ) - *byteP |= 1 << bitcount; - break; - } - --bitcount; - if ( bitcount < 0 ) - { - ++byteP; - *byteP = 0; - bitcount = 7; - } - } - break; - - case 8: - for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) - { - register int color; - - switch ( PNM_FORMAT_TYPE(format) ) - { - case PPM_TYPE: - if ( maxval != 255 ) - PPM_DEPTH( *xP, *xP, maxval, 255 ); - color = ppm_lookupcolor( cht, xP ); - if ( color == -1 ) - pm_error( - "color not found?!? row=%d col=%d r=%d g=%d b=%d", - row, col, PPM_GETR(*xP), PPM_GETG(*xP), - PPM_GETB(*xP) ); - break; - - case PGM_TYPE: - color = PNM_GET1( *xP ); - if ( maxval != 255 ) - color = color * 255 / maxval; - break; - - default: - color = PNM_GET1( *xP ); - } - *byteP++ = color; - } - break; + prP = mem_create(cols, rows, depth); + if (!prP) + pm_error("unable to create new pixrect"); - case 24: - /* If depth is 24, we do NOT have a valid cht. */ - for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) - { - if ( maxval != 255 ) - PPM_DEPTH( *xP, *xP, maxval, 255 ); - *byteP++ = PPM_GETB( *xP ); - *byteP++ = PPM_GETG( *xP ); - *byteP++ = PPM_GETR( *xP ); - } - break; + computeRaster(prP->pr_data->md_image, + prP->pr_data->md_linebytes, + depth, + cols, rows, format, maxval, xels, cht); - default: - pm_error( "can't happen" ); - } - data += linesize; - } - pnm_freearray( xels, rows ); + pnm_freearray(xels, rows); - /* Finally, write the sucker out. */ - if ( pr_dump( pr, stdout, pr_colormapP, pr_type, 0 ) == PIX_ERR ) - pm_error( "error writing rasterfile" ); + { + int rc; - exit( 0 ); + rc = pr_dump(prP, stdout, prColormapP, prType, 0); + if (rc == PIX_ERR ) + pm_error("error writing rasterfile"); + } + return 0; } diff --git a/converter/other/pnmtosgi.c b/converter/other/pnmtosgi.c index 472b5197..cc57349f 100644 --- a/converter/other/pnmtosgi.c +++ b/converter/other/pnmtosgi.c @@ -13,342 +13,349 @@ ** implied warranty. ** ** 29Jan94: first version + +** Feb 2010 afu +** Added dimension check to prevent short int from overflowing */ + +#include + #include "pnm.h" #include "sgi.h" #include "mallocvar.h" +#include "runlength.h" + /*#define DEBUG*/ -typedef short ScanElem; +typedef uint16_t ScanElem; typedef struct { ScanElem * data; long length; } ScanLine; -/* prototypes */ -static void put_big_short ARGS((short s)); -static void put_big_long ARGS((long l)); -#define put_byte(b) (void)(putc((unsigned char)(b), stdout)) -static void put_short_as_byte ARGS((short s)); -static void write_table ARGS((long *table, int tabsize)); -static void write_channels ARGS((int cols, int rows, int channels, void (*put) ARGS((short)) )); -static long * build_channels ARGS((FILE *ifp, int cols, int rows, xelval maxval, int format, int bpc, int channels)); -static ScanElem *compress ARGS((ScanElem *temp, int row, int rows, int cols, int chan_no, long *table, int bpc)); -static int rle_compress ARGS((ScanElem *inbuf, int cols)); - -#define WORSTCOMPR(x) (2*(x) + 2) - - #define MAXVAL_BYTE 255 #define MAXVAL_WORD 65535 +#define INT16MAX 32767 static char storage = STORAGE_RLE; static ScanLine * channel[3]; -static ScanElem * rletemp; static xel * pnmrow; -static void -write_header(int const cols, - int const rows, - xelval const maxval, - int const bpc, - int const dimensions, - int const channels, - const char * const imagename) -{ - int i; - -#ifdef DEBUG - pm_message("writing header"); -#endif - - put_big_short(SGI_MAGIC); - put_byte(storage); - put_byte((char)bpc); - put_big_short(dimensions); - put_big_short(cols); - put_big_short(rows); - put_big_short(channels); - put_big_long(0); /* PIXMIN */ - put_big_long(maxval); /* PIXMAX */ - for( i = 0; i < 4; i++ ) - put_byte(0); - for( i = 0; i < 79 && imagename[i] != '\0'; i++ ) - put_byte(imagename[i]); - for(; i < 80; i++ ) - put_byte(0); - put_big_long(CMAP_NORMAL); - for( i = 0; i < 404; i++ ) - put_byte(0); -} +#define putByte(b) (void)(putc((unsigned char)(b), stdout)) -int -main(argc, argv) - int argc; - char *argv[]; -{ - FILE *ifp; - int argn; - const char * const usage = "[-verbatim|-rle] [-imagename ] [pnmfile]"; - int cols, rows, format; - xelval maxval, newmaxval; - const char *imagename = "no name"; - int bpc, dimensions, channels; - long *table = NULL; +static void +putBigShort(short const s) { - pnm_init(&argc, argv); + if (pm_writebigshort(stdout, s ) == -1) + pm_error( "write error" ); +} - argn = 1; - while( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) { - if( pm_keymatch(argv[argn], "-verbatim", 2) ) - storage = STORAGE_VERBATIM; - else - if( pm_keymatch(argv[argn], "-rle", 2) ) - storage = STORAGE_RLE; - else - if( pm_keymatch(argv[argn], "-imagename", 2) ) { - if( ++argn >= argc ) - pm_usage(usage); - imagename = argv[argn]; - } - else - pm_usage(usage); - ++argn; - } - if( argn < argc ) { - ifp = pm_openr( argv[argn] ); - argn++; - } - else - ifp = stdin; - if( argn != argc ) - pm_usage(usage); +static void +putBigLong(long const l) { - pnm_readpnminit(ifp, &cols, &rows, &maxval, &format); - pnmrow = pnm_allocrow(cols); + if (pm_writebiglong( stdout, l ) == -1) + pm_error( "write error" ); +} - switch( PNM_FORMAT_TYPE(format) ) { - case PBM_TYPE: - newmaxval = PGM_MAXMAXVAL; - pm_message("promoting PBM to PGM"); - case PGM_TYPE: - newmaxval = maxval; - dimensions = 2; channels = 1; - break; - case PPM_TYPE: - newmaxval = maxval; - dimensions = 3; channels = 3; - break; - default: - pm_error("can\'t happen"); - } - if( newmaxval <= MAXVAL_BYTE ) - bpc = 1; - else if( newmaxval <= MAXVAL_WORD ) - bpc = 2; - else - pm_error("maxval too large - try using \"pnmdepth %d\"", MAXVAL_WORD); - table = build_channels(ifp, cols, rows, newmaxval, format, bpc, channels); - pnm_freerow(pnmrow); - pm_close(ifp); - write_header(cols, rows, newmaxval, bpc, dimensions, channels, imagename); - if( table ) - write_table(table, rows * channels); - if( bpc == 1 ) - write_channels(cols, rows, channels, put_short_as_byte); - else - write_channels(cols, rows, channels, put_big_short); +static void +putShortAsByte(short const s) { - exit(0); + putByte((unsigned char)s); } + static void -write_table(table, tabsize) - long *table; - int tabsize; -{ - int i; - long offset; +writeTable(long * const table, + unsigned int const tabsize) { -#ifdef DEBUG - pm_message("writing table"); -#endif + unsigned int i; + unsigned long offset; offset = HeaderSize + tabsize * 8; - for( i = 0; i < tabsize; i++ ) { - put_big_long(offset); + + for (i = 0; i < tabsize; ++i) { + putBigLong(offset); offset += table[i]; } - for( i = 0; i < tabsize; i++ ) - put_big_long(table[i]); + for (i = 0; i < tabsize; ++i) + putBigLong(table[i]); } + static void -write_channels(cols, rows, channels, put) - int cols, rows, channels; - void (*put) ARGS((short)); -{ - int i, row, col; - -#ifdef DEBUG - pm_message("writing image data"); -#endif - - for( i = 0; i < channels; i++ ) { - for( row = 0; row < rows; row++ ) { - for( col = 0; col < channel[i][row].length; col++ ) { +writeChannels(unsigned int const cols, + unsigned int const rows, + unsigned int const channels, + void (*put) (short)) { + + unsigned int i; + + for (i = 0; i < channels; ++i) { + unsigned int row; + for (row = 0; row < rows; ++row) { + unsigned int col; + for (col = 0; col < channel[i][row].length; ++col) { (*put)(channel[i][row].data[col]); } + pm_rlenc_freebuf((unsigned char *) channel[i][row].data); } } } -static void -put_big_short(short s) -{ - if ( pm_writebigshort( stdout, s ) == -1 ) - pm_error( "write error" ); -} -static void -put_big_long(l) - long l; -{ - if ( pm_writebiglong( stdout, l ) == -1 ) - pm_error( "write error" ); +static ScanElem * +compress(ScanElem * const tempArg, + unsigned int const row, + unsigned int const rows, + unsigned int const cols, + unsigned int const chanNum, + long * const table, + unsigned int const bpc) { +/*---------------------------------------------------------------------------- + Compress a row, putting results in global 'channel' array, in newly + allocated storage (which Caller must free). + + Except that if the compression is null compression, we make 'channel' + point to existing storage, which Caller must not free. Yuck. +-----------------------------------------------------------------------------*/ + ScanElem * retval; + + switch (storage) { + case STORAGE_VERBATIM: + channel[chanNum][row].length = cols; + channel[chanNum][row].data = tempArg; + MALLOCARRAY_NOFAIL(retval, cols); + break; + case STORAGE_RLE: { + unsigned int const tabrow = chanNum * rows + row; + + unsigned int len; + size_t lenBytes; + ScanElem * p; + + pm_rlenc_allocoutbuf((unsigned char **) &p, cols, PM_RLE_SGI16); + + pm_rlenc_compressword(tempArg,(unsigned char *) p, PM_RLE_SGI16, + cols, &lenBytes); + + assert((unsigned)lenBytes == lenBytes); + /* Guaranteed by pm_rlenc_compressword() */ + + len = lenBytes / 2; /* sizeof(ScanElem) */ + channel[chanNum][row].length = len; + REALLOCARRAY(p, len); /* reclaim some space */ + if (p == NULL) + pm_error("realloc failure while reclaiming memory space " + "for output"); + channel[chanNum][row].data = p; + table[tabrow] = len * bpc; + retval = tempArg; + } break; + default: + pm_error("unknown storage type - can't happen"); + } + return retval; } -static void -put_short_as_byte(short s) -{ - put_byte((unsigned char)s); -} - static long * -build_channels(FILE *ifp, int cols, int rows, xelval maxval, - int format, int bpc, int channels) -{ - int i, row, col, sgirow; - long *table = NULL; - ScanElem *temp; - -#ifdef DEBUG - pm_message("building channels"); -#endif - - if( storage != STORAGE_VERBATIM ) { +buildChannels(FILE * const ifP, + unsigned int const cols, + unsigned int const rows, + xelval const maxval, + int const format, + unsigned int const bpc, + unsigned int const channels) { + + unsigned int row; + unsigned int sgirow; + long * table; + ScanElem * temp; + + if (storage != STORAGE_VERBATIM) { MALLOCARRAY_NOFAIL(table, channels * rows); - MALLOCARRAY_NOFAIL(rletemp, WORSTCOMPR(cols)); - } + } else + table = NULL; + MALLOCARRAY_NOFAIL(temp, cols); - for( i = 0; i < channels; i++ ) - MALLOCARRAY_NOFAIL(channel[i], rows); + { + unsigned int i; + for (i = 0; i < channels; ++i) + MALLOCARRAY_NOFAIL(channel[i], rows); + } - for( row = 0, sgirow = rows-1; row < rows; row++, sgirow-- ) { - pnm_readpnmrow(ifp, pnmrow, cols, maxval, format); - if( channels == 1 ) { - for( col = 0; col < cols; col++ ) + for (row = 0, sgirow = rows-1; row < rows; ++row, --sgirow) { + pnm_readpnmrow(ifP, pnmrow, cols, maxval, format); + if (channels == 1) { + unsigned int col; + for (col = 0; col < cols; ++col) temp[col] = (ScanElem)PNM_GET1(pnmrow[col]); temp = compress(temp, sgirow, rows, cols, 0, table, bpc); - } - else { - for( col = 0; col < cols; col++ ) + } else { + unsigned int col; + for (col = 0; col < cols; ++col) temp[col] = (ScanElem)PPM_GETR(pnmrow[col]); temp = compress(temp, sgirow, rows, cols, 0, table, bpc); - for( col = 0; col < cols; col++ ) + for (col = 0; col < cols; ++col) temp[col] = (ScanElem)PPM_GETG(pnmrow[col]); temp = compress(temp, sgirow, rows, cols, 1, table, bpc); - for( col = 0; col < cols; col++ ) + for (col = 0; col < cols; ++col) temp[col] = (ScanElem)PPM_GETB(pnmrow[col]); temp = compress(temp, sgirow, rows, cols, 2, table, bpc); } } free(temp); - if( table ) - free(rletemp); return table; } -static ScanElem * -compress(temp, row, rows, cols, chan_no, table, bpc) - ScanElem *temp; - int row, rows, cols, chan_no; - long *table; - int bpc; -{ - int len, i, tabrow; - ScanElem *p; - - switch( storage ) { - case STORAGE_VERBATIM: - channel[chan_no][row].length = cols; - channel[chan_no][row].data = temp; - MALLOCARRAY_NOFAIL(temp, cols); + +static void +writeHeader(unsigned int const cols, + unsigned int const rows, + xelval const maxval, + unsigned int const bpc, + unsigned int const dimensions, + unsigned int const channels, + const char * const imagename) { + + unsigned int i; + + putBigShort(SGI_MAGIC); + putByte(storage); + putByte((char)bpc); + putBigShort(dimensions); + putBigShort(cols); + putBigShort(rows); + putBigShort(channels); + putBigLong(0); /* PIXMIN */ + putBigLong(maxval); /* PIXMAX */ + + for(i = 0; i < 4; ++i) + putByte(0); + + for (i = 0; i < 79 && imagename[i] != '\0'; ++i) + putByte(imagename[i]); + + for(; i < 80; ++i) + putByte(0); + + putBigLong(CMAP_NORMAL); + + for (i = 0; i < 404; ++i) + putByte(0); +} + + + +int +main(int argc,char * argv[]) { + + FILE * ifP; + int argn; + const char * const usage = "[-verbatim|-rle] [-imagename ] [pnmfile]"; + int cols, rows; + int format; + xelval maxval, newmaxval; + const char * imagename; + unsigned int bpc; + unsigned int dimensions; + unsigned int channels; + long * table; + + pnm_init(&argc, argv); + + imagename = "no name"; /* default value */ + argn = 1; + while( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) { + if( pm_keymatch(argv[argn], "-verbatim", 2) ) + storage = STORAGE_VERBATIM; + else + if( pm_keymatch(argv[argn], "-rle", 2) ) + storage = STORAGE_RLE; + else + if( pm_keymatch(argv[argn], "-imagename", 2) ) { + if( ++argn >= argc ) + pm_usage(usage); + imagename = argv[argn]; + } + else + pm_usage(usage); + ++argn; + } + + if( argn < argc ) { + ifP = pm_openr( argv[argn] ); + argn++; + } + else + ifP = stdin; + + if( argn != argc ) + pm_usage(usage); + + pnm_readpnminit(ifP, &cols, &rows, &maxval, &format); + + if (rows > INT16MAX || cols > INT16MAX) + pm_error ("Input image is too large."); + + pnmrow = pnm_allocrow(cols); + + switch (PNM_FORMAT_TYPE(format)) { + case PBM_TYPE: + pm_message("promoting PBM to PGM"); + newmaxval = PGM_MAXMAXVAL; + case PGM_TYPE: + newmaxval = maxval; + dimensions = 2; + channels = 1; break; - case STORAGE_RLE: - tabrow = chan_no * rows + row; - len = rle_compress(temp, cols); /* writes result into rletemp */ - channel[chan_no][row].length = len; - MALLOCARRAY(p, len); - channel[chan_no][row].data = p; - for( i = 0; i < len; i++, p++ ) - *p = rletemp[i]; - table[tabrow] = len * bpc; + case PPM_TYPE: + newmaxval = maxval; + dimensions = 3; + channels = 3; break; default: - pm_error("unknown storage type - can\'t happen"); + pm_error("can\'t happen"); } - return temp; -} + if (newmaxval <= MAXVAL_BYTE) + bpc = 1; + else if (newmaxval <= MAXVAL_WORD) + bpc = 2; + else + pm_error("maxval too large - try using \"pnmdepth %u\"", MAXVAL_WORD); + table = buildChannels(ifP, cols, rows, newmaxval, format, bpc, channels); -/* -slightly modified RLE algorithm from ppmtoilbm.c -written by Robert A. Knop (rknop@mop.caltech.edu) -*/ -static int -rle_compress(inbuf, size) - ScanElem *inbuf; - int size; -{ - int in, out, hold, count; - ScanElem *outbuf = rletemp; - - in=out=0; - while( in=size-2)&&(in=127 ) - break; - } - outbuf[hold]=(ScanElem)(count | 0x80); - } - } - outbuf[out++] = (ScanElem)0; /* terminator */ - return(out); + pnm_freerow(pnmrow); + + pm_close(ifP); + + writeHeader(cols, rows, newmaxval, bpc, dimensions, channels, imagename); + + if (table) + writeTable(table, rows * channels); + + if (bpc == 1) + writeChannels(cols, rows, channels, putShortAsByte); + else + writeChannels(cols, rows, channels, putBigShort); + + return 0; } + diff --git a/converter/other/pnmtoxwd.c b/converter/other/pnmtoxwd.c index b6439d28..eda2ee8f 100644 --- a/converter/other/pnmtoxwd.c +++ b/converter/other/pnmtoxwd.c @@ -20,11 +20,11 @@ #include "x11wd.h" -struct cmdlineInfo { +struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ - const char *inputFilespec; /* Filespecs of input file */ + const char * inputFilename; /* Filename of input file */ unsigned int pseudodepth; unsigned int directcolor; }; @@ -34,7 +34,7 @@ struct cmdlineInfo { static void parseCommandLine(int argc, char ** argv, - struct cmdlineInfo * const cmdlineP) { + struct CmdlineInfo * const cmdlineP) { /* -------------------------------------------------------------------------- Parse program command line described in Unix standard form by argc and argv. Return the information in the options as *cmdlineP. @@ -46,7 +46,7 @@ parseCommandLine(int argc, was passed to us as the argv array. We also trash *argv. --------------------------------------------------------------------------*/ optEntry *option_def; - /* Instructions to optParseOptions3 on how to parse our options. */ + /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; unsigned int option_def_index; @@ -63,7 +63,7 @@ parseCommandLine(int argc, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3( &argc, argv, opt, sizeof(opt), 0 ); + pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0 ); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (!depthSpec) @@ -78,12 +78,12 @@ parseCommandLine(int argc, } if (argc-1 == 0) - cmdlineP->inputFilespec = "-"; + cmdlineP->inputFilename = "-"; else if (argc-1 != 1) pm_error("Program takes zero or one argument (filename). You " "specified %d", argc-1); else - cmdlineP->inputFilespec = argv[1]; + cmdlineP->inputFilename = argv[1]; } @@ -410,7 +410,7 @@ writeRaster(FILE * const ofP, int main(int argc, char * argv[]) { - struct cmdlineInfo cmdline; + struct CmdlineInfo cmdline; FILE* ifP; xel ** xels; int rows, cols, format, colors; @@ -426,7 +426,7 @@ main(int argc, char * argv[]) { parseCommandLine(argc, argv, &cmdline); - ifP = pm_openr(cmdline.inputFilespec); + ifP = pm_openr(cmdline.inputFilename); xels = pnm_readpnm(ifP, &cols, &rows, &maxval, &format); xmaxval = (1 << cmdline.pseudodepth) - 1; @@ -473,13 +473,13 @@ main(int argc, char * argv[]) { } } - if (streq(cmdline.inputFilespec, "-")) + if (streq(cmdline.inputFilename, "-")) dumpname = "stdin"; else { - if (strlen(cmdline.inputFilespec) > XWDVAL_MAX - sizeof(h11) - 1) + if (strlen(cmdline.inputFilename) > XWDVAL_MAX - sizeof(h11) - 1) pm_error("Input file name is ridiculously long."); else - dumpname = cmdline.inputFilespec; + dumpname = cmdline.inputFilename; } setupX11Header(&h11, dumpname, cols, rows, format, diff --git a/converter/other/ppmtopgm.c b/converter/other/ppmtopgm.c index 86e7ae6a..e20c5660 100644 --- a/converter/other/ppmtopgm.c +++ b/converter/other/ppmtopgm.c @@ -36,9 +36,9 @@ convertRaster(FILE * const ifP, outputRow[col] = (gray) ppm_fastlumin(inputRow[col]); } else { /* Can't use fast approximation, so fall back on floats. */ - int col; + unsigned int col; for (col = 0; col < cols; ++col) - outputRow[col] = (gray) (PPM_LUMIN(inputRow[col]) + 0.5); + outputRow[col] = ppm_luminosity(inputRow[col]); } pgm_writepgmrow(ofP, outputRow, cols, maxval, 0); } diff --git a/converter/other/pstopnm.c b/converter/other/pstopnm.c index ba1470b0..b253442f 100644 --- a/converter/other/pstopnm.c +++ b/converter/other/pstopnm.c @@ -18,6 +18,7 @@ #define _XOPEN_SOURCE 500 /* Make sure fdopen() is in stdio.h and strdup() is in string.h */ +#include #include #include #include @@ -27,12 +28,15 @@ #include #include "pm_c_util.h" +#include "mallocvar.h" #include "pnm.h" #include "shhopt.h" #include "nstring.h" -enum orientation {PORTRAIT, LANDSCAPE, UNSPECIFIED}; -struct box { +static bool verbose; + +enum Orientation {PORTRAIT, LANDSCAPE, UNSPECIFIED}; +struct Box { /* Description of a rectangle within an image; all coordinates measured in points (1/72") with lower left corner of page being the origin. @@ -44,15 +48,28 @@ struct box { int ury; /* upper right Y coord */ }; -struct cmdlineInfo { +struct Dimensions { +/*---------------------------------------------------------------------------- + Horizontal and vertical dimensions of something, both in pixels and + spatial distance (points). + + Sizes are in pixels. Resolutions are in dots per inch (pixels per inch); +-----------------------------------------------------------------------------*/ + unsigned int xsize; + unsigned int ysize; + unsigned int xres; + unsigned int yres; +}; + +struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ - const char *input_filespec; /* Filespecs of input files */ + const char * inputFileName; /* Names of input files */ unsigned int forceplain; - struct box extract_box; + struct Box extractBox; unsigned int nocrop; - unsigned int format_type; + unsigned int formatType; unsigned int verbose; float xborder; unsigned int xmax; @@ -61,30 +78,34 @@ struct cmdlineInfo { unsigned int ymax; unsigned int ysize; /* zero means unspecified */ unsigned int dpi; /* zero means unspecified */ - enum orientation orientation; - unsigned int goto_stdout; + enum Orientation orientation; + unsigned int stdoutSpec; + unsigned int textalphabits; }; static void parseCommandLine(int argc, char ** argv, - struct cmdlineInfo * const cmdlineP) { + struct CmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- Note that the file spec array we return is stored in the storage that was passed to us as the argv array. -----------------------------------------------------------------------------*/ - optEntry *option_def = malloc( 100*sizeof( optEntry ) ); - /* Instructions to optParseOptions3 on how to parse our options. + optEntry * option_def; + /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; unsigned int option_def_index; - unsigned int pbm_opt, pgm_opt, ppm_opt; - unsigned int portrait_opt, landscape_opt; + unsigned int pbmOpt, pgmOpt, ppmOpt; + unsigned int portraitOpt, landscapeOpt; float llx, lly, urx, ury; unsigned int llxSpec, llySpec, urxSpec, urySpec; unsigned int xmaxSpec, ymaxSpec, xsizeSpec, ysizeSpec, dpiSpec; + unsigned int textalphabitsSpec; + + MALLOCARRAY_NOFAIL(option_def, 100); option_def_index = 0; /* incremented by OPTENTRY */ OPTENT3(0, "forceplain", OPT_FLAG, NULL, &cmdlineP->forceplain, 0); @@ -93,9 +114,9 @@ parseCommandLine(int argc, char ** argv, OPTENT3(0, "urx", OPT_FLOAT, &urx, &urxSpec, 0); OPTENT3(0, "ury", OPT_FLOAT, &ury, &urySpec, 0); OPTENT3(0, "nocrop", OPT_FLAG, NULL, &cmdlineP->nocrop, 0); - OPTENT3(0, "pbm", OPT_FLAG, NULL, &pbm_opt, 0); - OPTENT3(0, "pgm", OPT_FLAG, NULL, &pgm_opt, 0); - OPTENT3(0, "ppm", OPT_FLAG, NULL, &ppm_opt, 0); + OPTENT3(0, "pbm", OPT_FLAG, NULL, &pbmOpt , 0); + OPTENT3(0, "pgm", OPT_FLAG, NULL, &pgmOpt, 0); + OPTENT3(0, "ppm", OPT_FLAG, NULL, &ppmOpt, 0); OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); OPTENT3(0, "xborder", OPT_FLOAT, &cmdlineP->xborder, NULL, 0); OPTENT3(0, "xmax", OPT_UINT, &cmdlineP->xmax, &xmaxSpec, 0); @@ -104,9 +125,11 @@ parseCommandLine(int argc, char ** argv, OPTENT3(0, "ymax", OPT_UINT, &cmdlineP->ymax, &ymaxSpec, 0); OPTENT3(0, "ysize", OPT_UINT, &cmdlineP->ysize, &ysizeSpec, 0); OPTENT3(0, "dpi", OPT_UINT, &cmdlineP->dpi, &dpiSpec, 0); - OPTENT3(0, "portrait", OPT_FLAG, NULL, &portrait_opt, 0); - OPTENT3(0, "landscape", OPT_FLAG, NULL, &landscape_opt, 0); - OPTENT3(0, "stdout", OPT_FLAG, NULL, &cmdlineP->goto_stdout, 0); + OPTENT3(0, "portrait", OPT_FLAG, NULL, &portraitOpt, 0); + OPTENT3(0, "landscape", OPT_FLAG, NULL, &landscapeOpt, 0); + OPTENT3(0, "stdout", OPT_FLAG, NULL, &cmdlineP->stdoutSpec, 0); + OPTENT3(0, "textalphabits", OPT_UINT, + &cmdlineP->textalphabits, &textalphabitsSpec, 0); /* Set the defaults */ cmdlineP->xborder = cmdlineP->yborder = 0.1; @@ -115,7 +138,7 @@ parseCommandLine(int argc, char ** argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (xmaxSpec) { @@ -142,38 +165,38 @@ parseCommandLine(int argc, char ** argv, } else cmdlineP->ysize = 0; - if (portrait_opt & !landscape_opt) + if (portraitOpt && !landscapeOpt) cmdlineP->orientation = PORTRAIT; - else if (!portrait_opt & landscape_opt) + else if (!portraitOpt && landscapeOpt) cmdlineP->orientation = LANDSCAPE; - else if (!portrait_opt & !landscape_opt) + else if (!portraitOpt && !landscapeOpt) cmdlineP->orientation = UNSPECIFIED; else pm_error("Cannot specify both -portrait and -landscape options"); - if (pbm_opt) - cmdlineP->format_type = PBM_TYPE; - else if (pgm_opt) - cmdlineP->format_type = PGM_TYPE; - else if (ppm_opt) - cmdlineP->format_type = PPM_TYPE; + if (pbmOpt) + cmdlineP->formatType = PBM_TYPE; + else if (pgmOpt) + cmdlineP->formatType = PGM_TYPE; + else if (ppmOpt) + cmdlineP->formatType = PPM_TYPE; else - cmdlineP->format_type = PPM_TYPE; + cmdlineP->formatType = PPM_TYPE; /* If any one of the 4 bounding box coordinates is given on the command line, we default any of the 4 that aren't. */ if (llxSpec || llySpec || urxSpec || urySpec) { - if (!llxSpec) cmdlineP->extract_box.llx = 72; - else cmdlineP->extract_box.llx = llx * 72; - if (!llySpec) cmdlineP->extract_box.lly = 72; - else cmdlineP->extract_box.lly = lly * 72; - if (!urxSpec) cmdlineP->extract_box.urx = 540; - else cmdlineP->extract_box.urx = urx * 72; - if (!urySpec) cmdlineP->extract_box.ury = 720; - else cmdlineP->extract_box.ury = ury * 72; + if (!llxSpec) cmdlineP->extractBox.llx = 72; + else cmdlineP->extractBox.llx = llx * 72; + if (!llySpec) cmdlineP->extractBox.lly = 72; + else cmdlineP->extractBox.lly = lly * 72; + if (!urxSpec) cmdlineP->extractBox.urx = 540; + else cmdlineP->extractBox.urx = urx * 72; + if (!urySpec) cmdlineP->extractBox.ury = 720; + else cmdlineP->extractBox.ury = ury * 72; } else { - cmdlineP->extract_box.llx = -1; + cmdlineP->extractBox.llx = -1; } if (dpiSpec) { @@ -185,79 +208,93 @@ parseCommandLine(int argc, char ** argv, if (dpiSpec && xsizeSpec + ysizeSpec + xmaxSpec + ymaxSpec > 0) pm_error("You may not specify both size options and -dpi"); + if (textalphabitsSpec) { + if (cmdlineP->textalphabits != 1 && cmdlineP->textalphabits != 2 + && cmdlineP->textalphabits != 4) { + /* Pstopnm won't take this value, and we don't want to inflict + a Pstopnm failure error message on the user. + */ + pm_error("Valid values for -textalphabits are 1, 2, and 4. " + "You specified %u", cmdlineP->textalphabits ); + } + } else + cmdlineP->textalphabits = 4; + if (argc-1 == 0) - cmdlineP->input_filespec = "-"; /* stdin */ + cmdlineP->inputFileName = "-"; /* stdin */ else if (argc-1 == 1) - cmdlineP->input_filespec = argv[1]; + cmdlineP->inputFileName = argv[1]; else pm_error("Too many arguments (%d). " - "Only need one: the Postscript filespec", argc-1); + "Only need one: the Postscript file name", argc-1); + + free(option_def); } static void -addPsToFilespec(char const orig_filespec[], - const char ** const new_filespec_p, - bool const verbose) { +addPsToFileName(char const origFileName[], + const char ** const newFileNameP) { /*---------------------------------------------------------------------------- - If orig_filespec[] does not name an existing file, but the same + If origFileName[] does not name an existing file, but the same name with ".ps" added to the end does, return the name with the .ps - attached. Otherwise, just return orig_filespec[]. + attached. Otherwise, just return origFileName[]. Return the name in newly malloc'ed storage, pointed to by - *new_filespec_p. + *newFileNameP. -----------------------------------------------------------------------------*/ struct stat statbuf; - int stat_rc; + int statRc; - stat_rc = lstat(orig_filespec, &statbuf); + statRc = lstat(origFileName, &statbuf); - if (stat_rc == 0) - *new_filespec_p = strdup(orig_filespec); + if (statRc == 0) + *newFileNameP = strdup(origFileName); else { - const char *filespec_plus_ps; + const char * fileNamePlusPs; - asprintfN(&filespec_plus_ps, "%s.ps", orig_filespec); + pm_asprintf(&fileNamePlusPs, "%s.ps", origFileName); - stat_rc = lstat(filespec_plus_ps, &statbuf); - if (stat_rc == 0) - *new_filespec_p = strdup(filespec_plus_ps); + statRc = lstat(fileNamePlusPs, &statbuf); + if (statRc == 0) + *newFileNameP = strdup(fileNamePlusPs); else - *new_filespec_p = strdup(orig_filespec); - strfree(filespec_plus_ps); + *newFileNameP = strdup(origFileName); + pm_strfree(fileNamePlusPs); } if (verbose) - pm_message("Input file is %s", *new_filespec_p); + pm_message("Input file is %s", *newFileNameP); } static void -computeSizeResFromSizeSpec(unsigned int const requestedXsize, - unsigned int const requestedYsize, - unsigned int const imageWidth, - unsigned int const imageHeight, - unsigned int * const xsizeP, - unsigned int * const ysizeP, - unsigned int * const xresP, - unsigned int * const yresP) { +computeSizeResFromSizeSpec(unsigned int const requestedXsize, + unsigned int const requestedYsize, + unsigned int const imageWidth, + unsigned int const imageHeight, + struct Dimensions * const imageDimP) { if (requestedXsize) { - *xsizeP = requestedXsize; - *xresP = (unsigned int) (requestedXsize * 72 / imageWidth + 0.5); + imageDimP->xsize = requestedXsize; + imageDimP->xres = (unsigned int) + (requestedXsize * 72 / imageWidth + 0.5); if (!requestedYsize) { - *yresP = *xresP; - *ysizeP = (unsigned int) (imageHeight * (float)*yresP/72 + 0.5); + imageDimP->yres = imageDimP->xres; + imageDimP->ysize = (unsigned int) + (imageHeight * (float)imageDimP->yres/72 + 0.5); } } if (requestedYsize) { - *ysizeP = requestedYsize; - *yresP = (unsigned int) (requestedYsize * 72 / imageHeight + 0.5); + imageDimP->ysize = requestedYsize; + imageDimP->yres = (unsigned int) + (requestedYsize * 72 / imageHeight + 0.5); if (!requestedXsize) { - *xresP = *yresP; - *xsizeP = (unsigned int) (imageWidth * (float)*xresP/72 + 0.5); + imageDimP->xres = imageDimP->yres; + imageDimP->xsize = (unsigned int) + (imageWidth * (float)imageDimP->xres/72 + 0.5); } } } @@ -265,42 +302,36 @@ computeSizeResFromSizeSpec(unsigned int const requestedXsize, static void -computeSizeResBlind(unsigned int const xmax, - unsigned int const ymax, - unsigned int const imageWidth, - unsigned int const imageHeight, - bool const nocrop, - unsigned int * const xsizeP, - unsigned int * const ysizeP, - unsigned int * const xresP, - unsigned int * const yresP) { - - *xresP = *yresP = MIN(xmax * 72 / imageWidth, - ymax * 72 / imageHeight); +computeSizeResBlind(unsigned int const xmax, + unsigned int const ymax, + unsigned int const imageWidth, + unsigned int const imageHeight, + bool const nocrop, + struct Dimensions * const imageDimP) { + + imageDimP->xres = imageDimP->yres = MIN(xmax * 72 / imageWidth, + ymax * 72 / imageHeight); if (nocrop) { - *xsizeP = xmax; - *ysizeP = ymax; + imageDimP->xsize = xmax; + imageDimP->ysize = ymax; } else { - *xsizeP = (unsigned int) (imageWidth * (float)*xresP / 72 + 0.5); - *ysizeP = (unsigned int) (imageHeight * (float)*yresP / 72 + 0.5); + imageDimP->xsize = (unsigned int) + (imageWidth * (float)imageDimP->xres / 72 + 0.5); + imageDimP->ysize = (unsigned int) + (imageHeight * (float)imageDimP->yres / 72 + 0.5); } } static void -computeSizeRes(struct cmdlineInfo const cmdline, - enum orientation const orientation, - struct box const bordered_box, - unsigned int * const xsizeP, - unsigned int * const ysizeP, - unsigned int * const xresP, - unsigned int * const yresP) { +computeSizeRes(struct CmdlineInfo const cmdline, + struct Box const borderedBox, + struct Dimensions * const imageDimP) { /*---------------------------------------------------------------------------- - Figure out how big the output image should be (return as - *xsizeP and *ysizeP) and what output device resolution Ghostscript - should assume (return as *xresP, *yresP). + Figure out how big the output image should be and what output device + resolution Ghostscript should assume (return as *imageDimP). A resolution number is the number of pixels per inch that the a printer prints. Since we're emulating a printed page with a PNM @@ -315,56 +346,50 @@ computeSizeRes(struct cmdlineInfo const cmdline, tell Ghostscript that our horizontal output device resolution is 500 pixels per inch. - *xresP and *yresP are in dots per inch. + X and Y in all returned values is with respect to the image, not the + page. Note that the image might be placed sideways on the page, so that + page X and Y would be reversed from image X and Y. -----------------------------------------------------------------------------*/ - unsigned int sx, sy; - /* The horizontal and vertical sizes of the input image, in points - (1/72 inch) - */ - - if (orientation == LANDSCAPE) { - sx = bordered_box.ury - bordered_box.lly; - sy = bordered_box.urx - bordered_box.llx; - } else { - sx = bordered_box.urx - bordered_box.llx; - sy = bordered_box.ury - bordered_box.lly; - } + /* The horizontal and vertical sizes of the input image, in points + (1/72 inch) + */ + unsigned int const sx = borderedBox.urx - borderedBox.llx; + unsigned int const sy = borderedBox.ury - borderedBox.lly; if (cmdline.dpi) { /* User gave resolution; we figure out output image size */ - *xresP = *yresP = cmdline.dpi; - *xsizeP = (int) (cmdline.dpi * sx / 72 + 0.5); - *ysizeP = (int) (cmdline.dpi * sy / 72 + 0.5); + imageDimP->xres = imageDimP->yres = cmdline.dpi; + imageDimP->xsize = ROUNDU(cmdline.dpi * sx / 72.0); + imageDimP->ysize = ROUNDU(cmdline.dpi * sy / 72.0); } else if (cmdline.xsize || cmdline.ysize) computeSizeResFromSizeSpec(cmdline.xsize, cmdline.ysize, sx, sy, - xsizeP, ysizeP, xresP, yresP); + imageDimP); else computeSizeResBlind(cmdline.xmax, cmdline.ymax, sx, sy, cmdline.nocrop, - xsizeP, ysizeP, xresP, yresP); + imageDimP); if (cmdline.verbose) { pm_message("output is %u pixels wide X %u pixels high", - *xsizeP, *ysizeP); + imageDimP->xsize, imageDimP->ysize); pm_message("output device resolution is %u dpi horiz, %u dpi vert", - *xresP, *yresP); + imageDimP->xres, imageDimP->yres); } } -enum postscript_language {COMMON_POSTSCRIPT, ENCAPSULATED_POSTSCRIPT}; +enum PostscriptLanguage {COMMON_POSTSCRIPT, ENCAPSULATED_POSTSCRIPT}; -static enum postscript_language -languageDeclaration(char const input_filespec[], - bool const verbose) { +static enum PostscriptLanguage +languageDeclaration(char const inputFileName[]) { /*---------------------------------------------------------------------------- Return the Postscript language in which the file declares it is written. (Except that if the file is on Standard Input or doesn't validly declare a languages, just say it is Common Postscript). -----------------------------------------------------------------------------*/ - enum postscript_language language; + enum PostscriptLanguage language; - if (streq(input_filespec, "-")) + if (streq(inputFileName, "-")) /* Can't read stdin, because we need it to remain positioned for the Ghostscript interpreter to read it. */ @@ -373,14 +398,14 @@ languageDeclaration(char const input_filespec[], FILE *infile; char line[80]; - infile = pm_openr(input_filespec); + infile = pm_openr(inputFileName); if (fgets(line, sizeof(line), infile) == NULL) language = COMMON_POSTSCRIPT; else { - const char eps_header[] = " EPSF-"; + const char epsHeader[] = " EPSF-"; - if (strstr(line, eps_header)) + if (strstr(line, epsHeader)) language = ENCAPSULATED_POSTSCRIPT; else language = COMMON_POSTSCRIPT; @@ -397,61 +422,63 @@ languageDeclaration(char const input_filespec[], -static struct box -computeBoxToExtract(struct box const cmdline_extract_box, - char const input_filespec[], - bool const verbose) { +static struct Box +computeBoxToExtract(struct Box const cmdlineExtractBox, + char const inputFileName[]) { - struct box retval; + struct Box retval; - if (cmdline_extract_box.llx != -1) + if (cmdlineExtractBox.llx != -1) /* User told us what box to extract, so that's what we'll do */ - retval = cmdline_extract_box; + retval = cmdlineExtractBox; else { /* Try to get the bounding box from the DSC %%BoundingBox statement (A Postscript comment) in the input. */ - struct box ps_bb; /* Box described by %%BoundingBox stmt in input */ + struct Box psBb; /* Box described by %%BoundingBox stmt in input */ - if (streq(input_filespec, "-")) + if (streq(inputFileName, "-")) /* Can't read stdin, because we need it to remain positioned for the Ghostscript interpreter to read it. */ - ps_bb.llx = -1; + psBb.llx = -1; else { - FILE *infile; - int found_BB, eof; /* logical */ - infile = pm_openr(input_filespec); + FILE * ifP; + bool foundBb; + bool eof; + + ifP = pm_openr(inputFileName); - found_BB = FALSE; - eof = FALSE; - while (!eof && !found_BB) { + for (foundBb = FALSE, eof = FALSE; !foundBb && !eof; ) { char line[200]; - - if (fgets(line, sizeof(line), infile) == NULL) + char * fgetsRc; + + fgetsRc = fgets(line, sizeof(line), ifP); + + if (fgetsRc == NULL) eof = TRUE; else { int rc; rc = sscanf(line, "%%%%BoundingBox: %d %d %d %d", - &ps_bb.llx, &ps_bb.lly, - &ps_bb.urx, &ps_bb.ury); + &psBb.llx, &psBb.lly, + &psBb.urx, &psBb.ury); if (rc == 4) - found_BB = TRUE; + foundBb = TRUE; } } - fclose(infile); + fclose(ifP); - if (!found_BB) { - ps_bb.llx = -1; + if (!foundBb) { + psBb.llx = -1; pm_message("Warning: no %%%%BoundingBox statement " - "in the input or command line.\n" + "in the input or command line. " "Will use defaults"); } } - if (ps_bb.llx != -1) { + if (psBb.llx != -1) { if (verbose) pm_message("Using %%%%BoundingBox statement from input."); - retval = ps_bb; + retval = psBb; } else { /* Use the center of an 8.5" x 11" page with 1" border all around*/ retval.llx = 72; @@ -468,44 +495,75 @@ computeBoxToExtract(struct box const cmdline_extract_box, -static enum orientation -computeOrientation(struct cmdlineInfo const cmdline, - struct box const extract_box) { +static enum Orientation +computeOrientation(struct CmdlineInfo const cmdline, + struct Box const extractBox) { +/*---------------------------------------------------------------------------- + The proper orientation of the image on the page, given the user's + parameters 'cmdline' and the image dimensions 'extractBox'. +-----------------------------------------------------------------------------*/ + /* We're putting an _image_ on a _page_. Either one can have portrait or + landscape aspect ratio. In our return value, orientation just means + whether the image is rotated on the page: Portrait means it isn't + Landscape means it is. The result can be confusing: Consider an image + which is a landscape, wider than it is tall, being printed on a page + which is also wider than it is tall. The orientation we would return + for that case is Portrait. + + The decision is simple: if the user didn't request a particular + orientation, we return the value that makes the image orientation match + the page orientation. If both possibilities match equally (because the + image or the page is square), we return Portrait. + */ - enum orientation retval; - unsigned int const input_width = extract_box.urx - extract_box.llx; - unsigned int const input_height = extract_box.ury - extract_box.lly; + enum Orientation retval; if (cmdline.orientation != UNSPECIFIED) retval = cmdline.orientation; else { - if ((!cmdline.xsize || !cmdline.ysize) & - (cmdline.xsize || cmdline.ysize)) { - /* User specified one output dimension, but not the other, - so we can't use output dimensions to make the decision. So - just use the input dimensions. - */ - if (input_height > input_width) retval = PORTRAIT; - else retval = LANDSCAPE; + /* Dimensions of image to print, in points */ + unsigned int const imageWidPt = extractBox.urx - extractBox.llx; + unsigned int const imageHgtPt = extractBox.ury - extractBox.lly; + + /* Dimensions of image to print, in pixels (possibly of assumed + resolution) + */ + unsigned int imageWidXel; + unsigned int imageHgtXel; + + /* We have to deal with the awkward case that the printed pixels are + not square. We match up the aspect ratio of the image in _pixels_ + and the aspect ratio of the page in _pixels_. But only the ratio + matters; we don't care what the absolute size of the pixels is. + And that's good, because if the user didn't specify xsize/ysize, we + don't know the absolute size in pixels. In that case, fortunately, + the pixels are guaranteed to be square so we can just pretend it is + one point per pixel and get the right result. + */ + + if (cmdline.xsize && cmdline.ysize) { + imageWidXel = cmdline.xsize; + imageHgtXel = cmdline.ysize; } else { - int output_width, output_height; - if (cmdline.xsize) { - /* He gave xsize and ysize, so that's the output size */ - output_width = cmdline.xsize; - output_height = cmdline.ysize; - } else { - /* Well then we'll just use his (or default) xmax, ymax */ - output_width = cmdline.xmax; - output_height = cmdline.ymax; - } + /* Pixels are square, so it doesn't matter what the resolution + is; just call it one pixel per point. + */ + imageWidXel = imageWidPt; + imageHgtXel = imageHgtPt; + } - if (input_height > input_width && output_height > output_width) - retval = PORTRAIT; - else if (input_height < input_width && - output_height < output_width) - retval = PORTRAIT; - else - retval = LANDSCAPE; + if (imageHgtXel >= imageWidXel && cmdline.ymax >= cmdline.xmax) { + /* Both image and page are higher than wide, so no rotation */ + retval = PORTRAIT; + } else if (imageHgtXel < imageWidXel && + cmdline.ymax < cmdline.xmax) { + /* Both image and page are wider than high, so no rotation */ + retval = PORTRAIT; + } else { + /* Image and pixel have opposite aspect ratios, so rotate + for best fit. + */ + retval = LANDSCAPE; } } return retval; @@ -513,29 +571,32 @@ computeOrientation(struct cmdlineInfo const cmdline, -static struct box -addBorders(struct box const input_box, - float const xborder_scale, - float const yborder_scale, - bool const verbose) { +static struct Box +addBorders(struct Box const inputBox, + float const xborderScale, + float const yborderScale) { /*---------------------------------------------------------------------------- - Return a box which is 'input_box' plus some borders. + Return a box which is 'inputBox' plus some borders. - Add left and right borders that are the fraction 'xborder_scale' of the + Add left and right borders that are the fraction 'xborderScale' of the width of the input box; likewise for top and bottom borders with - 'yborder_scale'. + 'yborderScale'. -----------------------------------------------------------------------------*/ - struct box retval; + unsigned int const leftRightBorderSize = + ROUNDU((inputBox.urx - inputBox.llx) * xborderScale); + unsigned int const topBottomBorderSize = + ROUNDU((inputBox.ury - inputBox.lly) * yborderScale); + + struct Box retval; - const int left_right_border_size = - (int) ((input_box.urx - input_box.llx) * xborder_scale + 0.5); - const int top_bottom_border_size = - (int) ((input_box.ury - input_box.lly) * yborder_scale + 0.5); - retval.llx = input_box.llx - left_right_border_size; - retval.lly = input_box.lly - top_bottom_border_size; - retval.urx = input_box.urx + left_right_border_size; - retval.ury = input_box.ury + top_bottom_border_size; + assert(inputBox.urx >= inputBox.llx); + assert(inputBox.ury >= inputBox.lly); + + retval.llx = inputBox.llx - (int)leftRightBorderSize; + retval.lly = inputBox.lly - (int)topBottomBorderSize; + retval.urx = inputBox.urx + (int)leftRightBorderSize; + retval.ury = inputBox.ury + (int)topBottomBorderSize; if (verbose) pm_message("With borders, extracted box is ((%d,%d),(%d,%d))", @@ -546,65 +607,87 @@ addBorders(struct box const input_box, -static const char * -computePstrans(struct box const box, - enum orientation const orientation, - int const xsize, - int const ysize, - int const xres, - int const yres) { +static void +writePstrans(struct Box const box, + struct Dimensions const d, + enum Orientation const orientation, + FILE * const pipeToGsP) { - const char * retval; + int const xsize = d.xsize; + int const ysize = d.ysize; + int const xres = d.xres; + int const yres = d.yres; + + const char * pstrans; - if (orientation == PORTRAIT) { + switch (orientation) { + case PORTRAIT: { int llx, lly; llx = box.llx - (xsize * 72 / xres - (box.urx - box.llx)) / 2; lly = box.lly - (ysize * 72 / yres - (box.ury - box.lly)) / 2; - asprintfN(&retval, "%d neg %d neg translate", llx, lly); - } else { + pm_asprintf(&pstrans, "%d neg %d neg translate", llx, lly); + } break; + case LANDSCAPE: { int llx, ury; - llx = box.llx - (ysize * 72 / yres - (box.urx - box.llx)) / 2; - ury = box.ury + (xsize * 72 / xres - (box.ury - box.lly)) / 2; - asprintfN(&retval, "90 rotate %d neg %d neg translate", llx, ury); + llx = box.llx - (xsize * 72 / xres - (box.urx - box.llx)) / 2; + ury = box.ury + (ysize * 72 / yres - (box.ury - box.lly)) / 2; + pm_asprintf(&pstrans, "90 rotate %d neg %d neg translate", llx, ury); + } break; + case UNSPECIFIED: + assert(false); } - if (retval == NULL) + if (pstrans == pm_strsol) pm_error("Unable to allocate memory for pstrans"); - return retval; + if (verbose) + pm_message("Postscript prefix command: '%s'", pstrans); + + fprintf(pipeToGsP, "%s\n", pstrans); + + pm_strfree(pstrans); } static const char * -computeOutfileArg(struct cmdlineInfo const cmdline) { - - const char *retval; /* malloc'ed */ +computeOutfileArg(struct CmdlineInfo const cmdline) { +/*---------------------------------------------------------------------------- + Determine the value for the "OutputFile" variable to pass to Ghostscript, + which is what tells Ghostscript where to put its output. This is either + a pattern such as "foo%03d.ppm" or "-" to indicate Standard Output. + + We go with "-" if, according to 'cmdline', the user asked for + Standard Output or is giving his input on Standard Input. Otherwise, + we go with the pattern, based on the name of the input file and output + format type the user requested. +-----------------------------------------------------------------------------*/ + const char * retval; /* malloc'ed */ - if (cmdline.goto_stdout) + if (cmdline.stdoutSpec) retval = strdup("-"); - else if (streq(cmdline.input_filespec, "-")) + else if (streq(cmdline.inputFileName, "-")) retval = strdup("-"); else { char * basename; const char * suffix; - basename = strdup(cmdline.input_filespec); + basename = strdup(cmdline.inputFileName); if (strlen(basename) > 3 && streq(basename+strlen(basename)-3, ".ps")) - /* The input filespec ends in ".ps". Chop it off. */ + /* The input file name ends in ".ps". Chop it off. */ basename[strlen(basename)-3] = '\0'; - switch (cmdline.format_type) { + switch (cmdline.formatType) { case PBM_TYPE: suffix = "pbm"; break; case PGM_TYPE: suffix = "pgm"; break; case PPM_TYPE: suffix = "ppm"; break; - default: pm_error("Internal error: invalid value for format_type: %d", - cmdline.format_type); + default: pm_error("Internal error: invalid value for formatType: %d", + cmdline.formatType); } - asprintfN(&retval, "%s%%03d.%s", basename, suffix); + pm_asprintf(&retval, "%s%%03d.%s", basename, suffix); - strfree(basename); + pm_strfree(basename); } return(retval); } @@ -612,22 +695,22 @@ computeOutfileArg(struct cmdlineInfo const cmdline) { static const char * -computeGsDevice(int const format_type, +computeGsDevice(int const formatType, bool const forceplain) { const char * basetype; const char * retval; - switch (format_type) { + switch (formatType) { case PBM_TYPE: basetype = "pbm"; break; case PGM_TYPE: basetype = "pgm"; break; case PPM_TYPE: basetype = "ppm"; break; - default: pm_error("Internal error: invalid value format_type"); + default: pm_error("Internal error: invalid value formatType"); } if (forceplain) retval = strdup(basetype); else - asprintfN(&retval, "%sraw", basetype); + pm_asprintf(&retval, "%sraw", basetype); if (retval == NULL) pm_error("Unable to allocate memory for gs device"); @@ -645,7 +728,7 @@ findGhostscriptProg(const char ** const retvalP) { *retvalP = strdup(getenv("GHOSTSCRIPT")); if (*retvalP == NULL) { if (getenv("PATH") != NULL) { - char *pathwork; /* malloc'ed */ + char * pathwork; /* malloc'ed */ const char * candidate; pathwork = strdup(getenv("PATH")); @@ -658,7 +741,7 @@ findGhostscriptProg(const char ** const retvalP) { const char * filename; int rc; - asprintfN(&filename, "%s/gs", candidate); + pm_asprintf(&filename, "%s/gs", candidate); rc = stat(filename, &statbuf); if (rc == 0) { if (S_ISREG(statbuf.st_mode)) @@ -667,7 +750,7 @@ findGhostscriptProg(const char ** const retvalP) { pm_error("Error looking for Ghostscript program. " "stat(\"%s\") returns errno %d (%s)", filename, errno, strerror(errno)); - strfree(filename); + pm_strfree(filename); candidate = strtok(NULL, ":"); } @@ -681,22 +764,26 @@ findGhostscriptProg(const char ** const retvalP) { static void -execGhostscript(int const inputPipeFd, - char const ghostscript_device[], - char const outfile_arg[], - int const xsize, - int const ysize, - int const xres, - int const yres, - char const input_filespec[], - bool const verbose) { - +execGhostscript(int const inputPipeFd, + char const ghostscriptDevice[], + char const outfileArg[], + struct Dimensions const pageDim, + unsigned int const textalphabits) { +/*---------------------------------------------------------------------------- + Exec the Ghostscript program and have it execute the Postscript program + that it receives on 'inputPipeFd', then exit. + + 'pageDim' describes the print area. X and Y in 'pageDim' are with respect + to the page, independent of whether the program we receive on 'inputPipeFd' + puts an image in there sideways. +-----------------------------------------------------------------------------*/ const char * arg0; const char * ghostscriptProg; const char * deviceopt; const char * outfileopt; const char * gopt; const char * ropt; + const char * textalphabitsopt; int rc; findGhostscriptProg(&ghostscriptProg); @@ -705,11 +792,12 @@ execGhostscript(int const inputPipeFd, rc = dup2(inputPipeFd, STDIN_FILENO); close(inputPipeFd); - asprintfN(&arg0, "gs"); - asprintfN(&deviceopt, "-sDEVICE=%s", ghostscript_device); - asprintfN(&outfileopt, "-sOutputFile=%s", outfile_arg); - asprintfN(&gopt, "-g%dx%d", xsize, ysize); - asprintfN(&ropt, "-r%dx%d", xres, yres); + pm_asprintf(&arg0, "gs"); + pm_asprintf(&deviceopt, "-sDEVICE=%s", ghostscriptDevice); + pm_asprintf(&outfileopt, "-sOutputFile=%s", outfileArg); + pm_asprintf(&gopt, "-g%dx%d", pageDim.xsize, pageDim.ysize); + pm_asprintf(&ropt, "-r%dx%d", pageDim.xres, pageDim.yres); + pm_asprintf(&textalphabitsopt, "-dTextAlphaBits=%u", textalphabits); /* -dSAFER causes Postscript to disable %pipe and file operations, which are almost certainly not needed here. This prevents our @@ -719,9 +807,10 @@ execGhostscript(int const inputPipeFd, if (verbose) { pm_message("execing '%s' with args '%s' (arg 0), " - "'%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s'", + "'%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s'", ghostscriptProg, arg0, - deviceopt, outfileopt, gopt, ropt, "-q", "-dNOPAUSE", + deviceopt, outfileopt, gopt, ropt, textalphabitsopt, + "-q", "-dNOPAUSE", "-dSAFER", "-"); } @@ -735,28 +824,126 @@ execGhostscript(int const inputPipeFd, static void -executeGhostscript(char const pstrans[], - char const ghostscript_device[], - char const outfile_arg[], - int const xsize, - int const ysize, - int const xres, - int const yres, - char const input_filespec[], - enum postscript_language const language, - bool const verbose) { - - int gs_exit; /* wait4 exit code from Ghostscript */ - FILE *gs; /* Pipe to Ghostscript's standard input */ - FILE *infile; +feedPsToGhostScript(const char * const inputFileName, + struct Box const borderedBox, + struct Dimensions const imageDim, + enum Orientation const orientation, + int const pipeToGhostscriptFd, + enum PostscriptLanguage const language) { +/*---------------------------------------------------------------------------- + Send a Postscript program to the Ghostscript process running on the + other end of the pipe 'pipeToGhostscriptFd'. That program is mostly + the contents of file 'inputFileName' (special value "-" means Standard + Input), but we may add a little to it. + + The image has dimensions 'imageDim' and is oriented on the page according + to 'orientation' ('imageDim' X and Y are with respect to the image itself, + without regard to how it is oriented on the page). +-----------------------------------------------------------------------------*/ + FILE * pipeToGsP; /* Pipe to Ghostscript's standard input */ + FILE * ifP; + bool eof; /* End of file on input */ + + pipeToGsP = fdopen(pipeToGhostscriptFd, "w"); + if (pipeToGsP == NULL) + pm_error("Unable to open stream on pipe to Ghostscript process."); + + ifP = pm_openr(inputFileName); + /* + In encapsulated Postscript, we the encapsulator are supposed to + handle showing the page (which we do by passing a showpage + statement to Ghostscript). Any showpage statement in the + input must be defined to have no effect. + + See "Enscapsulated PostScript Format File Specification", + v. 3.0, 1 May 1992, in particular Example 2, p. 21. I found + it at + http://partners.adobe.com/asn/developer/pdfs/tn/5002.EPSF_Spec.pdf + The example given is a much fancier solution than we need + here, I think, so I boiled it down a bit. JM + */ + if (language == ENCAPSULATED_POSTSCRIPT) + fprintf(pipeToGsP, "\n/b4_Inc_state save def /showpage { } def\n"); + + writePstrans(borderedBox, imageDim, orientation, pipeToGsP); + + /* If our child dies, it closes the pipe and when we next write to it, + we get a SIGPIPE. We must survive that signal in order to report + on the fate of the child. So we ignore SIGPIPE: + */ + signal(SIGPIPE, SIG_IGN); + + eof = FALSE; + while (!eof) { + char buffer[4096]; + size_t readCt; + + readCt = fread(buffer, 1, sizeof(buffer), ifP); + if (readCt == 0) + eof = TRUE; + else + fwrite(buffer, 1, readCt, pipeToGsP); + } + pm_close(ifP); + + if (language == ENCAPSULATED_POSTSCRIPT) + fprintf(pipeToGsP, "\nb4_Inc_state restore showpage\n"); + + fclose(pipeToGsP); +} + + + +static struct Dimensions +pageDimFromImageDim(struct Dimensions const imageDim, + enum Orientation const orientation) { +/*---------------------------------------------------------------------------- + The dimensions of the page of an image whose dimensions are + 'imageDim', if we place it on the page with orientation 'orientation'. + + (I.e. swap and X and Y if landscape orientation). + + 'orientation' must not be UNSPECIFIED. +-----------------------------------------------------------------------------*/ + struct Dimensions retval; + + switch (orientation) { + case PORTRAIT: + retval = imageDim; + break; + case LANDSCAPE: + retval.xsize = imageDim.ysize; + retval.ysize = imageDim.xsize; + retval.xres = imageDim.yres; + retval.yres = imageDim.xres; + break; + case UNSPECIFIED: + assert(false); + break; + } + + return retval; +} + + + +static void +executeGhostscript(char const inputFileName[], + struct Box const borderedBox, + struct Dimensions const imageDim, + enum Orientation const orientation, + char const ghostscriptDevice[], + char const outfileArg[], + unsigned int const textalphabits, + enum PostscriptLanguage const language) { + int rc; - int eof; /* End of file on input */ int pipefd[2]; - if (strlen(outfile_arg) > 80) + if (strlen(outfileArg) > 80) pm_error("output file spec too long."); - rc = pipe(pipefd); + rc = pm_pipe(pipefd); if (rc < 0) pm_error("Unable to create pipe to talk to Ghostscript process. " "errno = %d (%s)", errno, strerror(errno)); @@ -768,79 +955,38 @@ executeGhostscript(char const pstrans[], else if (rc == 0) { /* Child process */ close(pipefd[1]); - execGhostscript(pipefd[0], ghostscript_device, outfile_arg, - xsize, ysize, xres, yres, input_filespec, verbose); + execGhostscript(pipefd[0], ghostscriptDevice, outfileArg, + pageDimFromImageDim(imageDim, orientation), + textalphabits); } else { + /* parent process */ pid_t const ghostscriptPid = rc; int const pipeToGhostscriptFd = pipefd[1]; - /* parent process */ - close(pipefd[0]); - gs = fdopen(pipeToGhostscriptFd, "w"); - if (gs == NULL) - pm_error("Unable to open stream on pipe to Ghostscript process."); - - infile = pm_openr(input_filespec); - /* - In encapsulated Postscript, we the encapsulator are supposed to - handle showing the page (which we do by passing a showpage - statement to Ghostscript). Any showpage statement in the - input must be defined to have no effect. - - See "Enscapsulated PostScript Format File Specification", - v. 3.0, 1 May 1992, in particular Example 2, p. 21. I found - it at - http://partners.adobe.com/asn/developer/pdfs/tn/5002.EPSF_Spec.pdf - The example given is a much fancier solution than we need - here, I think, so I boiled it down a bit. JM - */ - if (language == ENCAPSULATED_POSTSCRIPT) - fprintf(gs, "\n/b4_Inc_state save def /showpage { } def\n"); - - if (verbose) - pm_message("Postscript prefix command: '%s'", pstrans); - - fprintf(gs, "%s\n", pstrans); - - /* If our child dies, it closes the pipe and when we next write to it, - we get a SIGPIPE. We must survive that signal in order to report - on the fate of the child. So we ignore SIGPIPE: - */ - signal(SIGPIPE, SIG_IGN); + int gsTermStatus; /* termination status of Ghostscript process */ + pid_t rc; - eof = FALSE; - while (!eof) { - char buffer[4096]; - int bytes_read; - - bytes_read = fread(buffer, 1, sizeof(buffer), infile); - if (bytes_read == 0) - eof = TRUE; - else - fwrite(buffer, 1, bytes_read, gs); - } - pm_close(infile); + close(pipefd[0]); - if (language == ENCAPSULATED_POSTSCRIPT) - fprintf(gs, "\nb4_Inc_state restore showpage\n"); + feedPsToGhostScript(inputFileName, borderedBox, + imageDim, orientation, + pipeToGhostscriptFd, language); - fclose(gs); - - waitpid(ghostscriptPid, &gs_exit, 0); + rc = waitpid(ghostscriptPid, &gsTermStatus, 0); if (rc < 0) pm_error("Wait for Ghostscript process to terminated failed. " "errno = %d (%s)", errno, strerror(errno)); - if (gs_exit != 0) { - if (WIFEXITED(gs_exit)) + if (gsTermStatus != 0) { + if (WIFEXITED(gsTermStatus)) pm_error("Ghostscript failed. Exit code=%d\n", - WEXITSTATUS(gs_exit)); - else if (WIFSIGNALED(gs_exit)) - pm_error("Ghostscript process died due to a signal %d.", - WTERMSIG(gs_exit)); + WEXITSTATUS(gsTermStatus)); + else if (WIFSIGNALED(gsTermStatus)) + pm_error("Ghostscript process died because of a signal %d.", + WTERMSIG(gsTermStatus)); else pm_error("Ghostscript process died with exit code %d", - gs_exit); + gsTermStatus); } } } @@ -850,60 +996,54 @@ executeGhostscript(char const pstrans[], int main(int argc, char ** argv) { - struct cmdlineInfo cmdline; - const char * input_filespec; /* malloc'ed */ + struct CmdlineInfo cmdline; + const char * inputFileName; /* malloc'ed */ /* The file specification of our Postscript input file */ - unsigned int xres, yres; /* Resolution in pixels per inch */ - unsigned int xsize, ysize; /* output image size in pixels */ - struct box extract_box; + struct Dimensions imageDim; + /* Size and resolution of the input image */ + struct Box extractBox; /* coordinates of the box within the input we are to extract; i.e. that will become the output. */ - struct box bordered_box; + struct Box borderedBox; /* Same as above, but expanded to include borders */ - enum postscript_language language; - enum orientation orientation; - const char * ghostscript_device; - const char * outfile_arg; - const char * pstrans; + enum PostscriptLanguage language; + enum Orientation orientation; + const char * ghostscriptDevice; + const char * outfileArg; pnm_init(&argc, argv); parseCommandLine(argc, argv, &cmdline); - addPsToFilespec(cmdline.input_filespec, &input_filespec, cmdline.verbose); + verbose = cmdline.verbose; + + addPsToFileName(cmdline.inputFileName, &inputFileName); - extract_box = computeBoxToExtract(cmdline.extract_box, input_filespec, - cmdline.verbose); + extractBox = computeBoxToExtract(cmdline.extractBox, inputFileName); - language = languageDeclaration(input_filespec, cmdline.verbose); + language = languageDeclaration(inputFileName); - orientation = computeOrientation(cmdline, extract_box); + orientation = computeOrientation(cmdline, extractBox); - bordered_box = addBorders(extract_box, cmdline.xborder, cmdline.yborder, - cmdline.verbose); + borderedBox = addBorders(extractBox, cmdline.xborder, cmdline.yborder); - computeSizeRes(cmdline, orientation, bordered_box, - &xsize, &ysize, &xres, &yres); + computeSizeRes(cmdline, borderedBox, &imageDim); - pstrans = computePstrans(bordered_box, orientation, - xsize, ysize, xres, yres); - - outfile_arg = computeOutfileArg(cmdline); + outfileArg = computeOutfileArg(cmdline); - ghostscript_device = - computeGsDevice(cmdline.format_type, cmdline.forceplain); + ghostscriptDevice = + computeGsDevice(cmdline.formatType, cmdline.forceplain); - pm_message("Writing %s file", ghostscript_device); + pm_message("Writing %s format", ghostscriptDevice); - executeGhostscript(pstrans, ghostscript_device, outfile_arg, - xsize, ysize, xres, yres, input_filespec, - language, cmdline.verbose); + executeGhostscript(inputFileName, borderedBox, imageDim, orientation, + ghostscriptDevice, outfileArg, cmdline.textalphabits, + language); - strfree(ghostscript_device); - strfree(outfile_arg); - strfree(pstrans); + pm_strfree(ghostscriptDevice); + pm_strfree(outfileArg); return 0; } diff --git a/converter/other/rast.c b/converter/other/rast.c index 91c50ccd..1c787089 100644 --- a/converter/other/rast.c +++ b/converter/other/rast.c @@ -269,32 +269,71 @@ pr_dump( p, out, colormap, type, copy_flag ) return 0; } + + int -pr_load_header( in, hP ) - FILE* in; - struct rasterfile* hP; -{ - if ( pm_readbiglong( in, &(hP->ras_magic) ) == -1 ) - return PIX_ERR; - if ( hP->ras_magic != RAS_MAGIC ) - return PIX_ERR; - if ( pm_readbiglong( in, &(hP->ras_width) ) == -1 ) - return PIX_ERR; - if ( pm_readbiglong( in, &(hP->ras_height) ) == -1 ) - return PIX_ERR; - if ( pm_readbiglong( in, &(hP->ras_depth) ) == -1 ) - return PIX_ERR; - if ( pm_readbiglong( in, &(hP->ras_length) ) == -1 ) - return PIX_ERR; - if ( pm_readbiglong( in, &(hP->ras_type) ) == -1 ) - return PIX_ERR; - if ( pm_readbiglong( in, &(hP->ras_maptype) ) == -1 ) - return PIX_ERR; - if ( pm_readbiglong( in, &(hP->ras_maplength) ) == -1 ) - return PIX_ERR; +pr_load_header(FILE * const ifP, struct rasterfile * const headerP) { + + { + long magic; + + pm_readbiglong(ifP, &magic); + if (magic != RAS_MAGIC) + pm_error("Wrong magic number for a RAST file"); + } + { + long width; + pm_readbiglong(ifP, &width); + + if (width < 0) + pm_error("Negative width in RAST header"); + else + headerP->ras_width = width; + } + { + long height; + pm_readbiglong(ifP, &height); + + if (height < 0) + pm_error("Negative height in RAST header"); + else + headerP->ras_height = height; + } + { + long depth; + pm_readbiglong(ifP, &depth); + + if (depth < 0) + pm_error("Negative depth in RAST header"); + else + headerP->ras_depth = depth; + } + { + long length; + pm_readbiglong(ifP, &length); + + if (length < 0) + pm_error("Negative length in RAST header"); + else + headerP->ras_length = length; + } + pm_readbiglong(ifP, &headerP->ras_type); + + pm_readbiglong(ifP, &headerP->ras_maptype); + { + long mapLength; + pm_readbiglong(ifP, &mapLength); + + if (mapLength < 0) + pm_error("Negative map length in RAST header"); + else + headerP->ras_maplength = mapLength; + } return 0; } + + int pr_load_colormap( in, hP, colormap ) FILE* in; diff --git a/converter/other/rast.h b/converter/other/rast.h index e79896ea..eb6f4ec4 100644 --- a/converter/other/rast.h +++ b/converter/other/rast.h @@ -49,7 +49,7 @@ struct rasterfile { #define RMT_EQUAL_RGB 1 #define RMT_RAW 2 long ras_maplength; - }; +}; struct pixrectops { int (*pro_rop)(); @@ -65,21 +65,22 @@ struct pixrectops { int (*pro_getcolormap)(); int (*pro_putattributes)(); int (*pro_getattributes)(); - }; +}; struct pr_size { int x, y; - }; +}; + struct pr_pos { int x, y; - }; +}; struct pixrect { struct pixrectops* pr_ops; struct pr_size pr_size; int pr_depth; struct mpr_data* pr_data; /* work-alike only handles memory pixrects */ - }; +}; struct mpr_data { int md_linebytes; @@ -87,13 +88,13 @@ struct mpr_data { struct pr_pos md_offset; short md_primary; short md_flags; - }; +}; typedef struct { int type; int length; unsigned char* map[3]; - } colormap_t; +} colormap_t; /* And the routine definitions. */ diff --git a/converter/other/rasttopnm.c b/converter/other/rasttopnm.c index aa55850b..285fc5e0 100644 --- a/converter/other/rasttopnm.c +++ b/converter/other/rasttopnm.c @@ -10,254 +10,489 @@ ** implied warranty. */ +#include "pm_c_util.h" +#include "mallocvar.h" +#include "shhopt.h" #include "pnm.h" #include "rast.h" -int -main( argc, argv ) - int argc; - char* argv[]; - { - FILE* ifp; - struct rasterfile header; - colormap_t pr_colormap; - int grayscale; - struct pixrect* pr; - xel* xelrow; - register xel* xP; - int argn, rows, cols, format, depth, i, row, mask; - register int col; - xelval maxval; - xel zero, one; - int linesize; - unsigned char* data; - unsigned char* byteP; - pnm_init( &argc, argv ); - argn = 1; +struct cmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + const char * inputFileName; + unsigned int index; + unsigned int dumpheader; + unsigned int dumpcolormap; +}; + + + +static void +parseCommandLine(int argc, const char ** argv, + struct cmdlineInfo * const cmdlineP) { +/*---------------------------------------------------------------------------- + Note that the file spec array we return is stored in the storage that + was passed to us as the argv array. +-----------------------------------------------------------------------------*/ + optEntry * option_def; + /* Instructions to OptParseOptions2 on how to parse our options. + */ + optStruct3 opt; + + unsigned int option_def_index; - if ( argn != argc ) - { - ifp = pm_openr( argv[argn] ); - ++argn; - } + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENT3 */ + + opt.opt_table = option_def; + opt.short_allowed = false; /* We have no short (old-fashioned) options */ + opt.allowNegNum = false; /* We have no parms that are negative numbers */ + + OPTENT3(0, "index", OPT_FLAG, NULL, + &cmdlineP->index, 0); + OPTENT3(0, "dumpheader", OPT_FLAG, NULL, + &cmdlineP->dumpheader, 0); + OPTENT3(0, "dumpcolormap", OPT_FLAG, NULL, + &cmdlineP->dumpcolormap, 0); + + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + if (argc-1 == 0) + cmdlineP->inputFileName = "-"; + else if (argc-1 != 1) + pm_error("Program takes zero or one argument (filename). You " + "specified %d", argc-1); else - ifp = stdin; - - if ( argn != argc ) - pm_usage( "[rastfile]" ); - - /* Read in the rasterfile. First the header. */ - if ( pr_load_header( ifp, &header ) != 0 ) - pm_error( "unable to read in rasterfile header" ); - - cols = header.ras_width; - rows = header.ras_height; - depth = header.ras_depth; - - if ( cols <= 0 ) - pm_error( "invalid cols: %d", cols ); - if ( rows <= 0 ) - pm_error( "invalid rows: %d", rows ); - - /* If there is a color map, read it. */ - grayscale = 1; - if ( header.ras_maplength != 0 ) - { - if ( pr_load_colormap( ifp, &header, &pr_colormap ) != 0 ) - pm_error( "unable to skip colormap data" ); - for ( i = 0; i < header.ras_maplength / 3; ++i ) - if ( pr_colormap.map[0][i] != pr_colormap.map[1][i] || - pr_colormap.map[1][i] != pr_colormap.map[2][i] ) - { - grayscale = 0; - break; - } - } - - /* Check the depth and color map. */ - switch ( depth ) - { - case 1: - if ( header.ras_maptype == RMT_NONE && header.ras_maplength == 0 ) - { - maxval = 1; - format = PBM_TYPE; - PNM_ASSIGN1( zero, maxval ); - PNM_ASSIGN1( one, 0 ); - } - else if ( header.ras_maptype == RMT_EQUAL_RGB && - header.ras_maplength == 6 ) - { - if ( grayscale ) - { - maxval = 255; - format = PGM_TYPE; - PNM_ASSIGN1( zero, pr_colormap.map[0][0] ); - PNM_ASSIGN1( one, pr_colormap.map[0][1] ); - } - else - { - maxval = 255; - format = PPM_TYPE; - PPM_ASSIGN( - zero, pr_colormap.map[0][0], pr_colormap.map[1][0], - pr_colormap.map[2][0] ); - PPM_ASSIGN( - one, pr_colormap.map[0][1], pr_colormap.map[1][1], - pr_colormap.map[2][1] ); - } - } - else - pm_error( - "this depth-1 rasterfile has a non-standard colormap - " - "type %ld length %ld", - header.ras_maptype, header.ras_maplength ); - break; - - case 8: - if ( grayscale ) - { - maxval = 255; - format = PGM_TYPE; - } - else if ( header.ras_maptype == RMT_EQUAL_RGB ) - { - maxval = 255; - format = PPM_TYPE; - } - else - pm_error( - "this depth-8 rasterfile has a non-standard colormap - " - "type %ld length %ld", - header.ras_maptype, header.ras_maplength ); - break; - - case 24: - case 32: - if ( header.ras_maptype == RMT_NONE && header.ras_maplength == 0 ) - ; - else if ( header.ras_maptype == RMT_RAW || header.ras_maplength == 768 ) - ; - else - pm_error( - "this depth-%d rasterfile has a non-standard colormap - " - "type %ld length %ld", - depth, header.ras_maptype, header.ras_maplength ); - maxval = 255; - format = PPM_TYPE; - break; - - default: - pm_error( - "invalid depth: %d. Can only handle depth 1, 8, 24, or 32.", - depth ); - } - - /* Now load the data. The pixrect returned is a memory pixrect. */ - if ( ( pr = pr_load_image( ifp, &header, NULL ) ) == NULL ) - pm_error( - "unable to read in the image from the rasterfile" ); - - linesize = ( (struct mpr_data*) pr->pr_data )->md_linebytes; - data = ( (struct mpr_data*) pr->pr_data )->md_image; - - pm_close( ifp ); - - /* Now write out the anymap. */ - pnm_writepnminit( stdout, cols, rows, maxval, format, 0 ); - xelrow = pnm_allocrow( cols ); - switch ( PNM_FORMAT_TYPE(format) ) - { - case PBM_TYPE: - pm_message( "writing PBM file" ); + cmdlineP->inputFileName = argv[1]; +} + + + +static bool +colorMapIsGrayscale(colormap_t const colorMap) { +/*---------------------------------------------------------------------------- + The color map contains only gray. +-----------------------------------------------------------------------------*/ + unsigned int i; + bool grayscale; + + for (i = 0, grayscale = true; i < colorMap.length; ++i) { + if (colorMap.map[0][i] != colorMap.map[1][i] || + colorMap.map[1][i] != colorMap.map[2][i]) { + grayscale = false; + } + } + return grayscale; +} + + + +static void +analyzeImage(struct rasterfile const header, + colormap_t const colorMap, + int * const formatP, + xelval * const maxvalP, + bool * const grayscaleP, + xel * const zeroP, + xel * const oneP) { + + bool const grayscale = + header.ras_maplength == 0 || colorMapIsGrayscale(colorMap); + + *grayscaleP = grayscale; + + switch (header.ras_depth) { + case 1: + if (header.ras_maptype == RMT_NONE && header.ras_maplength == 0) { + *maxvalP = 1; + *formatP = PBM_TYPE; + PNM_ASSIGN1(*zeroP, 1); + PNM_ASSIGN1(*oneP, 0); + } else if (header.ras_maptype == RMT_EQUAL_RGB && + header.ras_maplength == 6) { + if (grayscale) { + *maxvalP = 255; + *formatP = PGM_TYPE; + PNM_ASSIGN1(*zeroP, colorMap.map[0][0]); + PNM_ASSIGN1(*oneP, colorMap.map[0][1]); + } else { + *maxvalP = 255; + *formatP = PPM_TYPE; + PPM_ASSIGN( + *zeroP, colorMap.map[0][0], colorMap.map[1][0], + colorMap.map[2][0]); + PPM_ASSIGN( + *oneP, colorMap.map[0][1], colorMap.map[1][1], + colorMap.map[2][1]); + } + } else + pm_error( + "this depth-1 rasterfile has a non-standard colormap - " + "type %ld length %ld", + header.ras_maptype, header.ras_maplength); + break; + + case 8: + if (grayscale) { + *maxvalP = 255; + *formatP = PGM_TYPE; + } else if (header.ras_maptype == RMT_EQUAL_RGB) { + *maxvalP = 255; + *formatP = PPM_TYPE; + } else + pm_error( + "this depth-8 rasterfile has a non-standard colormap - " + "type %ld length %ld", + header.ras_maptype, header.ras_maplength); break; - case PGM_TYPE: - pm_message( "writing PGM file" ); + case 24: + case 32: + if (header.ras_maptype == RMT_NONE && header.ras_maplength == 0); + else if (header.ras_maptype == RMT_RAW || header.ras_maplength == 768); + else + pm_error( + "this depth-%ld rasterfile has a non-standard colormap - " + "type %ld length %ld", + header.ras_depth, header.ras_maptype, header.ras_maplength); + *maxvalP = 255; + *formatP = PPM_TYPE; break; - case PPM_TYPE: - pm_message( "writing PPM file" ); + default: + pm_error("invalid depth: %ld. Can handle only depth 1, 8, 24, or 32.", + header.ras_depth); + } +} + + + +static void +reportOutputType(int const format) { + + switch (PNM_FORMAT_TYPE(format)) { + case PBM_TYPE: + pm_message("writing PBM file"); + break; + case PGM_TYPE: + pm_message("writing PGM file"); + break; + case PPM_TYPE: + pm_message("writing PPM file"); break; + default: + abort(); + } +} + + + +static void +convertRowDepth1(const unsigned char * const rastLine, + unsigned int const cols, + xel const zeroXel, + xel const oneXel, + xel * const xelrow) { + + const unsigned char * byteP; + unsigned int col; + unsigned char mask; + + byteP = rastLine; /* initial value */ + + for (col = 0, mask = 0x80; col < cols; ++col) { + if (mask == 0x00) { + ++byteP; + mask = 0x80; + } + xelrow[col] = (*byteP & mask) ? oneXel : zeroXel; + mask = mask >> 1; + } +} + + + +static void +convertRowDepth8(const unsigned char * const lineStart, + unsigned int const cols, + bool const colorMapped, + bool const useIndexForColor, + bool const grayscale, + colormap_t const colorMap, + xel * const xelrow) { +/*---------------------------------------------------------------------------- + Convert a line of raster data from the RAST input to a row of raster + data for the PNM output. + + 'lineStart' is where the RAST row starts. 'xelrow' is where to put the + PNM row. 'cols' is the number of pixels in the row. + + 'colorMapped' means the RAST image is colormapped. If so, 'colorMap' + is the color map from the RAST file and 'useIndexForColor' means not + to use that map but instead to create a PGM row of the colormap + _indices_. + + 'grayscale' means it is a grayscale image; the output is PGM. +-----------------------------------------------------------------------------*/ + const unsigned char * byteP; + unsigned int col; + + byteP = lineStart; /* initial value */ + + for (col = 0; col < cols; ++col) { + if (colorMapped && !useIndexForColor) { + if (grayscale) + PNM_ASSIGN1(xelrow[col], colorMap.map[0][*byteP]); + else + PPM_ASSIGN(xelrow[col], + colorMap.map[0][*byteP], + colorMap.map[1][*byteP], + colorMap.map[2][*byteP]); + } else + PNM_ASSIGN1(xelrow[col], *byteP); + + ++byteP; + } +} + + + +static void +convertRowRgb(const unsigned char * const lineStart, + unsigned int const cols, + unsigned int const depth, + long const rastType, + bool const colorMapped, + bool const useIndexForColor, + colormap_t const colorMap, + xel * const xelrow) { + + const unsigned char * byteP; + unsigned int col; + + byteP = lineStart; /* initial value */ + + for (col = 0; col < cols; ++col) { + xelval r, g, b; + if (depth == 32) + ++byteP; + if (rastType == RT_FORMAT_RGB) { + r = *byteP++; + g = *byteP++; + b = *byteP++; + } else { + b = *byteP++; + g = *byteP++; + r = *byteP++; + } + if (colorMapped && !useIndexForColor) + PPM_ASSIGN(xelrow[col], + colorMap.map[0][r], + colorMap.map[1][g], + colorMap.map[2][b]); + else + PPM_ASSIGN(xelrow[col], r, g, b); + } +} + + + +static void +writePnm(FILE * const ofP, + const struct pixrect * const pixRectP, + unsigned int const cols, + unsigned int const rows, + xelval const maxval, + int const format, + unsigned int const depth, + long const rastType, + bool const grayscale, + bool const colorMapped, + colormap_t const colorMap, + xel const zeroXel, + xel const oneXel, + bool const useIndexForColor) { + + struct mpr_data const mprData = *pixRectP->pr_data; + + xel * xelrow; + unsigned int row; + unsigned char * lineStart; + + pnm_writepnminit(ofP, cols, rows, maxval, format, 0); + + xelrow = pnm_allocrow(cols); + + reportOutputType(format); + + for (row = 0, lineStart = mprData.md_image; + row < rows; + ++row, lineStart += mprData.md_linebytes) { + + switch (depth) { + case 1: + convertRowDepth1(lineStart, cols, zeroXel, oneXel, xelrow); + break; + case 8: + convertRowDepth8(lineStart, cols, colorMapped, useIndexForColor, + grayscale, colorMap, xelrow); + break; + case 24: + case 32: + convertRowRgb(lineStart, cols, depth, rastType, colorMapped, + useIndexForColor, colorMap, xelrow); + break; default: - pm_error( "shouldn't happen" ); + pm_error("Invalid depth value: %u", depth); } + pnm_writepnmrow(ofP, xelrow, cols, maxval, format, 0); + } +} + + + +static void +dumpHeader(struct rasterfile const header) { + + const char * typeName; + + switch (header.ras_type) { + case RT_OLD: typeName = "old"; break; + case RT_STANDARD: typeName = "standard"; break; + case RT_BYTE_ENCODED: typeName = "byte encoded"; break; + case RT_FORMAT_RGB: typeName = "format rgb"; break; + case RT_FORMAT_TIFF: typeName = "format_tiff"; break; + case RT_FORMAT_IFF: typeName = "format_iff"; break; + case RT_EXPERIMENTAL: typeName = "experimental"; break; + default: typeName = "???"; + } + + pm_message("type: %s (%lu)", typeName, (unsigned long)header.ras_type); + pm_message("%luw x %lul x %lud", + (unsigned long)header.ras_width, + (unsigned long)header.ras_height, + (unsigned long)header.ras_depth); + pm_message("raster length: %lu", (unsigned long)header.ras_length); + + if (header.ras_maplength) + pm_message("Has color map"); +} + + + +static void +dumpHeaderAnalysis(bool const grayscale, + unsigned int const depth, + xel const zero, + xel const one) { + + pm_message("grayscale: %s", grayscale ? "YES" : "NO"); + + if (depth == 1) { + pm_message("Zero color: (%u,%u,%u)", + PNM_GETR(zero), + PNM_GETG(zero), + PNM_GETB(zero)); + + pm_message("One color: (%u,%u,%u)", + PNM_GETR(one), + PNM_GETG(one), + PNM_GETB(one)); + } +} + - for ( row = 0; row < rows; ++row ) - { - byteP = data; - switch ( depth ) - { - case 1: - mask = 0x80; - for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) - { - if ( mask == 0 ) - { - ++byteP; - mask = 0x80; - } - *xP = ( *byteP & mask ) ? one : zero; - mask = mask >> 1; - } - break; - - case 8: - for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) - { - if ( header.ras_maplength == 0 ) - PNM_ASSIGN1( *xP, *byteP ); - else if ( grayscale ) - PNM_ASSIGN1( *xP, pr_colormap.map[0][*byteP] ); - else - PPM_ASSIGN( - *xP, pr_colormap.map[0][*byteP], - pr_colormap.map[1][*byteP], - pr_colormap.map[2][*byteP] ); - ++byteP; - } - break; - - case 24: - case 32: - for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) - { - register xelval r, g, b; - - if ( depth == 32 ) - ++byteP; - if ( header.ras_type == RT_FORMAT_RGB ) - { - r = *byteP++; - g = *byteP++; - b = *byteP++; - } - else - { - b = *byteP++; - g = *byteP++; - r = *byteP++; - } - if ( header.ras_maplength == 0 ) - PPM_ASSIGN( *xP, r, g, b ); - else - PPM_ASSIGN( - *xP, pr_colormap.map[0][r], pr_colormap.map[1][g], - pr_colormap.map[2][b] ); - } - break; - - default: - pm_error( "can't happen" ); - } - data += linesize; - pnm_writepnmrow( stdout, xelrow, cols, maxval, format, 0 ); - } - - pm_close( stdout ); - - exit( 0 ); + +static void +dumpColorMap(colormap_t const colorMap) { + + unsigned int i; + const char * typeName; + + switch (colorMap.type) { + case RMT_NONE: typeName = "NONE"; break; + case RMT_EQUAL_RGB: typeName = "EQUAL_RGB"; break; + case RMT_RAW: typeName = "RAW"; break; + default: typeName = "???"; } + + pm_message("color map type = %s (%u)", typeName, colorMap.type); + + pm_message("color map size = %u", colorMap.length); + + for (i = 0; i < colorMap.length; ++i) + pm_message("color %u: (%u, %u, %u)", i, + (unsigned char)colorMap.map[0][i], + (unsigned char)colorMap.map[1][i], + (unsigned char)colorMap.map[2][i]); +} + + + +int +main(int argc, const char ** const argv) { + + struct cmdlineInfo cmdline; + FILE * ifP; + struct rasterfile header; + colormap_t colorMap; + bool grayscale; + struct pixrect * pr; + int format; + xelval maxval; + xel zero, one; + int rc; + + pm_proginit(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + ifP = pm_openr(cmdline.inputFileName); + + rc = pr_load_header(ifP, &header); + if (rc != 0 ) + pm_error("unable to read in rasterfile header"); + + if (cmdline.dumpheader) + dumpHeader(header); + + if (header.ras_maplength != 0) { + int rc; + + rc = pr_load_colormap(ifP, &header, &colorMap); + + if (rc != 0 ) + pm_error("unable to read colormap from RAST file"); + + if (cmdline.dumpcolormap) + dumpColorMap(colorMap); + } + + analyzeImage(header, colorMap, &format, &maxval, &grayscale, &zero, &one); + + if (cmdline.dumpheader) + dumpHeaderAnalysis(grayscale, header.ras_depth, zero, one); + + pr = pr_load_image(ifP, &header, NULL); + if (pr == NULL ) + pm_error("unable to read in the image from the rasterfile" ); + + if (cmdline.index && header.ras_maplength == 0) + pm_error("You requested to use color map indices as colors (-index), " + "but this is not a color mapped image"); + + writePnm(stdout, pr, header.ras_width, header.ras_height, maxval, format, + header.ras_depth, header.ras_type, grayscale, + header.ras_maplength > 0, colorMap, zero, one, cmdline.index); + + pm_close(ifP); + pm_close(stdout); + + return 0; +} diff --git a/converter/other/rletopnm.c b/converter/other/rletopnm.c index 83ada51b..99959141 100644 --- a/converter/other/rletopnm.c +++ b/converter/other/rletopnm.c @@ -61,19 +61,19 @@ /* * Utah type declarations. */ -rle_hdr hdr; -rle_map *colormap; +static rle_hdr hdr; +static rle_map * colormap; -struct cmdlineInfo { +struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ - char *input_filename; + char * inputFilename; unsigned int headerdump; unsigned int verbose; - char *alpha_filename; - bool alpha_stdout; + char * alphaout; + bool alphaStdout; }; @@ -81,15 +81,14 @@ struct cmdlineInfo { /* * Other declarations. */ -int visual, maplen; -int width, height; - +static int visual, maplen; +static int width, height; static void parseCommandLine(int argc, char ** argv, - struct cmdlineInfo * const cmdlineP) { + struct CmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- Note that many of the strings that this function returns in the *cmdlineP structure are actually in the supplied argv array. And @@ -110,34 +109,34 @@ parseCommandLine(int argc, char ** argv, OPTENT3('v', "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); OPTENT3(0, "alphaout", OPT_STRING, - &cmdlineP->alpha_filename, &alphaoutSpec, 0); + &cmdlineP->alphaout, &alphaoutSpec, 0); opt.opt_table = option_def; opt.short_allowed = TRUE; /* We have short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and all of *cmdlineP. */ if (!alphaoutSpec) - cmdlineP->alpha_filename = NULL; + cmdlineP->alphaout = NULL; if (argc - 1 == 0) - cmdlineP->input_filename = NULL; /* he wants stdin */ + cmdlineP->inputFilename = NULL; /* he wants stdin */ else if (argc - 1 == 1) { if (streq(argv[1], "-")) - cmdlineP->input_filename = NULL; /* he wants stdin */ + cmdlineP->inputFilename = NULL; /* he wants stdin */ else - cmdlineP->input_filename = strdup(argv[1]); + cmdlineP->inputFilename = strdup(argv[1]); } else pm_error("Too many arguments. The only argument accepted " "is the input file specification"); - if (cmdlineP->alpha_filename && - streq(cmdlineP->alpha_filename, "-")) - cmdlineP->alpha_stdout = TRUE; + if (cmdlineP->alphaout && + streq(cmdlineP->alphaout, "-")) + cmdlineP->alphaStdout = TRUE; else - cmdlineP->alpha_stdout = FALSE; + cmdlineP->alphaStdout = FALSE; } @@ -167,15 +166,14 @@ reportRleGetSetupError(int const rleGetSetupRc) { } -/*----------------------------------------------------------------------------- - * Read the rle header. - */ + static void -read_rle_header(FILE * const ifp, - bool const headerDump) { +readRleHeader(FILE * const ifP, + bool const headerDump) { + int rc; int i; - hdr.rle_file = ifp; + hdr.rle_file = ifP; rc = rle_get_setup(&hdr); if (rc != 0) reportRleGetSetupError(rc); @@ -254,12 +252,12 @@ read_rle_header(FILE * const ifp, for (i = 0; hdr.comments[i] != NULL; i++) HMSG("%s", hdr.comments[i]); } -/*----------------------------------------------------------------------------- - * Write the ppm image data. - */ + + + static void -write_ppm_data(FILE * const imageout_file, - FILE * const alpha_file) { +writePpmRaster(FILE * const imageoutFileP, + FILE * const alphaFileP) { rle_pixel ***scanlines, **scanline; pixval r, g, b; @@ -341,17 +339,17 @@ write_ppm_data(FILE * const imageout_file, /* * Write the scan line. */ - if (imageout_file ) - ppm_writeppmrow(imageout_file, pixelrow, width, RLE_MAXVAL, 0); - if (alpha_file) - pgm_writepgmrow(alpha_file, alpharow, width, RLE_MAXVAL, 0); + if (imageoutFileP) + ppm_writeppmrow(imageoutFileP, pixelrow, width, RLE_MAXVAL, 0); + if (alphaFileP) + pgm_writepgmrow(alphaFileP, alpharow, width, RLE_MAXVAL, 0); } /* end of for scan = 0 to height */ /* Free scanline memory. */ - for ( scan = 0; scan < height; scan++ ) - rle_row_free( &hdr, scanlines[scan] ); - free( scanlines ); + for (scan = 0; scan < height; ++scan) + rle_row_free(&hdr, scanlines[scan]); + free (scanlines); ppm_freerow(pixelrow); pgm_freerow(alpharow); } @@ -359,8 +357,8 @@ write_ppm_data(FILE * const imageout_file, static void -write_pgm_data(FILE * const imageout_file, - FILE * const alpha_file) { +writePgmRaster(FILE * const imageoutFileP, + FILE * const alphaFileP) { /*---------------------------------------------------------------------------- Write the PGM image data -----------------------------------------------------------------------------*/ @@ -397,10 +395,10 @@ write_pgm_data(FILE * const imageout_file, else alpharow[x] = 0; } - if (imageout_file) - pgm_writepgmrow(imageout_file, pixelrow, width, RLE_MAXVAL, 0); - if (alpha_file) - pgm_writepgmrow(alpha_file, alpharow, width, RLE_MAXVAL, 0); + if (imageoutFileP) + pgm_writepgmrow(imageoutFileP, pixelrow, width, RLE_MAXVAL, 0); + if (alphaFileP) + pgm_writepgmrow(alphaFileP, alpharow, width, RLE_MAXVAL, 0); } /* end of for scan = 0 to height */ @@ -414,59 +412,59 @@ write_pgm_data(FILE * const imageout_file, -/*----------------------------------------------------------------------------- - * Convert a Utah rle file to a pbmplus pnm file. - */ int main(int argc, char ** argv) { - struct cmdlineInfo cmdline; - FILE *ifp; - FILE *imageout_file, *alpha_file; - char *fname = NULL; + struct CmdlineInfo cmdline; + FILE * ifP; + FILE * imageoutFileP; + FILE * alphaFileP; + char * fname; pnm_init( &argc, argv ); parseCommandLine(argc, argv, &cmdline); - if ( cmdline.input_filename != NULL ) - ifp = pm_openr( cmdline.input_filename ); + fname = NULL; /* initial value */ + + if (cmdline.inputFilename != NULL ) + ifP = pm_openr(cmdline.inputFilename); else - ifp = stdin; + ifP = stdin; - if (cmdline.alpha_stdout) - alpha_file = stdout; - else if (cmdline.alpha_filename == NULL) - alpha_file = NULL; + if (cmdline.alphaStdout) + alphaFileP = stdout; + else if (cmdline.alphaout == NULL) + alphaFileP = NULL; else { - alpha_file = pm_openw(cmdline.alpha_filename); + alphaFileP = pm_openw(cmdline.alphaout); } - if (cmdline.alpha_stdout) - imageout_file = NULL; + if (cmdline.alphaStdout) + imageoutFileP = NULL; else - imageout_file = stdout; + imageoutFileP = stdout; /* * Open the file. */ /* Initialize header. */ - hdr = *rle_hdr_init( (rle_hdr *)NULL ); - rle_names( &hdr, cmd_name( argv ), fname, 0 ); + hdr = *rle_hdr_init(NULL); + rle_names(&hdr, cmd_name( argv ), fname, 0); /* * Read the rle file header. */ - read_rle_header(ifp, cmdline.headerdump || cmdline.verbose); + readRleHeader(ifP, cmdline.headerdump || cmdline.verbose); if (cmdline.headerdump) exit(0); /* * Write the alpha file header */ - if (alpha_file) - pgm_writepgminit(alpha_file, width, height, RLE_MAXVAL, 0); + if (alphaFileP) + pgm_writepgminit(alphaFileP, width, height, RLE_MAXVAL, 0); /* * Write the pnm file header. @@ -475,24 +473,24 @@ main(int argc, char ** argv) { case GRAYSCALE: /* 8 bits without colormap -> pgm */ if (cmdline.verbose) pm_message("Writing pgm file."); - if (imageout_file) - pgm_writepgminit(imageout_file, width, height, RLE_MAXVAL, 0); - write_pgm_data(imageout_file, alpha_file); + if (imageoutFileP) + pgm_writepgminit(imageoutFileP, width, height, RLE_MAXVAL, 0); + writePgmRaster(imageoutFileP, alphaFileP); break; default: /* anything else -> ppm */ if (cmdline.verbose) pm_message("Writing ppm file."); - if (imageout_file) - ppm_writeppminit(imageout_file, width, height, RLE_MAXVAL, 0); - write_ppm_data(imageout_file, alpha_file); + if (imageoutFileP) + ppm_writeppminit(imageoutFileP, width, height, RLE_MAXVAL, 0); + writePpmRaster(imageoutFileP, alphaFileP); break; } - pm_close(ifp); - if (imageout_file) - pm_close( imageout_file ); - if (alpha_file) - pm_close( alpha_file ); + pm_close(ifP); + if (imageoutFileP) + pm_close(imageoutFileP); + if (alphaFileP) + pm_close(alphaFileP); return 0; } diff --git a/converter/other/sgi.h b/converter/other/sgi.h index 3700d356..2f57f52d 100644 --- a/converter/other/sgi.h +++ b/converter/other/sgi.h @@ -5,7 +5,7 @@ typedef struct { short magic; - char storage; + unsigned char storage; char bpc; /* pixel size: 1 = bytes, 2 = shorts */ unsigned short dimension; /* 1 = single row, 2 = B/W, 3 = RGB */ unsigned short xsize, /* width in pixels */ @@ -25,9 +25,9 @@ typedef struct { #define STORAGE_RLE 1 #define CMAP_NORMAL 0 -#define CMAP_DITHERED 1 /* not supported */ -#define CMAP_SCREEN 2 /* not supported */ -#define CMAP_COLORMAP 3 /* not supported */ +#define CMAP_DITHERED 1 /* can't handle this */ +#define CMAP_SCREEN 2 /* can't handle this */ +#define CMAP_COLORMAP 3 /* can't handle this */ #endif diff --git a/converter/other/sgitopnm.c b/converter/other/sgitopnm.c index 0d26bb9c..6fd4efcf 100644 --- a/converter/other/sgitopnm.c +++ b/converter/other/sgitopnm.c @@ -5,6 +5,11 @@ ** Based on the SGI image description v0.9 by Paul Haeberli (paul@sgi.comp) ** Available via ftp from sgi.com:graphics/SGIIMAGESPEC ** +** The definitive document describing the SGI image file format, +** SGI Image File Format Version 1.00 is available from +** ftp://ftp.sgi.com/graphics/grafica/sgiimage.html +** +** ** Permission to use, copy, modify, and distribute this software and its ** documentation for any purpose and without fee is hereby granted, provided ** that the above copyright notice appear in all copies and that both that @@ -12,314 +17,451 @@ ** documentation. This software is provided "as is" without express or ** implied warranty. ** -** 29Jan94: first version -** 08Feb94: minor bugfix -** 29Jul00: added -channel option (smar@reptiles.org) */ + + +#include +#include +#include "pm_c_util.h" +#include "mallocvar.h" +#include "shhopt.h" #include "pnm.h" #include "sgi.h" -#include "mallocvar.h" -#ifndef VMS -#include -#endif -/*#define DEBUG*/ +#define MAX_ZSIZE 256 -#ifndef SEEK_SET -#define SEEK_SET 0 -#endif +struct CmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + const char * inputFileName; /* '-' if stdin */ + unsigned int verbose; + unsigned int channelSpec; + unsigned int channel; +}; -/* entry in RLE offset table */ -typedef struct { - long start; /* offset in file */ - long length; /* length of compressed scanline */ -} TabEntry; -typedef short ScanElem; -typedef ScanElem * ScanLine; - -/* prototypes */ -static unsigned char get_byte ARGS(( FILE* f )); -static long get_big_long ARGS((FILE *f)); -static short get_big_short ARGS((FILE *f)); -static short get_byte_as_short ARGS((FILE *f)); -static void readerr ARGS((FILE *f)); -static const char * -compression_name(char compr); -static void read_bytes ARGS((FILE *ifp, int n, char *buf)); -static Header * read_header ARGS((FILE *ifp, int channel)); -static TabEntry * read_table ARGS((FILE *ifp, int tablen)); -static ScanLine * read_channels ARGS((FILE *ifp, Header *head, TabEntry *table, short (*func) ARGS((FILE *)), int ochan )); -static void image_to_pnm ARGS((Header *head, ScanLine *image, xelval maxval, int channel)); -static void rle_decompress ARGS((ScanElem *src, int srclen, ScanElem *dest, int destlen)); -#define WORSTCOMPR(x) (2*(x) + 2) +static void +parseCommandLine(int argc, const char ** argv, + struct CmdlineInfo * const cmdlineP) { +/*---------------------------------------------------------------------------- + parse program command line described in Unix standard form by argc + and argv. Return the information in the options as *cmdlineP. + + If command line is internally inconsistent (invalid options, etc.), + issue error message to stderr and abort program. + + Note that the strings we return are stored in the storage that + was passed to us as the argv array. We also trash *argv. +-----------------------------------------------------------------------------*/ + optEntry * option_def; + /* Instructions to pm_optParseOptions3 on how to parse our options. + */ + optStruct3 opt; + + unsigned int option_def_index; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENT3 */ + OPTENT3(0, "channel", OPT_UINT, + &cmdlineP->channel, + &cmdlineP->channelSpec, 0); + OPTENT3(0, "verbose", OPT_FLAG, NULL, + &cmdlineP->verbose, 0); + OPTENT3(0, "noverbose", OPT_FLAG, NULL, + NULL, 0); /* backward compatibility */ + + opt.opt_table = option_def; + opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ + opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ + + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + free(option_def); + + if (!cmdlineP->channelSpec) + cmdlineP->channel = MAX_ZSIZE + 1; + /* Invalid value; to suppress Valgrind error */ + + if (argc-1 < 1) + cmdlineP->inputFileName = "-"; + else if (argc-1 == 1) + cmdlineP->inputFileName = argv[1]; + else + pm_error("Program takes at most one argument: input file name"); +} -static short verbose = 0; +/* basic I/O functions, taken from ilbmtoppm.c */ -int -main(argc, argv) - int argc; - char *argv[]; -{ - FILE *ifp; - int argn; - const char * const usage = "[-verbose] [-channel n] [sgifile]"; - TabEntry *table = NULL; - ScanLine *image; - Header *head; - pixval maxval; - int channel = -1; - - pnm_init(&argc, argv); - - argn = 1; - while( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) { - if( pm_keymatch(argv[argn], "-verbose", 2) ) - verbose++; - else - if( pm_keymatch(argv[argn], "-noverbose", 4) ) - verbose = 0; - else - if( pm_keymatch(argv[argn], "-channel", 2) ) { - char *s; - - ++argn; - if( argn >= argc ) - pm_usage(usage); - - s = argv[argn]; - channel = strtol(argv[argn], &s, 10); - if( s == argv[argn] || channel < 0) - pm_usage(usage); - } - else - pm_usage(usage); - ++argn; - } +static void +readerr(FILE * const f) { - if( argn < argc ) { - ifp = pm_openr( argv[argn] ); - argn++; - } + if (ferror(f)) + pm_error("read error"); else - ifp = stdin; + pm_error("premature EOF"); +} - if( argn != argc ) - pm_usage(usage); - head = read_header(ifp, channel); - maxval = head->pixmax - head->pixmin; - if( maxval > PNM_OVERALLMAXVAL ) - pm_error("Maximum sample value in input image (%d) is too large. " - "This program's limit is %d.", - maxval, PNM_OVERALLMAXVAL); - if (channel >= head->zsize) - pm_error("channel out of range - only %d channels in image", - head->zsize); - if( head->storage != STORAGE_VERBATIM ) - table = read_table(ifp, head->ysize * head->zsize); - if( head->bpc == 1 ) - image = read_channels(ifp, head, table, get_byte_as_short, channel); - else - image = read_channels(ifp, head, table, get_big_short, channel); - image_to_pnm(head, image, (xelval)maxval, channel); - pm_close(ifp); +static short +getBigShort(FILE * const ifP) { + + short s; + + if (pm_readbigshort(ifP, &s) == -1) + readerr(ifP); + + return s; +} + + + +static long +getBigLong(FILE * const ifP) { + + long l; + + if (pm_readbiglong(ifP, &l) == -1) + readerr(ifP); - exit(0); + return l; } + +static unsigned char +getByte(FILE * const ifP) { + + int i; + + i = getc(ifP); + if (i == EOF) + readerr(ifP); + + return (unsigned char) i; +} + + + +static void +readBytes(FILE * const ifP, + int const n, + char * const buf) { + + int r; + + r = fread((void *)buf, 1, n, ifP); + + if (r != n) + readerr(ifP); +} + + + +static short +getByteAsShort(FILE * const ifP) { + + return (short)getByte(ifP); +} + + + +static const char * +compressionName(unsigned char const storageCode) { + + switch (storageCode) { + case STORAGE_VERBATIM: + return "none"; + case STORAGE_RLE: + return "RLE"; + default: + return "unknown"; + } +} + + + +/* entry in RLE offset table */ +typedef struct { + long start; /* offset in file */ + long length; /* length of compressed scanline */ +} TabEntry; + +typedef short ScanElem; +typedef ScanElem * ScanLine; + +#define WORSTCOMPR(x) (2*(x) + 2) + + + static Header * -read_header(ifp, channel) - FILE *ifp; - int channel; -{ - Header *head; - - MALLOCVAR_NOFAIL(head); - - head->magic = get_big_short(ifp); - head->storage = get_byte(ifp); - head->bpc = get_byte(ifp); - head->dimension = get_big_short(ifp); - head->xsize = get_big_short(ifp); - head->ysize = get_big_short(ifp); - head->zsize = get_big_short(ifp); - head->pixmin = get_big_long(ifp); - head->pixmax = get_big_long(ifp); - read_bytes(ifp, 4, head->dummy1); - read_bytes(ifp, 80, head->name); - head->colormap = get_big_long(ifp); - read_bytes(ifp, 404, head->dummy2); - - if( head->magic != SGI_MAGIC ) +readHeader(FILE * const ifP, + bool const outChannelSpec, + bool const verbose) { + + Header * headP; + + MALLOCVAR_NOFAIL(headP); + + headP->magic = getBigShort(ifP); + headP->storage = getByte(ifP); + headP->bpc = getByte(ifP); + headP->dimension = getBigShort(ifP); + headP->xsize = getBigShort(ifP); + headP->ysize = getBigShort(ifP); + headP->zsize = getBigShort(ifP); + if (headP->zsize > MAX_ZSIZE) + pm_error("Too many channels in input image: %u", + (unsigned int) headP->zsize ); + headP->pixmin = getBigLong(ifP); + headP->pixmax = getBigLong(ifP); + if (headP->pixmin >= headP->pixmax) + pm_error("Invalid sgi image header: pixmin larger than pixmax"); + readBytes(ifP, 4, headP->dummy1); + readBytes(ifP, 80, headP->name); + headP->colormap = getBigLong(ifP); + readBytes(ifP, 404, headP->dummy2); + + if (headP->magic != SGI_MAGIC) pm_error("bad magic number - not an SGI image"); - if( head->storage != STORAGE_VERBATIM && head->storage != STORAGE_RLE ) + if (headP->storage != STORAGE_VERBATIM && headP->storage != STORAGE_RLE) pm_error("unknown compression type"); - if( head->bpc < 1 || head->bpc > 2 ) - pm_error("illegal precision value %d (only 1-2 allowed)", head->bpc ); - if( head->colormap != CMAP_NORMAL ) + if (headP->bpc < 1 || headP->bpc > 2) + pm_error("illegal precision value %d (only 1-2 allowed)", headP->bpc); + if (headP->colormap != CMAP_NORMAL) pm_error("non-normal pixel data of a form we don't recognize"); /* adjust ysize/zsize to dimension, just to be sure */ - switch( head->dimension ) { + switch (headP->dimension) { + case 1: + headP->ysize = 1; + break; + case 2: + headP->zsize = 1; + break; + case 3: + switch (headP->zsize) { case 1: - head->ysize = 1; + headP->dimension = 2; break; case 2: - head->zsize = 1; + if (!outChannelSpec) + pm_message("2-channel image, using only first channel. " + "Extract alpha channel with -channel=1"); break; case 3: - switch( head->zsize ) { - case 1: - head->dimension = 2; - break; - case 2: - pm_error("don\'t know how to interpret 2-channel image"); - break; - case 3: - break; - default: - if (channel < 0) - pm_message("%d-channel image, using only first 3 channels", head->zsize); - break; - } break; default: - pm_error("illegal dimension value %d (only 1-3 allowed)", head->dimension); + if (!outChannelSpec) + pm_message("%u-channel image, using only first 3 channels " + "Extract %s with -channel=%c", + headP->zsize, + headP->zsize==4 ? + "alpha channel" : "additional channels", + headP->zsize==4 ? '3' : 'N'); + break; + } + break; + default: + pm_error("illegal dimension value %u (only 1-3 allowed)", + headP->dimension); } - if( verbose ) { - pm_message("raster size %dx%d, %d channels", head->xsize, head->ysize, head->zsize); - pm_message("compression: %d = %s", head->storage, compression_name(head->storage)); - head->name[79] = '\0'; /* just to be safe */ - pm_message("Image name: \"%s\"", head->name); -#ifdef DEBUG - pm_message("bpc: %d dimension: %d zsize: %d", head->bpc, head->dimension, head->zsize); - pm_message("pixmin: %ld pixmax: %ld colormap: %ld", head->pixmin, head->pixmax, head->colormap); -#endif + if (verbose) { + pm_message("raster size %ux%u, %u channels", + headP->xsize, headP->ysize, headP->zsize); + pm_message("compression: 0x%02x = %s", + headP->storage, compressionName(headP->storage)); + headP->name[79] = '\0'; /* just to be safe */ + pm_message("Image name: '%s'", headP->name); } - return head; + return headP; } + static TabEntry * -read_table(ifp, tablen) - FILE *ifp; - int tablen; -{ - TabEntry *table; - int i; +readTable(FILE * const ifP, + int const tablen) { - MALLOCARRAY_NOFAIL(table, tablen); + TabEntry * table; + unsigned int i; -#ifdef DEBUG - pm_message("reading offset table"); -#endif + MALLOCARRAY_NOFAIL(table, tablen); - for( i = 0; i < tablen; i++ ) - table[i].start = get_big_long(ifp); - for( i = 0; i < tablen; i++ ) - table[i].length = get_big_long(ifp); + for (i = 0; i < tablen; ++i) + table[i].start = getBigLong(ifP); + for (i = 0; i < tablen; ++i) + table[i].length = getBigLong(ifP); return table; } +static void +rleDecompress(ScanElem * const srcStart, + int const srcleftStart, + ScanElem * const destStart, + int const destleftStart) { + + ScanElem * src; + int srcleft; + ScanElem * dest; + int destleft; + + for (src = srcStart, + srcleft = srcleftStart, + dest = destStart, + destleft = destleftStart; srcleft; ) { + + unsigned char const el = (unsigned char)(*src++ & 0xff); + unsigned int const count = (unsigned int)(el & 0x7f); + + --srcleft; + + if (count == 0) + return; + if (destleft < count) + pm_error("RLE error: too much input data " + "(space left %d, need %d)", destleft, count); + destleft -= count; + if (el & 0x80) { + unsigned int i; + if (srcleft < count) + pm_error("RLE error: not enough data for literal run " + "(data left %d, need %d)", srcleft, count); + srcleft -= count; + for (i = 0; i < count; ++i) + *dest++ = *src++; + } else { + unsigned int i; + if (srcleft == 0) + pm_error("RLE error: not enough data for replicate run"); + for (i = 0; i < count; ++i) + *dest++ = *src; + ++src; + --srcleft; + } + } + pm_error("RLE error: no terminating 0-byte"); +} + + + static ScanLine * -read_channels(ifp, head, table, func, ochan) - FILE *ifp; - Header *head; - TabEntry *table; - short (*func) ARGS((FILE *)); - int ochan; -{ - ScanLine *image; - ScanElem *temp; - int channel, maxchannel, row, sgi_index, i; - long offset, length; - -#ifdef DEBUG - pm_message("reading channels"); -#endif - - if (ochan < 0) { - maxchannel = (head->zsize < 3) ? head->zsize : 3; - MALLOCARRAY_NOFAIL(image, head->ysize * maxchannel); - } else { - maxchannel = ochan + 1; +readChannels(FILE * const ifP, + Header * const head, + TabEntry * const table, + bool const outChannelSpec, + unsigned int const outChannel) { + + ScanLine * image; + ScanElem * temp; + unsigned int channel; + unsigned int maxchannel; + + if (outChannelSpec) { + maxchannel = outChannel + 1; + MALLOCARRAY_NOFAIL(image, head->ysize); + } else if (head->zsize <= 2) { + maxchannel = 1; MALLOCARRAY_NOFAIL(image, head->ysize); + } else { + maxchannel = 3; + MALLOCARRAY_NOFAIL(image, head->ysize * maxchannel); } - if ( table ) + if (table) MALLOCARRAY_NOFAIL(temp, WORSTCOMPR(head->xsize)); - for( channel = 0; channel < maxchannel; channel++ ) { -#ifdef DEBUG - pm_message(" channel %d", channel); -#endif - for( row = 0; row < head->ysize; row++ ) { - int iindex; + for (channel = 0; channel < maxchannel; ++channel) { + unsigned int row; + for (row = 0; row < head->ysize; ++row) { + int const sgiIndex = channel * head->ysize + row; + + unsigned long int iindex; - sgi_index = channel * head->ysize + row; - iindex = (ochan < 0) ? sgi_index : row; - if (ochan < 0 || ochan == channel) + iindex = outChannelSpec ? row : sgiIndex; + if (!outChannelSpec || outChannel == channel) MALLOCARRAY_NOFAIL(image[iindex], head->xsize); - if( table ) { - if (channel < ochan) - continue; - - offset = table[sgi_index].start; - length = table[sgi_index].length; - if( head->bpc == 2 ) - length /= 2; - /* doc says length is in bytes, we are reading words */ - if( fseek(ifp, offset, SEEK_SET) != 0 ) - pm_error("seek error for offset %ld", offset); - - for( i = 0; i < length; i++ ) - temp[i] = (*func)(ifp); - rle_decompress(temp, length, image[iindex], head->xsize); - } - else { - for( i = 0; i < head->xsize; i++ ) - image[iindex][i] = (*func)(ifp); + if (table) { + if (!outChannelSpec || channel >= outChannel) { + pm_filepos const offset = (pm_filepos) + table[sgiIndex].start; + long const length = head->bpc == 2 ? + table[sgiIndex].length / 2 : + table[sgiIndex].length; + + unsigned int i; + + /* Note: (offset < currentPosition) can happen */ + + pm_seek2(ifP, &offset, sizeof(offset)); + + for (i = 0; i < length; ++i) + if (head->bpc == 1) + temp[i] = getByteAsShort(ifP); + else + temp[i] = getBigShort(ifP); + rleDecompress(temp, length, image[iindex], head->xsize); + } + } else { + unsigned int i; + for (i = 0; i < head->xsize; ++i) { + ScanElem p; + if (head->bpc == 1) + p = getByteAsShort(ifP); + else + p = getBigShort(ifP); + + if (!outChannelSpec || outChannel == channel) + image[iindex][i] = p; + } } } } - - if( table ) free(temp); + if (table) + free(temp); return image; } + static void -image_to_pnm(Header *head, ScanLine *image, xelval maxval, int channel) -{ - int col, row, format; - xel *pnmrow = pnm_allocrow(head->xsize); - int sub = head->pixmin; +imageToPnm(Header * const head, + ScanLine * const image, + xelval const maxval, + bool const outChannelSpec, + unsigned int const outChannel) { + + int const sub = head->pixmin; + xel * const pnmrow = pnm_allocrow(head->xsize); + + int row; + int format; - if( head->zsize == 1 || channel >= 0) { + if (head->zsize <= 2 || outChannelSpec) { pm_message("writing PGM image"); format = PGM_TYPE; - } - else { + } else { pm_message("writing PPM image"); format = PPM_TYPE; } - pnm_writepnminit(stdout, head->xsize, head->ysize, (xelval)maxval, format, 0); - for( row = head->ysize-1; row >= 0; row-- ) { - for( col = 0; col < head->xsize; col++ ) { - if( format == PGM_TYPE ) + pnm_writepnminit(stdout, head->xsize, head->ysize, maxval, format, 0); + for (row = head->ysize-1; row >= 0; --row) { + unsigned int col; + for (col = 0; col < head->xsize; ++col) { + if (format == PGM_TYPE) PNM_ASSIGN1(pnmrow[col], image[row][col] - sub); else { pixval r, g, b; @@ -329,135 +471,54 @@ image_to_pnm(Header *head, ScanLine *image, xelval maxval, int channel) PPM_ASSIGN(pnmrow[col], r, g, b); } } - pnm_writepnmrow(stdout, pnmrow, head->xsize, (xelval)maxval, format, 0); + pnm_writepnmrow(stdout, pnmrow, head->xsize, maxval, format, 0); } pnm_freerow(pnmrow); } -static void -rle_decompress(src, srcleft, dest, destleft) - ScanElem *src; - int srcleft; - ScanElem *dest; - int destleft; -{ - int count; - unsigned char el; - - while( srcleft ) { - el = (unsigned char)(*src++ & 0xff); - --srcleft; - count = (int)(el & 0x7f); - if( count == 0 ) - return; - if( destleft < count ) - pm_error("RLE error: too much input data (space left %d, need %d)", destleft, count); - destleft -= count; - if( el & 0x80 ) { - if( srcleft < count ) - pm_error("RLE error: not enough data for literal run (data left %d, need %d)", srcleft, count); - srcleft -= count; - while( count-- ) - *dest++ = *src++; - } - else { - if( srcleft == 0 ) - pm_error("RLE error: not enough data for replicate run"); - while( count-- ) - *dest++ = *src; - ++src; - --srcleft; - } - } - pm_error("RLE error: no terminating 0-byte"); -} - - -/* basic I/O functions, taken from ilbmtoppm.c */ - -static short -get_big_short(ifp) - FILE *ifp; -{ - short s; - - if( pm_readbigshort(ifp, &s) == -1 ) - readerr(ifp); - - return s; -} +int +main(int argc, const char * argv[]) { -static long -get_big_long(ifp) - FILE *ifp; -{ - long l; + struct CmdlineInfo cmdline; + FILE * ifP; + TabEntry * table; + ScanLine * image; + Header * headP; + xelval maxval; - if( pm_readbiglong(ifp, &l) == -1 ) - readerr(ifp); + pm_proginit(&argc, argv); - return l; -} + parseCommandLine(argc, argv, &cmdline); -static unsigned char -get_byte(ifp) - FILE* ifp; -{ - int i; + ifP = pm_openr_seekable(cmdline.inputFileName); - i = getc(ifp); - if( i == EOF ) - readerr(ifp); + headP = readHeader(ifP, cmdline.channelSpec, cmdline.verbose); - return (unsigned char) i; -} + maxval = headP->pixmax - headP->pixmin; + if (maxval > PNM_OVERALLMAXVAL) + pm_error("Maximum sample value in input image (%d) is too large. " + "This program's limit is %d.", + maxval, PNM_OVERALLMAXVAL); + if (cmdline.channelSpec && cmdline.channel >= headP->zsize) + pm_error("channel out of range - only %d channels in image", + headP->zsize); -static void -readerr(f) - FILE *f; -{ - if( ferror(f) ) - pm_error("read error"); + if (headP->storage != STORAGE_VERBATIM) + table = readTable(ifP, headP->ysize * headP->zsize); else - pm_error("premature EOF"); -} - + table = NULL; -static void -read_bytes(ifp, n, buf) - FILE *ifp; - int n; - char *buf; -{ - int r; + image = readChannels(ifP, headP, table, + cmdline.channelSpec, cmdline.channel); - r = fread((void *)buf, 1, n, ifp); - if( r != n ) - readerr(ifp); -} + imageToPnm(headP, image, maxval, cmdline.channelSpec, cmdline.channel); + pm_close(ifP); -static short -get_byte_as_short(ifp) - FILE *ifp; -{ - return (short)get_byte(ifp); + return 0; } -static const char * -compression_name(char compr) -{ - switch( compr ) { - case STORAGE_VERBATIM: - return "none"; - case STORAGE_RLE: - return "RLE"; - default: - return "unknown"; - } -} - diff --git a/converter/other/srf.c b/converter/other/srf.c new file mode 100644 index 00000000..b0f97242 --- /dev/null +++ b/converter/other/srf.c @@ -0,0 +1,653 @@ +/* + * Funcs for working with SRF (Garmin vehicle) files + * + * Written by Mike Frysinger + * Released into the public domain + */ + +#include + +#include "pm_c_util.h" +#include "mallocvar.h" +#include "nstring.h" +#include "srf.h" + + +static unsigned char +csumRaw(void * const p, + size_t const len) { + + unsigned char retval; + + unsigned int i; + unsigned char * c; + + for (i = 0, retval = 0, c = p; i < len; ++i) + retval += *c++; + + return retval; +} + + + +static unsigned char +csumPstring(struct srf_pstring * const pstringP) { + + return + csumRaw(&pstringP->len, 4) + csumRaw(pstringP->val, pstringP->len); +} + + + +static bool +readPstring(FILE * const ifP, + struct srf_pstring * const pstringP) { + + size_t bytesRead; + + pm_readlittlelong2u(ifP, &pstringP->len); + + MALLOCARRAY(pstringP->val, pstringP->len + 1); + + if (!pstringP->val) + pm_error("Failed to allocate buffer to read %u-byte pstring", + pstringP->len); + + bytesRead = fread(pstringP->val, 1, pstringP->len, ifP); + if (bytesRead != pstringP->len) + pm_error("Failed to read pstring. Requested %u bytes, got %u", + (unsigned)pstringP->len, (unsigned)bytesRead); + + pstringP->val[pstringP->len] = '\0'; + + return true; +} + + + +static bool +writePstring(FILE * const ofP, + struct srf_pstring * const pstringP) { + + bool retval; + size_t bytesWritten; + + pm_writelittlelongu(ofP, pstringP->len); + + bytesWritten = fwrite(pstringP->val, 1, pstringP->len, ofP); + + if (bytesWritten == pstringP->len) + retval = true; + else + retval = false; + + return retval; +} + + + +static size_t +lenHeader(struct srf_header * const headerP) { + + return 16 + (4 * 4) + 4 + headerP->s578.len + + 4 + 4 + headerP->ver.len + + 4 + 4 + headerP->prod.len; +} + + + +static unsigned char +csumHeader(struct srf_header * const headerP) { + + return + csumRaw(headerP->magic, 16) + + csumRaw(&headerP->_int4, 2 * 4) + + csumRaw(&headerP->img_cnt, 4) + + csumRaw(&headerP->_int5, 4) + + csumPstring(&headerP->s578) + + csumRaw(&headerP->_int6, 4) + + csumPstring(&headerP->ver) + + csumRaw(&headerP->_int7, 4) + + csumPstring(&headerP->prod); +} + + + +static bool +readHeader(FILE * const ifP, + struct srf_header * const headerP) { + + bool const retval = + fread(headerP->magic, 1, 16, ifP) == 16 && + pm_readlittlelong2u(ifP, &headerP->_int4[0]) == 0 && + pm_readlittlelong2u(ifP, &headerP->_int4[1]) == 0 && + pm_readlittlelong2u(ifP, &headerP->img_cnt) == 0 && + pm_readlittlelong2u(ifP, &headerP->_int5) == 0 && + readPstring(ifP, &headerP->s578) && + pm_readlittlelong2u(ifP, &headerP->_int6) == 0 && + readPstring(ifP, &headerP->ver) && + pm_readlittlelong2u(ifP, &headerP->_int7) == 0 && + readPstring(ifP, &headerP->prod); + + headerP->magic[16] = '\0'; + + return retval; +} + + + +static bool +writeHeader(FILE * const ofP, + struct srf_header * const headerP) { + + return + fwrite(headerP->magic, 1, 16, ofP) == 16 && + pm_writelittlelongu(ofP, headerP->_int4[0]) == 0 && + pm_writelittlelongu(ofP, headerP->_int4[1]) == 0 && + pm_writelittlelongu(ofP, headerP->img_cnt) == 0 && + pm_writelittlelongu(ofP, headerP->_int5) == 0 && + writePstring(ofP, &headerP->s578) && + pm_writelittlelongu(ofP, headerP->_int6) == 0 && + writePstring(ofP, &headerP->ver) && + pm_writelittlelongu(ofP, headerP->_int7) == 0 && + writePstring(ofP, &headerP->prod); +} + + + +static bool +checkHeader(struct srf_header * const headerP) { + + return + streq(headerP->magic, SRF_MAGIC) && + headerP->_int4[0] == 4 && + headerP->_int4[1] == 4 && + /* Should we require img_cnt to be multiple of 2 ? */ + headerP->img_cnt > 0 && + headerP->_int5 == 5 && + headerP->s578.len == 3 && + strcmp(headerP->s578.val, "578") == 0 && + headerP->_int6 == 6 && + headerP->ver.len == 4 && + /* Allow any headerP->ver value */ + headerP->_int7 == 7 && + headerP->prod.len == 12; + /* Allow any headerP->prod value */ +} + + + +static size_t +lenImg(struct srf_img * const imgP) { + + return + (4 * 3) + (2 * 2) + (1 * 2) + 2 + 4 + + 4 + 4 + imgP->alpha.data_len + + 4 + 4 + imgP->data.data_len; +} + + + +static unsigned char +csumImg(struct srf_img * const imgP) { + + struct srf_img_header * const headerP = &imgP->header; + struct srf_img_alpha * const alphaP = &imgP->alpha; + struct srf_img_data * const dataP = &imgP->data; + + return + csumRaw(&headerP->_ints, 4 * 3) + + csumRaw(&headerP->height, 2) + + csumRaw(&headerP->width, 2) + + csumRaw(headerP->_bytes, 2) + + csumRaw(&headerP->line_len, 2) + + csumRaw(&headerP->zeros, 4) + + csumRaw(&alphaP->type, 4) + + csumRaw(&alphaP->data_len, 4) + + csumRaw(alphaP->data, alphaP->data_len) + + csumRaw(&dataP->type, 4) + + csumRaw(&dataP->data_len, 4) + + csumRaw(dataP->data, dataP->data_len); +} + + + +static bool +readImgHeader(FILE * const ifP, + struct srf_img_header * const headerP) { + return + pm_readlittlelong2u(ifP, &headerP->_ints[0]) == 0 && + pm_readlittlelong2u(ifP, &headerP->_ints[1]) == 0 && + pm_readlittlelong2u(ifP, &headerP->_ints[2]) == 0 && + pm_readlittleshortu(ifP, &headerP->height) == 0 && + pm_readlittleshortu(ifP, &headerP->width) == 0 && + fread(&headerP->_bytes[0], 1, 1, ifP) == 1 && + fread(&headerP->_bytes[1], 1, 1, ifP) == 1 && + pm_readlittleshortu(ifP, &headerP->line_len) == 0 && + pm_readlittlelong2u(ifP, &headerP->zeros) == 0; +} + + + +static bool +writeImgHeader(FILE * const ofP, + struct srf_img_header * const headerP) { + return + pm_writelittlelongu(ofP, headerP->_ints[0]) == 0 && + pm_writelittlelongu(ofP, headerP->_ints[1]) == 0 && + pm_writelittlelongu(ofP, headerP->_ints[2]) == 0 && + pm_writelittleshortu(ofP, headerP->height) == 0 && + pm_writelittleshortu(ofP, headerP->width) == 0 && + fwrite(&headerP->_bytes[0], 1, 1, ofP) == 1 && + fwrite(&headerP->_bytes[1], 1, 1, ofP) == 1 && + pm_writelittleshortu(ofP, headerP->line_len) == 0 && + pm_writelittlelongu(ofP, headerP->zeros) == 0; +} + + + +static bool +checkImgHeader(struct srf_img_header * const headerP) { + + return + headerP->_ints[0] == 0 && + headerP->_ints[1] == 16 && + headerP->_ints[2] == 0 && + headerP->_bytes[0] == 16 && + headerP->_bytes[1] == 8 && + headerP->line_len == headerP->width * 2 && + headerP->zeros == 0; +} + + + +static bool +readImgAlpha(FILE * const ifP, + struct srf_img_alpha * const alphaP) { + + bool retval; + + pm_readlittlelong2u(ifP, &alphaP->type); + pm_readlittlelong2u(ifP, &alphaP->data_len); + + MALLOCARRAY(alphaP->data, alphaP->data_len); + + if (!alphaP->data) + retval = false; + else { + size_t bytesRead; + + bytesRead = fread(alphaP->data, 1, alphaP->data_len, ifP); + retval = (bytesRead ==alphaP->data_len); + } + return retval; +} + + + +static bool +writeImageAlpha(FILE * const ofP, + struct srf_img_alpha * const alphaP) { + + return + pm_writelittlelongu(ofP, alphaP->type) == 0 && + pm_writelittlelongu(ofP, alphaP->data_len) == 0 && + fwrite(alphaP->data, 1, alphaP->data_len, ofP) == alphaP->data_len; +} + + + +static bool +checkImgAlpha(struct srf_img_alpha * const alphaP) { + + return (alphaP->type == 11); +} + + + +static bool +readImgData(FILE * const ifP, + struct srf_img_data * const dataP) { + + bool retval; + + pm_readlittlelong2u(ifP, &dataP->type); + pm_readlittlelong2u(ifP, &dataP->data_len); + + MALLOCARRAY(dataP->data, dataP->data_len / 2); + + if (!dataP->data) + retval = false; + else { + size_t bytesRead; + bytesRead = fread(dataP->data, 2, dataP->data_len / 2, ifP); + + retval = (bytesRead == dataP->data_len / 2); + } + return retval; +} + + + +static bool +writeImgData(FILE * const ofP, + struct srf_img_data * const dataP) { + + return + pm_writelittlelongu(ofP, dataP->type) == 0 && + pm_writelittlelongu(ofP, dataP->data_len) == 0 && + fwrite(dataP->data, 2, dataP->data_len / 2, ofP) + == dataP->data_len / 2; +} + + + +static bool +checkImgData(struct srf_img_data * const dataP) { + return dataP->type == 1; +} + + + +static bool +readImg(FILE * const ifP, + bool const verbose, + uint32_t const i, + struct srf_img * const imgP) { + + if (!readImgHeader(ifP, &imgP->header)) + pm_error("short srf image %u header", i); + if (!checkImgHeader(&imgP->header)) + pm_error("invalid srf image %u header", i); + + if (verbose) + pm_message("reading srf 16-bit RGB %ux%u image %u", + imgP->header.width, imgP->header.height, i); + + if (!readImgAlpha(ifP, &imgP->alpha)) + pm_error("short srf image %u alpha mask", i); + if (!checkImgAlpha(&imgP->alpha)) + pm_error("invalid srf image %u alpha mask", i); + + if (!readImgData(ifP, &imgP->data)) + pm_error("short srf image %u data", i); + if (!checkImgData(&imgP->data)) + pm_error("invalid srf image %u data", i); + + return true; +} + + + +static bool +writeImg(FILE * const ofP, + uint32_t const i, + struct srf_img * const imgP) { + + if (!checkImgHeader(&imgP->header)) + pm_error("invalid srf image %u header", i); + if (!writeImgHeader(ofP, &imgP->header)) + pm_error("short srf image %u header", i); + + if (!checkImgAlpha(&imgP->alpha)) + pm_error("invalid srf image %u alpha mask", i); + if (!writeImageAlpha(ofP, &imgP->alpha)) + pm_error("short srf image %u alpha mask", i); + + if (!checkImgData(&imgP->data)) + pm_error("invalid srf image %u data", i); + if (!writeImgData(ofP, &imgP->data)) + pm_error("short srf image %u data", i); + + return true; +} + + + +static uint8_t +csum(struct srf * const srfP, + size_t const padLen) { +/*---------------------------------------------------------------------------- + The sum of everything in the SRF image except the checksum byte. The + checksum byte is supposed to be the arithmetic opposite of this so that the + sum of everything is zero. +-----------------------------------------------------------------------------*/ + unsigned char retval; + unsigned int i; + + retval = csumHeader(&srfP->header); + + for (i = 0; i < srfP->header.img_cnt; ++i) + retval += csumImg(&srfP->imgs[i]); + + for (i = 0; i < padLen; ++i) + retval += 0xff; + + return retval; +} + + + +void +srf_read(FILE * const ifP, + bool const verbose, + struct srf * const srfP) { + + uint8_t trialCsum; + size_t padLen; + unsigned char pad[256]; + unsigned int i; + + if (!readHeader(ifP, &srfP->header)) + pm_error("short srf header"); + if (!checkHeader(&srfP->header)) + pm_error("invalid srf header"); + + if (verbose) + pm_message("reading srf ver %s with prod code %s and %u images", + srfP->header.ver.val, srfP->header.prod.val, + srfP->header.img_cnt); + + MALLOCARRAY(srfP->imgs, srfP->header.img_cnt); + + if (!srfP->imgs) + pm_error("Could not allocate memory for %u images", + srfP->header.img_cnt); + + for (i = 0; i < srfP->header.img_cnt; ++i) + if (!readImg(ifP, verbose, i, &srfP->imgs[i])) + pm_error("invalid srf image %u", i); + + padLen = fread(pad, 1, sizeof(pad), ifP); + if (!feof(ifP)) { + pm_errormsg("excess data at end of file"); + return; + } + + trialCsum = csum(srfP, 0); /* initial value */ + for (i = 0; i < padLen; ++i) + trialCsum += pad[i]; + if (trialCsum != 0) + pm_errormsg("checksum does not match"); +} + + + +void +srf_write(FILE * const ofP, + struct srf * const srfP) { + + uint8_t srfCsum; /* checksum value in SRF image */ + size_t padLen; + unsigned int i; + size_t bytesWritten; + + padLen = 1; /* initial value */ + + if (!checkHeader(&srfP->header)) + pm_error("invalid srf header"); + if (!writeHeader(ofP, &srfP->header)) + pm_error("write srf header"); + padLen += lenHeader(&srfP->header); + + for (i = 0; i < srfP->header.img_cnt; ++i) { + if (!writeImg(ofP, i, &srfP->imgs[i])) + pm_error("invalid srf image %u", i); + padLen += lenImg(&srfP->imgs[i]); + } + + /* Pad to 256 bytes */ + padLen = 256 - (padLen % 256); + if (padLen) { + char * d; + size_t bytesWritten; + + MALLOCARRAY(d, padLen); + + if (!d) + pm_error("Could not allocate memory for %u bytes of padding", + (unsigned)padLen); + + memset(d, 0xff, padLen); + + bytesWritten = fwrite(d, 1, padLen, ofP); + + if (bytesWritten != padLen) + pm_error("unable to 0xff pad file"); + + free(d); + } + + /* Write out checksum byte */ + srfCsum = 0xff - csum(srfP, padLen) + 1; + bytesWritten = fwrite(&srfCsum, 1, 1, ofP); + if (bytesWritten != 1) + pm_error("unable to write checksum"); +} + + + +static void +freeImg(struct srf_img * const imgP) { + + free(imgP->alpha.data); + free(imgP->data.data); +} + + + +void +srf_term(struct srf * const srfP) { + + unsigned int i; + + free(srfP->header.s578.val); + free(srfP->header.ver.val); + free(srfP->header.prod.val); + + for (i = 0; i < srfP->header.img_cnt; ++i) + freeImg(&srfP->imgs[i]); + + free(srfP->imgs); +} + + + +static void +srf_img_init(struct srf_img * const imgP, + uint16_t const width, + uint16_t const height) { + + struct srf_img_header * const headerP = &imgP->header; + struct srf_img_alpha * const alphaP = &imgP->alpha; + struct srf_img_data * const dataP = &imgP->data; + + headerP->_ints[0] = 0; + headerP->_ints[1] = 16; + headerP->_ints[2] = 0; + headerP->height = height; + headerP->width = width; + headerP->_bytes[0] = 16; + headerP->_bytes[1] = 8; + headerP->line_len = width * 2; + headerP->zeros = 0; + + alphaP->type = 11; + alphaP->data_len = height * width; + MALLOCARRAY(alphaP->data, alphaP->data_len); + + if (!alphaP->data) + pm_error("Could not allocate buffer for %u bytes of alpha", + alphaP->data_len); + + dataP->type = 1; + dataP->data_len = height * width * 2; + MALLOCARRAY(dataP->data, dataP->data_len / 2); + + if (!dataP->data) + pm_error("Could not allocation buffer for %u units of data", + dataP->data_len); +} + + + +static void +initPstring(struct srf_pstring * const pstringP, + const char * const s) { + + pstringP->len = strlen(s); + + MALLOCARRAY(pstringP->val, pstringP->len + 1); + + if (!pstringP->val) + pm_error("Could not allocate memory for string of length %u", + pstringP->len); + + memcpy(pstringP->val, s, pstringP->len + 1); +} + + + +void +srf_init(struct srf * const srfP) { + + struct srf_header * const headerP = &srfP->header; + + strcpy(headerP->magic, SRF_MAGIC); + headerP->_int4[0] = 4; + headerP->_int4[1] = 4; + headerP->img_cnt = 0; + headerP->_int5 = 5; + initPstring(&headerP->s578, "578"); + headerP->_int6 = 6; + initPstring(&headerP->ver, "1.00"); + headerP->_int7 = 7; + initPstring(&headerP->prod, "006-D0578-XX"); + + srfP->imgs = NULL; +} + + + +void +srf_create_img(struct srf * const srfP, + uint16_t const width, + uint16_t const height) { +/*---------------------------------------------------------------------------- + Add an "image" to the SRF. An image is a horizontal series of 36 + square frames, each showing a different angle view of an object, 10 + degrees about. At least that's what it's supposed to be. We don't + really care -- it's just an arbitrary rectangular raster image to us. +-----------------------------------------------------------------------------*/ + + ++srfP->header.img_cnt; + + REALLOCARRAY(srfP->imgs, srfP->header.img_cnt); + + if (!srfP->imgs) + pm_error("Could not allocate memory for %u images", + srfP->header.img_cnt); + + srf_img_init(&srfP->imgs[srfP->header.img_cnt-1], width, height); +} + diff --git a/converter/other/srf.h b/converter/other/srf.h new file mode 100644 index 00000000..e06355a4 --- /dev/null +++ b/converter/other/srf.h @@ -0,0 +1,170 @@ +#ifndef SRF_H_INCLUDED +#define SRF_H_INCLUDED + +/* + * Structures for working with SRF (Garmin vehicle) files + * http://www.techmods.net/nuvi/ + * + * Written by Mike Frysinger + * Released into the public domain + */ + +#include "pm_config.h" +#include "pam.h" + +struct srf_pstring { + uint32_t len; + char * val; +}; + +#define SRF_NUM_FRAMES 36 + +/* + File Header + 16 bytes - string - "GARMIN BITMAP 01" + 32 bytes - two 32-bit ints, [4, 4] -- purpose unknown + 4 bytes - 32-bit int -- number of images (usually just 2) + 4 bytes - 32-bit int, [5] -- purpose unknown + 7 bytes - PString - "578" + 4 bytes - 32-bit int, [6] -- purpose unknown + 8 bytes - PString - version number ("1.00", "2.00", "2.10", or "2.20") + 4 bytes - 32-bit int, [7] -- purpose unknown + 16 bytes - PString - "006-D0578-XX" (where "XX" changes) -- + I assume this is Garmin's product code? +*/ +#define SRF_MAGIC "GARMIN BITMAP 01" + +struct srf_header { + char magic[16 + 1]; + + uint32_t _int4[2]; + + uint32_t img_cnt; + + uint32_t _int5; + + struct srf_pstring s578; + + uint32_t _int6; + + struct srf_pstring ver; + + uint32_t _int7; + + struct srf_pstring prod; +}; + +/* + Image Header + 12 bytes - three 32-bit ints, [0,16,0] -- purpose unknown + 2 bytes - 16-bit int -- height of image (just the 3D section, so it's 80) + 2 bytes - 16-bit int -- width of image (just the 3D section, 2880 or 2881) + 2 bytes - [16, 8] -- purpose unknown + 2 bytes - 16-bit int -- byte length of each line of image RGB data + (16-bit RGB), so "width * 2" + 4 bytes - all zeroes -- purpose unknown +*/ +struct srf_img_header { + uint32_t _ints[3]; + + uint16_t height, width; + + char _bytes[2]; + + uint16_t line_len; + + uint32_t zeros; +}; + +/* + Image Alpha Mask + + 4 bytes - 32-bit int, [11] -- Might specify the type of data that + follows? + + 4 bytes - 32-bit int, length of following data (width*height of 3D + section) + + width*height bytes - alpha mask data, 0 = opaque, 128 = transparent + (across, then down) + + Notes: The Garmin format has 129 values: [0..128] [opaque..transparent] + The PNG format has 256 values: [0..255] [transparent..opaque] + So we have to do a little edge case tweaking to keep things lossless. +*/ + +#define SRF_ALPHA_OPAQUE 0 +#define SRF_ALPHA_TRANS 128 + +struct srf_img_alpha { + uint32_t type; + + uint32_t data_len; + unsigned char * data; +}; + +/* + Image RGB Data + 4 bytes - 32-bit int, [1] -- Might specify the type of data that follows? + 4 bytes - 32-bit int, length of following data (width*height*2 of 3D + section, as the RGB data is 16-bit) + width*height*2 bytes - RBG values as "rrrrrggggg0bbbbb" bits + (across, then down) +*/ + +struct srf_img_data { + uint32_t type; + + uint32_t data_len; + uint16_t * data; +}; + +struct srf_img { + struct srf_img_header header; + struct srf_img_alpha alpha; + struct srf_img_data data; +}; + +/* + Footer + arbitrary number of bytes - all 0xFF -- these are used (as well as the + checksum byte) to pad the file + size to a multiple of 256. + + 1 byte - checksum byte -- use this byte to adjust so that the ascii sum + of all bytes in the file is a multiple of 256. + */ + +struct srf { + struct srf_header header; + struct srf_img * imgs; +}; + +uint8_t +srf_alpha_srftopam(uint8_t const d); + +uint8_t +srf_alpha_pamtosrf(uint8_t const d); + +void +srf_read(FILE * const ifP, + bool const verbose, + struct srf * const srfP); + +void +srf_write(FILE * const ofP, + struct srf * const srfP); + +void +srf_term(struct srf * const srfP); + +void +srf_init(struct srf * const srfP); + +void +srf_create_img(struct srf * const srfP, + uint16_t const width, + uint16_t const height); + +#endif + diff --git a/converter/other/srftopam.c b/converter/other/srftopam.c new file mode 100644 index 00000000..efe55253 --- /dev/null +++ b/converter/other/srftopam.c @@ -0,0 +1,226 @@ +/* + * Convert a SRF (Garmin vehicle) to a PAM image + * + * Copyright (C) 2011 by Mike Frysinger + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. This software is provided "as is" without express or + * implied warranty. + */ + +#include +#include + +#include "pm_c_util.h" +#include "shhopt.h" +#include "mallocvar.h" +#include "nstring.h" +#include "pam.h" +#include "srf.h" + +struct cmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + const char * inputFileName; /* '-' if stdin */ + unsigned int verbose; +}; + +static bool verbose; + + + +static void +parseCommandLine(int argc, const char ** argv, + struct cmdlineInfo * const cmdlineP) { +/*---------------------------------------------------------------------------- + parse program command line described in Unix standard form by argc + and argv. Return the information in the options as *cmdlineP. + + If command line is internally inconsistent (invalid options, etc.), + issue error message to stderr and abort program. + + Note that the strings we return are stored in the storage that + was passed to us as the argv array. We also trash *argv. +-----------------------------------------------------------------------------*/ + optEntry *option_def; + /* Instructions to pm_optParseOptions3 on how to parse our options. + */ + optStruct3 opt; + + unsigned int option_def_index; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENT3 */ + OPTENT3(0, "verbose", OPT_FLAG, NULL, + &cmdlineP->verbose, 0); + + opt.opt_table = option_def; + opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ + opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ + + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + if (argc-1 < 1) + cmdlineP->inputFileName = "-"; + else if (argc-1 == 1) + cmdlineP->inputFileName = argv[1]; + else + pm_error("Program takes at most one argument: input file name"); +} + + + +static unsigned int +srfRed(uint16_t const pixel) { + return ((pixel >> 11) & 0x1f) << 3; +} + + +static unsigned int +srfGrn(uint16_t const pixel) { + return ((pixel >> 6) & 0x1f) << 3; +} + + +static unsigned int +srfBlu(uint16_t const pixel) { + return ((pixel >> 0) & 0x1f) << 3; +} + + +static uint8_t +srfAlpha(uint8_t const d) { + + uint8_t retval; + + if (d == SRF_ALPHA_OPAQUE) + retval = 0xff; + else + retval = (128 - d) << 1; + + return retval; +} + + + +static void +writeRaster(struct pam * const pamP, + struct srf_img * const imgP) { + + tuple * tuplerow; + unsigned int row; + + assert(imgP->header.width <= pamP->width); + + tuplerow = pnm_allocpamrow(pamP); + + for (row = 0; row < imgP->header.height; ++row) { + unsigned int const rowStart = row * imgP->header.width; + + unsigned int col; + + for (col = 0; col < imgP->header.width; ++col) { + uint16_t const data = imgP->data.data[rowStart + col]; + uint16_t const alpha = imgP->alpha.data[rowStart + col]; + + assert(col < pamP->width); + + tuplerow[col][PAM_RED_PLANE] = srfRed(data); + tuplerow[col][PAM_GRN_PLANE] = srfGrn(data); + tuplerow[col][PAM_BLU_PLANE] = srfBlu(data); + tuplerow[col][PAM_TRN_PLANE] = srfAlpha(alpha); + } + + for (; col < pamP->width; ++col) { + tuplerow[col][PAM_RED_PLANE] = 0; + tuplerow[col][PAM_GRN_PLANE] = 0; + tuplerow[col][PAM_BLU_PLANE] = 0; + tuplerow[col][PAM_TRN_PLANE] = 0; + } + + pnm_writepamrow(pamP, tuplerow); + } + pnm_freepamrow(tuplerow); +} + + + +static void +convertOneImage(struct srf_img * const imgP, + FILE * const ofP) { + + const char * comment = "Produced by srftopam"; /* constant */ + + struct pam outPam; + + outPam.size = sizeof(struct pam); + outPam.len = PAM_STRUCT_SIZE(comment_p); + outPam.file = ofP; + outPam.format = PAM_FORMAT; + outPam.plainformat = 0; + outPam.width = imgP->header.width; + outPam.height = imgP->header.height; + outPam.depth = 4; + outPam.maxval = 255; + outPam.bytes_per_sample = 1; + sprintf(outPam.tuple_type, "RGB_ALPHA"); + outPam.allocation_depth = 4; + outPam.comment_p = &comment; + + pnm_writepaminit(&outPam); + + writeRaster(&outPam, imgP); +} + + + +static void +srftopam(struct cmdlineInfo const cmdline, + FILE * const ifP, + FILE * const ofP) { + + unsigned int imgSeq; + struct srf srf; + + srf_read(ifP, verbose, &srf); + + for (imgSeq = 0; imgSeq < srf.header.img_cnt; ++imgSeq) { + if (verbose) + pm_message("Converting Image %u", imgSeq); + convertOneImage(&srf.imgs[imgSeq], ofP); + } + + srf_term(&srf); +} + + + +int +main(int argc, const char * argv[]) { + + struct cmdlineInfo cmdline; + FILE * ifP; + + pm_proginit(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + verbose = cmdline.verbose; + + ifP = pm_openr(cmdline.inputFileName); + + srftopam(cmdline, ifP, stdout); + + pm_closer(ifP); + + return 0; +} + + + diff --git a/converter/other/sunicontopnm.c b/converter/other/sunicontopnm.c new file mode 100644 index 00000000..eff1be58 --- /dev/null +++ b/converter/other/sunicontopnm.c @@ -0,0 +1,172 @@ +/* icontopbm.c - read a Sun icon file and produce a Netbpbm image. +** +** Copyright (C) 1988 by Jef Poskanzer. +** +** Permission to use, copy, modify, and distribute this software and its +** documentation for any purpose and without fee is hereby granted, provided +** that the above copyright notice appear in all copies and that both that +** copyright notice and this permission notice appear in supporting +** documentation. This software is provided "as is" without express or +** implied warranty. +*/ + +/* + Most icon images are monochrome: Depth=1 + Depth=8 images are extremely rare. At least some of these are color + images but we can't tell the palette color order. + Output will be in pgm. Convert to ppm with pgmtoppm or pamlookup + if necessary. +*/ + +#include +#include + +#include "nstring.h" +#include "pbm.h" +#include "pgm.h" + + + +static void +ReadIconFileHeader(FILE * const file, + int * const widthP, + int * const heightP, + int * const depthP, + int * const bitsPerItemP) { + + unsigned int fieldCt; + + fieldCt = 0; + *widthP = *heightP = -1; + + for ( ; ; ) { + char variable[80+1]; + int ch; + unsigned int i; + int value; + + while ((ch = getc(file)) == ',' || ch == '\n' || ch == '\t' || + ch == ' ') + ; + for (i = 0; + ch != '=' && ch != ',' && ch != '\n' && ch != '\t' && + ch != ' ' && (i < (sizeof(variable) - 1)); + ++i) { + variable[i] = ch; + if ((ch = getc( file )) == EOF) + pm_error( "invalid input file -- premature EOF" ); + } + variable[i] = '\0'; + + if (streq(variable, "*/") && fieldCt > 0) + break; + + if (fscanf( file, "%d", &value ) != 1) + continue; + + if (streq( variable, "Width")) { + *widthP = value; + ++fieldCt; + } else if (streq( variable, "Height")) { + *heightP = value; + ++fieldCt; + } else if (streq( variable, "Depth")) { + if (value != 1 && value != 8) + pm_error("invalid depth"); + *depthP = value; + ++fieldCt; + } else if (streq(variable, "Format_version")) { + if (value != 1) + pm_error("invalid Format_version"); + ++fieldCt; + } else if (streq(variable, "Valid_bits_per_item")) { + if (value != 16 && value !=32) + pm_error("invalid Valid_bits_per_item"); + *bitsPerItemP = value; + ++fieldCt; + } + } + + if (fieldCt < 5) + pm_error("invalid sun icon file header: " + "only %u out of required 5 fields present", fieldCt); + + if (*widthP <= 0) + pm_error("invalid width (must be positive): %d", *widthP); + if (*heightP <= 0) + pm_error("invalid height (must be positive): %d", *heightP); + +} + + +int +main(int argc, const char ** argv) { + + FILE * ifP; + bit * bitrow; + gray * grayrow; + int rows, cols, depth, row, format, maxval, colChars, bitsPerItem; + + pm_proginit(&argc, argv); + + if (argc-1 > 1) + pm_error("Too many arguments (%u). Program takes at most one: " + "name of input file", argc-1); + + if (argc-1 == 1) + ifP = pm_openr(argv[1]); + else + ifP = stdin; + + ReadIconFileHeader(ifP, &cols, &rows, &depth, &bitsPerItem); + + if (depth == 1) { + format = PBM_TYPE; + maxval = 1; + pbm_writepbminit(stdout, cols, rows, 0); + bitrow = pbm_allocrow_packed(cols); + colChars = cols / 8; + } else { + assert(depth == 8); + format = PGM_TYPE; + maxval = 255; + pgm_writepgminit(stdout, cols, rows, maxval, 0); + grayrow = pgm_allocrow(cols); + colChars = cols; + } + + for (row = 0; row < rows; ++row) { + unsigned int colChar; + for (colChar = 0; colChar < colChars; ++colChar) { + unsigned int data; + int status; + + /* read 8 bits */ + if (row==0 && colChar == 0) + status = fscanf(ifP, " 0x%2x", &data); + else if (colChar % (bitsPerItem/8) == 0) + status = fscanf(ifP, ", 0x%2x", &data); + else + status = fscanf(ifP, "%2x", &data); + + /* write 8 bits */ + if (status == 1) { + if (format == PBM_TYPE) + bitrow[colChar] = data; + else + grayrow[colChar] = data; + } else + pm_error("error scanning bits item %u" , colChar); + } + + /* output row */ + if (format == PBM_TYPE) + pbm_writepbmrow_packed(stdout, bitrow, cols, 0); + else + pgm_writepgmrow(stdout, grayrow, cols, maxval, 0); + } + + pm_close(ifP); + pm_close(stdout); + return 0; +} diff --git a/converter/other/svgtopam.c b/converter/other/svgtopam.c index c7eac8e6..137f4732 100644 --- a/converter/other/svgtopam.c +++ b/converter/other/svgtopam.c @@ -26,7 +26,9 @@ ============================================================================*/ +#define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */ #define _BSD_SOURCE /* Make sure strdup() is in */ +#define _POSIX_SOURCE /* Make sure fileno() is in */ #include #include #include @@ -66,7 +68,7 @@ parseCommandLine(int argc, was passed to us as the argv array. We also trash *argv. --------------------------------------------------------------------------*/ optEntry *option_def; - /* Instructions to optParseOptions3 on how to parse our options. */ + /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; unsigned int option_def_index; @@ -81,7 +83,7 @@ parseCommandLine(int argc, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3( &argc, argv, opt, sizeof(opt), 0 ); + pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0 ); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (argc-1 < 1) @@ -192,7 +194,7 @@ destroyPath(path * const pathP) { assert(pathP->pathTextLength == strlen(pathP->pathText)); - strfree(pathP->pathText); + pm_strfree(pathP->pathText); free(pathP); } @@ -518,7 +520,7 @@ interpretStyle(const char * const styleAttr) { p = &buffer[0]; while (p) { - const char * const token = strsepN(&p, ";"); + const char * const token = pm_strsep(&p, ";"); const char * strippedToken; const char * p; char * buffer; @@ -661,14 +663,14 @@ stringToUint(const char * const string, /* TODO: move this to nstring.c */ if (strlen(string) == 0) - asprintfN(errorP, "Value is a null string"); + pm_asprintf(errorP, "Value is a null string"); else { char * tailptr; *uintP = strtoul(string, &tailptr, 10); if (*tailptr != '\0') - asprintfN(errorP, "Non-numeric crap in string: '%s'", tailptr); + pm_asprintf(errorP, "Non-numeric crap in string: '%s'", tailptr); else *errorP = NULL; } @@ -689,12 +691,12 @@ getSvgAttributes(xmlTextReaderPtr const xmlReaderP, stringToUint(width, colsP, &error); if (error) { pm_error("'width' attribute of has invalid value. %s", error); - strfree(error); + pm_strfree(error); } stringToUint(height, rowsP, &error); if (error) { pm_error("'height' attribute of has invalid value. %s", error); - strfree(error); + pm_strfree(error); } } diff --git a/converter/other/tiff.c b/converter/other/tiff.c index 90d50710..d0cbbd74 100644 --- a/converter/other/tiff.c +++ b/converter/other/tiff.c @@ -10,12 +10,6 @@ #include -#ifdef VMS -#ifdef SYSV -#undef SYSV -#endif -#include -#endif #include #include "pm_c_util.h" diff --git a/converter/other/tifftopnm.c b/converter/other/tifftopnm.c index 6665c7fd..0d6494f9 100644 --- a/converter/other/tifftopnm.c +++ b/converter/other/tifftopnm.c @@ -52,7 +52,6 @@ #include #include #include -#include #include "pm_c_util.h" #include "shhopt.h" @@ -60,12 +59,6 @@ #include "nstring.h" #include "pnm.h" -#ifdef VMS -#ifdef SYSV -#undef SYSV -#endif -#include -#endif /* See warning about tiffio.h in pamtotiff.c */ #include @@ -85,7 +78,7 @@ #define PHOTOMETRIC_DEPTH 32768 #endif -struct cmdlineInfo { +struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ @@ -103,7 +96,7 @@ struct cmdlineInfo { static void parseCommandLine(int argc, const char ** const argv, - struct cmdlineInfo * const cmdlineP) { + struct CmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- Note that many of the strings that this function returns in the *cmdlineP structure are actually in the supplied argv array. And @@ -135,7 +128,7 @@ parseCommandLine(int argc, const char ** const argv, OPTENT3(0, "alphaout", OPT_STRING, &cmdlineP->alphaFilename, &alphaSpec, 0); - optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); if (argc - 1 == 0) cmdlineP->inputFilename = strdup("-"); /* he wants stdin */ @@ -158,6 +151,31 @@ parseCommandLine(int argc, const char ** const argv, +static TIFF * +newTiffImageObject(const char * const inputFileName) { +/*---------------------------------------------------------------------------- + Create a TIFF library object for accessing the TIFF input in file + named 'inputFileName'. If 'inputFileName' is "-", that means + Standard Input. +-----------------------------------------------------------------------------*/ + const char * const tiffSourceName = + streq(inputFileName, "-") ? "Standard Input" : inputFileName; + + TIFF * retval; + + retval = TIFFFdOpen(fileno(pm_openr_seekable(inputFileName)), + tiffSourceName, + "r"); + + if (retval == NULL) + pm_error("Failed to access input file. The OS opened the file fine, " + "but the TIFF library's TIFFFdOpen rejected the open file."); + + return retval; +} + + + static void getBps(TIFF * const tif, unsigned short * const bpsP) { @@ -226,6 +244,8 @@ tiffToImageDim(unsigned int const tiffCols, } } + + static void getTiffDimensions(TIFF * const tiffP, unsigned int * const colsP, @@ -345,15 +365,15 @@ readDirectory(TIFF * const tiffP, static void -readscanline(TIFF * const tif, - unsigned char scanbuf[], - int const row, - int const plane, - unsigned int const cols, - unsigned short const bps, - unsigned short const spp, - unsigned short const fillorder, - unsigned int * const samplebuf) { +readscanline(TIFF * const tif, + unsigned char * const scanbuf, + int const row, + int const plane, + unsigned int const cols, + unsigned short const bps, + unsigned short const spp, + unsigned short const fillorder, + unsigned int * const samplebuf) { /*---------------------------------------------------------------------------- Read one scanline out of the Tiff input and store it into samplebuf[]. Unlike the scanline returned by the Tiff library function, samplebuf[] @@ -381,8 +401,8 @@ readscanline(TIFF * const tif, "TIFFReadScanline() failed.", row, plane); else if (bps == 8) { - int sample; - for (sample = 0; sample < cols*spp; sample++) + unsigned int sample; + for (sample = 0; sample < cols * spp; ++sample) samplebuf[sample] = scanbuf[sample]; } else if (bps < 8) { /* Note that in this format, samples do not span bytes. Rather, @@ -390,12 +410,12 @@ readscanline(TIFF * const tif, At least that's how I infer the format from reading pnmtotiff.c -Bryan 00.11.18 */ - int sample; - int bitsleft; + unsigned int sample; + unsigned int bitsleft; unsigned char * inP; - for (sample = 0, bitsleft=8, inP=scanbuf; - sample < cols*spp; + for (sample = 0, bitsleft = 8, inP = scanbuf; + sample < cols * spp; ++sample) { if (bitsleft == 0) { ++inP; @@ -412,6 +432,7 @@ readscanline(TIFF * const tif, pm_error("Internal error: invalid value for fillorder: %u", fillorder); } + assert(bitsleft >= bps); bitsleft -= bps; if (bitsleft < bps) /* Don't count dregs at end of byte */ @@ -433,10 +454,10 @@ readscanline(TIFF * const tif, for (sample = 0; sample < cols*spp; ++sample) samplebuf[sample] = scanbuf16[sample]; } else if (bps == 32) { - uint32 * const scanbuf32 = (uint32 *) scanbuf; + const uint32 * const scanbuf32 = (const uint32 *) scanbuf; unsigned int sample; - for (sample = 0; sample < cols*spp; ++sample) + for (sample = 0; sample < cols * spp; ++sample) samplebuf[sample] = scanbuf32[sample]; } else pm_error("Internal error: invalid bits per sample passed to " @@ -446,8 +467,11 @@ readscanline(TIFF * const tif, static void -pick_cmyk_pixel(const unsigned int samplebuf[], const int sample_cursor, - xelval * const r_p, xelval * const b_p, xelval * const g_p) { +pick_cmyk_pixel(unsigned int const samplebuf[], + int const sampleCursor, + xelval * const redP, + xelval * const bluP, + xelval * const grnP) { /* Note that the TIFF spec does not say which of the 4 samples is which, but common sense says they're in order C,M,Y,K. Before @@ -455,10 +479,10 @@ pick_cmyk_pixel(const unsigned int samplebuf[], const int sample_cursor, But combined with a compensating error in the CMYK->RGB calculation, it had the same effect as C,M,Y,K. */ - unsigned int const c = samplebuf[sample_cursor+0]; - unsigned int const m = samplebuf[sample_cursor+1]; - unsigned int const y = samplebuf[sample_cursor+2]; - unsigned int const k = samplebuf[sample_cursor+3]; + unsigned int const c = samplebuf[sampleCursor + 0]; + unsigned int const m = samplebuf[sampleCursor + 1]; + unsigned int const y = samplebuf[sampleCursor + 2]; + unsigned int const k = samplebuf[sampleCursor + 3]; /* The CMYK->RGB formula used by TIFFRGBAImageGet() in the TIFF library is the following, (with some apparent confusion with @@ -476,9 +500,9 @@ pick_cmyk_pixel(const unsigned int samplebuf[], const int sample_cursor, Yellow ink removes blue light from what the white paper reflects. */ - *r_p = 255 - MIN(255, c + k); - *g_p = 255 - MIN(255, m + k); - *b_p = 255 - MIN(255, y + k); + *redP = 255 - MIN(255, c + k); + *grnP = 255 - MIN(255, m + k); + *bluP = 255 - MIN(255, y + k); } @@ -515,9 +539,9 @@ analyzeImageType(TIFF * const tif, unsigned short const photomet, xelval * const maxvalP, int * const formatP, - xel colormap[], + xel * const colormap, bool const headerdump, - struct cmdlineInfo const cmdline) { + struct CmdlineInfo const cmdline) { bool grayscale; @@ -733,44 +757,40 @@ spawnWithInputPipe(const char * const shellCmd, int fd[2]; int rc; - rc = pipe(fd); + rc = pm_pipe(fd); if (rc != 0) - asprintfN(errorP, "Failed to create pipe for process input. " - "Errno=%d (%s)", errno, strerror(errno)); + pm_asprintf(errorP, "Failed to create pipe for process input. " + "Errno=%d (%s)", errno, strerror(errno)); else { - int rc; - - rc = fork(); + int iAmParent; + pid_t childPid; - if (rc < 0) { - asprintfN(errorP, "Failed to fork a process. errno=%d (%s)", - errno, strerror(errno)); - } else if (rc == 0) { - /* This is the child */ - int rc; - close(fd[PIPE_WRITE]); - close(STDIN_FILENO); - dup2(fd[PIPE_READ], STDIN_FILENO); + pm_fork(&iAmParent, &childPid, errorP); - rc = system(shellCmd); + if (!*errorP) { + if (iAmParent) { + close(fd[PIPE_READ]); - exit(rc); - } else { - /* Parent */ - pid_t const childPid = rc; - - close(fd[PIPE_READ]); + *pidP = childPid; + *pipePP = fdopen(fd[PIPE_WRITE], "w"); + + if (*pipePP == NULL) + pm_asprintf(errorP,"Unable to create stream from pipe. " + "fdopen() fails with errno=%d (%s)", + errno, strerror(errno)); + else + *errorP = NULL; + } else { + int rc; + close(fd[PIPE_WRITE]); + close(STDIN_FILENO); + dup2(fd[PIPE_READ], STDIN_FILENO); - *pidP = childPid; - *pipePP = fdopen(fd[PIPE_WRITE], "w"); + rc = system(shellCmd); - if (*pipePP == NULL) - asprintfN(errorP,"Unable to create stream from pipe. " - "fdopen() fails with errno=%d (%s)", - errno, strerror(errno)); - else - *errorP = NULL; + exit(rc); + } } } } @@ -787,7 +807,7 @@ createFlipProcess(FILE * const outFileP, Create a process that runs the program Pamflip and writes its output to *imageoutFileP. - The process takes it input from a pipe that we create. We return as + The process takes its input from a pipe that we create. We return as *inPipePP a file stream connected to the other end of that pipe. I.e. Caller will write a Netpbm file stream to **inPipePP and a flipped @@ -810,8 +830,8 @@ createFlipProcess(FILE * const outFileP, file descriptor is equivalent to writing to the stream. */ - asprintfN(&pamflipCmd, "pamflip -xform=%s >&%u", - xformNeeded(orientation), fileno(outFileP)); + pm_asprintf(&pamflipCmd, "pamflip -xform=%s >&%u", + xformNeeded(orientation), fileno(outFileP)); if (verbose) pm_message("Reorienting raster with shell command '%s'", pamflipCmd); @@ -823,7 +843,7 @@ createFlipProcess(FILE * const outFileP, "raster, failed. %s. To work around this, you can use " "the -orientraw option.", pamflipCmd, error); - strfree(error); + pm_strfree(error); } } @@ -973,12 +993,12 @@ pnmOut_init(FILE * const imageoutFileP, data, pnmOut get 'cols' x 'rows' data, but its output file may be 'rows x cols'. - Because the pnmOut object must be set up to receive flipped or not - flipped input, we have *flipOkP and *noflipOkP outputs that tell - Caller whether he has to flip or not. In the unique case that - the TIFF matrix is already oriented the way the output PNM file needs - to be, flipping is idempotent, so both *flipOkP and *noflipOkP are - true. + Because we must set up the pnmOut object either to receive flipped or not + flipped input, we have *flipOkP and *noflipOkP outputs that tell Caller + whether he has to flip or not. Note that Caller also influences which way + we set up pnmOut, with his 'flipIfNeeded' argument. In the unique case + that the TIFF matrix is already oriented the way the output PNM file needs + to be, flipping is idempotent, so both *flipOkP and *noflipOkP are true. -----------------------------------------------------------------------------*/ pnmOutP->imageoutFileP = imageoutFileP; pnmOutP->alphaFileP = alphaFileP; @@ -1040,14 +1060,12 @@ pnmOut_term(pnmOut * const pnmOutP, "waiting for Pamflip to terminate"); if (pnmOutP->imagePipeP) { - int status; fclose(pnmOutP->imagePipeP); - waitpid(pnmOutP->imageFlipPid, &status, 0); + pm_waitpidSimple(pnmOutP->imageFlipPid); } if (pnmOutP->alphaPipeP) { - int status; fclose(pnmOutP->alphaPipeP); - waitpid(pnmOutP->alphaFlipPid, &status, 0); + pm_waitpidSimple(pnmOutP->alphaFlipPid); } } else { if (pnmOutP->imageoutFileP) @@ -1090,8 +1108,8 @@ pnmOut_writeRow(pnmOut * const pnmOutP, static void convertRow(unsigned int const samplebuf[], - xel xelrow[], - gray alpharow[], + xel * const xelrow, + gray * const alpharow, int const cols, xelval const maxval, unsigned short const photomet, @@ -1167,9 +1185,9 @@ convertRow(unsigned int const samplebuf[], static void -scale32to16(unsigned int samplebuf[], - unsigned int const cols, - unsigned int const spp) { +scale32to16(unsigned int * const samplebuf, + unsigned int const cols, + unsigned int const spp) { /*---------------------------------------------------------------------------- Convert every sample in samplebuf[] to something that can be expressed in 16 bits, assuming it takes 32 bits now. @@ -1182,9 +1200,9 @@ scale32to16(unsigned int samplebuf[], static void -convertMultiPlaneRow(TIFF * const tif, - xel xelrow[], - gray alpharow[], +convertMultiPlaneRow(TIFF * const tif, + xel * const xelrow, + gray * const alpharow, int const cols, xelval const maxval, int const row, @@ -1200,15 +1218,15 @@ convertMultiPlaneRow(TIFF * const tif, for the blues. */ - int col; - if (photomet != PHOTOMETRIC_RGB) pm_error("This is a multiple-plane file, but is not an RGB " "file. This program does not know how to handle that."); else { + unsigned int col; + /* First, clear the buffer so we can add red, green, and blue one at a time. - */ + */ for (col = 0; col < cols; ++col) PPM_ASSIGN(xelrow[col], 0, 0, 0); @@ -1261,8 +1279,8 @@ convertRasterByRows(pnmOut * const pnmOutP, bool const verbose) { /*---------------------------------------------------------------------------- With the TIFF header all processed (and relevant information from it in - our arguments), write out the TIFF raster to the file images *imageoutFile - and *alphaFile. + our arguments), write out the TIFF raster to the Netpbm output files + as described by *pnmOutP. Do this one row at a time, employing the TIFF library's TIFFReadScanline. @@ -1282,12 +1300,12 @@ convertRasterByRows(pnmOut * const pnmOutP, row we are presently converting. */ - int row; + unsigned int row; if (verbose) pm_message("Converting row by row ..."); - scanbuf = (unsigned char *) malloc(TIFFScanlineSize(tif)); + MALLOCARRAY(scanbuf, TIFFScanlineSize(tif)); if (scanbuf == NULL) pm_error("can't allocate memory for scanline buffer"); @@ -1362,7 +1380,7 @@ warnBrokenTiffLibrary(TIFF * const tiffP) { case ORIENTATION_RIGHTBOT: case ORIENTATION_LEFTBOT: pm_message("WARNING: This TIFF image has an orientation that " - "most TIFF libraries converts incorrectly. " + "most TIFF libraries convert incorrectly. " "Use -byrow to circumvent."); break; } @@ -1421,20 +1439,23 @@ convertTiffRaster(uint32 * const raster, -enum convertDisp {CONV_DONE, CONV_OOM, CONV_UNABLE, CONV_FAILED, +enum convertDisp {CONV_DONE, + CONV_OOM, + CONV_UNABLE, + CONV_FAILED, CONV_NOTATTEMPTED}; static void -convertRasterInMemory(pnmOut * const pnmOutP, - xelval const maxval, - TIFF * const tif, - unsigned short const photomet, - unsigned short const planarconfig, - unsigned short const bps, - unsigned short const spp, - unsigned short const fillorder, - xel const colormap[], - bool const verbose, +convertRasterInMemory(pnmOut * const pnmOutP, + xelval const maxval, + TIFF * const tif, + unsigned short const photomet, + unsigned short const planarconfig, + unsigned short const bps, + unsigned short const spp, + unsigned short const fillorder, + xel const colormap[], + bool const verbose, enum convertDisp * const statusP) { /*---------------------------------------------------------------------------- With the TIFF header all processed (and relevant information from @@ -1469,7 +1490,7 @@ convertRasterInMemory(pnmOut * const pnmOutP, int ok; ok = TIFFRGBAImageOK(tif, emsg); if (!ok) { - pm_message(emsg); + pm_message("%s", emsg); *statusP = CONV_UNABLE; } else { uint32 * raster; @@ -1489,14 +1510,14 @@ convertRasterInMemory(pnmOut * const pnmOutP, ok = TIFFRGBAImageBegin(&img, tif, stopOnErrorFalse, emsg); if (!ok) { - pm_message(emsg); + pm_message("%s", emsg); *statusP = CONV_FAILED; } else { int ok; ok = TIFFRGBAImageGet(&img, raster, cols, rows); TIFFRGBAImageEnd(&img) ; if (!ok) { - pm_message(emsg); + pm_message("%s", emsg); *statusP = CONV_FAILED; } else { *statusP = CONV_DONE; @@ -1524,6 +1545,7 @@ convertRaster(pnmOut * const pnmOutP, bool const verbose) { enum convertDisp status; + if (byrow || !flipOk) status = CONV_NOTATTEMPTED; else { @@ -1563,7 +1585,7 @@ static void convertImage(TIFF * const tifP, FILE * const alphaFileP, FILE * const imageoutFileP, - struct cmdlineInfo const cmdline) { + struct CmdlineInfo const cmdline) { struct tiffDirInfo tiffDir; int format; @@ -1600,7 +1622,7 @@ static void convertIt(TIFF * const tifP, FILE * const alphaFile, FILE * const imageoutFile, - struct cmdlineInfo const cmdline) { + struct CmdlineInfo const cmdline) { unsigned int imageSeq; bool eof; @@ -1625,8 +1647,8 @@ convertIt(TIFF * const tifP, int main(int argc, const char * argv[]) { - struct cmdlineInfo cmdline; - TIFF * tif; + struct CmdlineInfo cmdline; + TIFF * tiffP; FILE * alphaFile; FILE * imageoutFile; @@ -1634,15 +1656,7 @@ main(int argc, const char * argv[]) { parseCommandLine(argc, argv, &cmdline); - if (!streq(cmdline.inputFilename, "-")) { - tif = TIFFOpen(cmdline.inputFilename, "r"); - if (tif == NULL) - pm_error("error opening TIFF file %s", cmdline.inputFilename); - } else { - tif = TIFFFdOpen(0, "Standard Input", "r"); - if (tif == NULL) - pm_error("error opening standard input as TIFF file"); - } + tiffP = newTiffImageObject(cmdline.inputFilename); if (cmdline.alphaStdout) alphaFile = stdout; @@ -1656,16 +1670,19 @@ main(int argc, const char * argv[]) { else imageoutFile = stdout; - convertIt(tif, alphaFile, imageoutFile, cmdline); + convertIt(tiffP, alphaFile, imageoutFile, cmdline); if (imageoutFile != NULL) pm_close( imageoutFile ); if (alphaFile != NULL) pm_close( alphaFile ); - strfree(cmdline.inputFilename); + TIFFClose(tiffP); + + pm_strfree(cmdline.inputFilename); /* If the program failed, it previously aborted with nonzero completion - code, via various function calls. */ + code, via various function calls. + */ return 0; } diff --git a/converter/other/winicon.h b/converter/other/winicon.h new file mode 100644 index 00000000..9ede01f5 --- /dev/null +++ b/converter/other/winicon.h @@ -0,0 +1,82 @@ +#include "pm_c_util.h" + +#define ICONDIR_TYPE_ICO (1) + +/* windows icon structures */ +struct IconDirEntry { + uint16_t width; /* image width in pixels 0 == 256 */ + uint16_t height; /* image height in pixels 0 == 256 */ + uint8_t color_count; /* 0 if bits_per_pixel >= 8 */ + uint8_t zero; /* 0 */ + uint16_t color_planes; /* 1 */ + uint16_t bits_per_pixel; /* allowed values: 1, 4, 8, 16 or 32 (1) */ + uint32_t size; /* size of image */ + uint32_t offset; /* file offset of image */ + + uint16_t index; /* extra field (not in file) */ +}; + +/* (1) This is from + * http://blogs.msdn.com/b/oldnewthing/archive/2010/10/19/10077610.aspx. + * + * However, the bpp value in the icon directory is used as a hint for + * image selection only. It seems to be legal to set this value to + * zero, and e.g. in SHELL32.DLL of Win98SE, there are many 8bpp + * images described as 24 bit images in the icon directory. + * + * The bpp value of image 1 in icon 150 in SHELL32.DLL of WinXP is 24 + * (in header and BMP). This may be a bug, as the 32 x 32 x 8 image + * is missing, but it shows the Windows icon rendering engine is able + * to cope with 24 bit images). + * + * 16bpp icons are at least rare in the wild. + */ +struct IconDir { + uint16_t zero; /* 0 */ + uint16_t type; /* 1 */ + uint16_t count; /* number of images in icon */ + + unsigned int entriesAllocCt; /* # of allocated slots in 'entries'*/ + struct IconDirEntry * entries; /* one entry for each image */ +}; + +/* BMP image structures */ + +struct BitmapInfoHeader { + uint32_t header_size; /* >= 40 */ + int32_t bm_width; + int32_t bm_height; + uint16_t color_planes; + uint16_t bits_per_pixel; + uint32_t compression_method; + uint32_t image_size; + int32_t horizontal_resolution; /* pixels per meter (!) */ + int32_t vertical_resolution; /* pixels per meter (!) */ + uint32_t colors_in_palette; + uint32_t important_colors; + + bool top_down; /* extra field (not in file) */ + +}; + +typedef enum { + BI_RGB = 0, + BI_BITFIELDS = 3 + +} BiCompression; + +/* PNG image structures */ +#define PNG_HEADER { 0x89, 'P', 'N', 'G', '\r', '\n', 0x1A /* ^Z */, '\n' } + +struct PngIhdr { + uint32_t length; /* 13 */ + uint32_t signature; /* "IHDR" */ + uint32_t width; /* image width in pixels */ + uint32_t height; /* image height in pixels */ + uint8_t bit_depth; /* depth per channel */ + uint8_t color_type; /* recognized values: 0, 2, 3, 4 and 6 */ + uint8_t compression; + uint8_t filter; + uint8_t interlace; + uint32_t crc; +}; diff --git a/converter/other/winicontopam.c b/converter/other/winicontopam.c new file mode 100644 index 00000000..664b4ef9 --- /dev/null +++ b/converter/other/winicontopam.c @@ -0,0 +1,1286 @@ +#include +#include +#include + +#include "netpbm/pm_config.h" +#include "netpbm/pm_c_util.h" +#include "netpbm/mallocvar.h" +#include "netpbm/nstring.h" +#include "netpbm/shhopt.h" +#include "netpbm/pam.h" +#include "netpbm/pm_system.h" + +#include "winicon.h" + +#define RED 0 +#define GRN 1 +#define BLU 2 +#define ALPHA 3 +#define CHANNEL_CHARS "RGBA" + + + +static bool verbose; + + + +struct CmdlineInfo { + + const char * inputFileName; + unsigned int allimages; + unsigned int imageSpec; + unsigned int image; + unsigned int andmasks; + unsigned int headerdump; + unsigned int verbose; +}; + + + +static void +parseCommandLine(int argc, const char **argv, + struct CmdlineInfo * const cmdlineP) { + + optEntry * option_def; + unsigned int option_def_index; + optStruct3 opt3; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; + + OPTENT3(0, "allimages", OPT_FLAG, NULL, + &cmdlineP->allimages, 0); + OPTENT3(0, "image", OPT_UINT, &cmdlineP->image, + &cmdlineP->imageSpec, 0); + OPTENT3(0, "andmasks", OPT_FLAG, NULL, + &cmdlineP->andmasks, 0); + OPTENT3(0, "headerdump", OPT_FLAG, NULL, + &cmdlineP->headerdump, 0); + OPTENT3(0, "verbose", OPT_FLAG, NULL, + &cmdlineP->verbose, 0); + + opt3.opt_table = option_def; + opt3.short_allowed = false; + opt3.allowNegNum = false; + + pm_optParseOptions3(&argc, (char **)argv, opt3, sizeof(opt3), 0); + + if (cmdlineP->allimages && cmdlineP->imageSpec) + pm_error("You cannot specify both -allimages and -image"); + + if (argc-1 < 1) + cmdlineP->inputFileName = "-"; + else { + cmdlineP->inputFileName = argv[1]; + + if (argc-1 > 1) + pm_error("Too many arguments. The only possible " + "non-option argument is the input file name"); + } + + free(option_def); +} + + + +static unsigned char const pngHeader[] = PNG_HEADER; + + + +struct File { + + FILE * fileP; + const char * name; + pm_filepos pos; + +}; + + + +static uint32_t +u8_le(const unsigned char * const buf, + size_t const offset) { + + return buf[offset + 0]; +} + + + +static uint32_t +u16_le(const unsigned char * const buf, + size_t const offset) { + + return + ((uint32_t)buf[offset + 0] << 0) + + ((uint32_t)buf[offset + 1] << 8); +} + + + +static uint32_t +u32_le(const unsigned char * const buf, + size_t const offset) { + + return + ((uint32_t)buf[offset + 0] << 0) + + ((uint32_t)buf[offset + 1] << 8) + + ((uint32_t)buf[offset + 2] << 16) + + ((uint32_t)buf[offset + 3] << 24); +} + + + +static uint32_t +s32_le(const unsigned char * const buf, + size_t const offset) { + + return + ((uint32_t)buf[offset + 0] << 0) + + ((uint32_t)buf[offset + 1] << 8) + + ((uint32_t)buf[offset + 2] << 16) + + ((uint32_t)buf[offset + 3] << 24); +} + + + +static uint32_t +u8_be(const unsigned char * const buf, + size_t const offset) { + + return buf[offset + 0]; +} + + + +static uint32_t +u32_be(const unsigned char * const buf, + size_t const offset) { + + return + ((uint32_t)buf[offset + 0] << 24) + + ((uint32_t)buf[offset + 1] << 16) + + ((uint32_t)buf[offset + 2] << 8) + + ((uint32_t)buf[offset + 3] << 0); +} + + + +static uint32_t +u32_xx(const unsigned char * const buf, + size_t const offset) { + + uint32_t u32; + + ((uint8_t*) &u32)[0] = buf[offset + 0]; + ((uint8_t*) &u32)[1] = buf[offset + 1]; + ((uint8_t*) &u32)[2] = buf[offset + 2]; + ((uint8_t*) &u32)[3] = buf[offset + 3]; + + return (u32); +} + + + +#ifndef LITERAL_FN_DEF_MATCH +static qsort_comparison_fn cmpfn; +#endif + +static int +cmpfn(const void * const aP, + const void * const bP) { + + const struct IconDirEntry * const dirEntryAP = aP; + const struct IconDirEntry * const dirEntryBP = bP; + + if (dirEntryAP->offset < dirEntryBP->offset) + return -1; + else if (dirEntryAP->offset > dirEntryBP->offset) + return +1; + else + return 0; +} + + + +static void +dumpIconDir(const struct IconDir * const dirP) { + + unsigned int i; + + pm_message("Type: %u", dirP->type); + pm_message("Icon directory has %u images:", dirP->count); + + for (i = 0; i < dirP->count; ++i) { + const struct IconDirEntry * const dirEntryP = &dirP->entries[i]; + + pm_message("width: %u", dirEntryP->width); + pm_message("height: %u", dirEntryP->height); + pm_message("color count: %u", dirEntryP->color_count); + pm_message("# color planes: %u", dirEntryP->color_planes); + pm_message("bits per pixel: %u", dirEntryP->bits_per_pixel); + pm_message("offset in file of image: %u", dirEntryP->offset); + pm_message("size of image: %u", dirEntryP->size); + pm_message("zero field: %u", dirEntryP->zero); + } +} + + + +static struct IconDir * +readIconDir(struct File * const fP, + bool const needHeaderDump) { + + struct IconDir head; + struct IconDir * dirP; + uint32_t imageIndex; /* more bits than dir.count */ + + pm_readlittleshortu(fP->fileP, &head.zero); + pm_readlittleshortu(fP->fileP, &head.type); + pm_readlittleshortu(fP->fileP, &head.count); + fP->pos += 6; + + if (head.zero != 0 || head.type != ICONDIR_TYPE_ICO) + pm_error("Not a valid windows icon file"); + + MALLOCVAR(dirP); + + if (dirP == NULL) + pm_error("Could't allocate memory for Icon directory"); + + MALLOCARRAY(dirP->entries, head.count); + + if (dirP->entries == NULL) + pm_error("Could not allocate memory for %u entries in icon directory", + head.count); + + dirP->zero = head.zero; + dirP->type = head.type; + dirP->count = head.count; + dirP->entriesAllocCt = head.count; + + for (imageIndex = 0; imageIndex < head.count; ++imageIndex) { + struct IconDirEntry * const dirEntryP = &dirP->entries[imageIndex]; + + unsigned char widthField, heightField; + + unsigned long ul; + + pm_readcharu(fP->fileP, &widthField); + dirEntryP->width = (widthField == 0 ? 256 : widthField); + + pm_readcharu(fP->fileP, &heightField); + dirEntryP->height = (heightField == 0 ? 256 : heightField); + + pm_readcharu(fP->fileP, &dirEntryP->color_count); + + pm_readcharu(fP->fileP, &dirEntryP->zero); + + pm_readlittleshortu(fP->fileP, &dirEntryP->color_planes); + + pm_readlittleshortu(fP->fileP, &dirEntryP->bits_per_pixel); + + pm_readlittlelongu(fP->fileP, &ul); dirEntryP->size = ul; + + pm_readlittlelongu(fP->fileP, &ul); dirEntryP->offset = ul; + + fP->pos += 16; + + dirEntryP->index = imageIndex; + } + + /* The following is paranoia code only: + + I've never seen a windows icon file in the wild with having the entries + in the directory stored in a different order than the images + themselves. However, the file format allows for it ... + */ + qsort(dirP->entries, dirP->count, sizeof(struct IconDirEntry), cmpfn); + + if (verbose) { + pm_message("%s icon directory (%u image%s):", + fP->name, + dirP->count, dirP->count == 1 ? "" : "s"); + + for (imageIndex = 0; imageIndex < dirP->count; ++imageIndex) { + const struct IconDirEntry * const dirEntryP = + &dirP->entries[imageIndex]; + + uint32_t colorCt; + + if (dirEntryP->bits_per_pixel == 0) + colorCt = 0; + else if (dirEntryP->bits_per_pixel >= 32) + colorCt = 1u << 24; + else + colorCt = 1u << dirEntryP->bits_per_pixel; + + if (dirEntryP->color_count != 0 && + colorCt > dirEntryP->color_count) { + colorCt = dirEntryP->color_count; + } + pm_message ("%5u: %3u x %3u, %8u colors, %5u bytes", + dirEntryP->index, + dirEntryP->width, + dirEntryP->height, + colorCt, + dirEntryP->size); + } + } + + if (needHeaderDump) + dumpIconDir(dirP); + + return dirP; +} + + + +static void +freeIconDir(struct IconDir * const dirP) { + + free(dirP->entries); + free(dirP); +} + + + +static const unsigned char * +readImage(struct File * const fP, + struct IconDirEntry * const dirEntryP) { + + size_t rc; + unsigned char * image; + uint32_t skippedCt; + + /* Don't try to read an image that is smaller than the + BITMAPINFOHEADER of BMP images (40 bytes). + + PNG compressed images can't be smaller than that either, as the + PNG header plus the mandantory IHDR and IEND chunks already take + 8 + 25 + 12 = 35 bytes, and there is to be a IDAT chunk too. + */ + if (dirEntryP->size < 40) { + pm_error("image %2u: format violation: too small as an image.", + dirEntryP->index); + } + if ((pm_filepos) dirEntryP->offset < fP->pos) + pm_error("image %2u: format violation: invalid offset.", + dirEntryP->index); + + /* The following is paranoia code only: + + I've never seen a windows icon file in the wild with gaps between + the images, but the file format allows for it, and Microsoft + expects the user to fseek() to the start of each image. + */ + skippedCt = 0; + + while ((pm_filepos) dirEntryP->offset > fP->pos) { + if (getc(fP->fileP) == EOF) { + pm_error("seeking to image %u: unexpected EOF", dirEntryP->index); + } + ++fP->pos; + ++skippedCt; + } + + /* The additional four bytes are for purify and friends, as the + routines reading BMP XOR and AND masks might read (but not + evaluate) some bytes beyond the image data. + */ + image = malloc(dirEntryP->size + sizeof(uint32_t)); + if (image == NULL) + pm_error("out of memory."); + + rc = fread (image, 1, dirEntryP->size, fP->fileP); + if (rc != dirEntryP->size) { + pm_error("reading image %2u: unexpected EOF", dirEntryP->index); + } + fP->pos += dirEntryP->size; + + return image; +} + + + +static uint8_t +getIdx1(const unsigned char * const bitmap, + uint32_t const offset, + int16_t const col) { + + return u8_le(bitmap, offset + (col >> 3)) >> (7 - (col & 0x07)) & 0x1; +} + + + +static uint8_t +getIdx4(const unsigned char * const bitmap, + uint32_t const offset, + int16_t const col) { + + if ((col & 1) == 0x0000) + return u8_le(bitmap, offset + (col >> 1)) >> 4 & 0x0F; + else + return u8_le(bitmap, offset + (col >> 1)) >> 0 & 0x0F; +} + + + +static uint8_t +getIdx8(const unsigned char * const bitmap, + uint32_t const offset, + int16_t const col) { + + return u8_le(bitmap, offset + col); +} + + + +typedef unsigned char PaletteEntry[4]; + + + +static void +dumpPalette(const PaletteEntry * const palette, + unsigned int const colorCt) { + + unsigned int i; + + for (i = 0; i < colorCt; ++i) { + pm_message("Color %u: (%u, %u, %u)", + i, palette[i][2], palette[i][1], palette[i][0]); + } +} + + + +static void +readXorPalette(struct BitmapInfoHeader * const hdrP, + const unsigned char * const bitmap, + uint32_t const maxSize, + tuple ** const tuples, + uint16_t const index, + bool const needHeaderDump, + uint32_t * const bytesConsumedP) { + + uint32_t paletteSize; + + int16_t row; + const PaletteEntry * palette; + uint32_t truncatedXorSize; + uint32_t bytesConsumed; + uint32_t bytesPerRow; + const unsigned char * bitmapCursor; + uint32_t sizeRemaining; + + uint8_t (*getIdx) (const unsigned char * bitmap, + uint32_t rowOffset, + int16_t col); + + if (hdrP->compression_method != BI_RGB) + pm_error("image %2u: invalid compression method %u.", + index, hdrP->compression_method); + + assert(hdrP->bits_per_pixel < 16); + + switch (hdrP->bits_per_pixel) { + case 1: + if (hdrP->colors_in_palette == 0) + hdrP->colors_in_palette = 2; + getIdx = getIdx1; + break; + + case 4: + if (hdrP->colors_in_palette == 0) + hdrP->colors_in_palette = 16; + getIdx = getIdx4; + break; + + case 8: + if (hdrP->colors_in_palette == 0) + hdrP->colors_in_palette = 256; + getIdx = getIdx8; + break; + + default: + pm_error("image %2u: " + "bits per pixel is a value we don't understand: %u", + index, hdrP->bits_per_pixel); + getIdx = NULL; + } + + bitmapCursor = &bitmap[0]; /* initial value */ + sizeRemaining = maxSize; /* initial value */ + bytesConsumed = 0; /* initial value */ + + paletteSize = hdrP->colors_in_palette * 4; + + if (sizeRemaining < paletteSize) + pm_error("image %2u: " + "reading palette: image truncated.", index); + + palette = (const PaletteEntry *) bitmapCursor; + + if (needHeaderDump) + dumpPalette(palette, hdrP->colors_in_palette); + + bitmapCursor += paletteSize; + sizeRemaining -= paletteSize; + bytesConsumed += paletteSize; + + { + uint32_t const xorSize = (uint32_t) + (((hdrP->bits_per_pixel * hdrP->bm_width + 31) / 32) + * 4 * hdrP->bm_height / 2); + + if (sizeRemaining < xorSize) { + pm_message("image %2u: " + "reading XOR mask: image truncated.", index); + truncatedXorSize = sizeRemaining; + } else + truncatedXorSize = xorSize; + } + + bytesPerRow = ((hdrP->bits_per_pixel * hdrP->bm_width + 31) / 32) * 4; + + for (row = 0; hdrP->bm_height / 2 > row; ++row) { + uint32_t rowOffset; + + if (hdrP->top_down) + rowOffset = row * bytesPerRow; + else + rowOffset = (hdrP->bm_height / 2 - row - 1) * bytesPerRow; + + if (rowOffset + bytesPerRow <= truncatedXorSize) { + int16_t col; + for (col = 0; hdrP->bm_width > col; ++col) { + uint8_t const idx = getIdx(bitmapCursor, rowOffset, col); + + if (idx > hdrP->colors_in_palette) + pm_error("invalid palette index in row %u, column %u.", + row, col); + + /* The palette is an array of little-endian 32-bit values, + where the RGB value is encoded as follows: + + red: bits 2^16..2^23 + green: bits 2^8 ..2^15 + blue: bits 2^0 ..2^7 + */ + tuples[row][col][PAM_RED_PLANE] = palette[idx][2]; + tuples[row][col][PAM_GRN_PLANE] = palette[idx][1]; + tuples[row][col][PAM_BLU_PLANE] = palette[idx][0]; + } + } + } + + bitmapCursor += truncatedXorSize; + sizeRemaining -= truncatedXorSize; + bytesConsumed += truncatedXorSize; + + *bytesConsumedP = bytesConsumed; +} + + + +static void +readXorBitfields(struct BitmapInfoHeader * const hdrP, + const unsigned char * const bitmap, + uint32_t const maxSize, + tuple ** const tuples, + uint16_t const index, + bool * const haveAlphaP, + uint32_t * const bytesConsumedP) { + + uint32_t bitfields[4]; + uint8_t shift [4]; + sample maxval [4]; + + int16_t row; + uint32_t bytesConsumed; + uint32_t bytesPerSample; + uint32_t bytesPerRow; + const unsigned char * bitmapCursor; + uint32_t sizeRemaining; + uint32_t truncatedXorSize; + + static uint8_t alphas [256]; + bool allOpaque; + bool allTransparent; + + bytesConsumed = 0; + + if (hdrP->compression_method != BI_RGB + && hdrP->compression_method != BI_BITFIELDS) + pm_error("image %2u: invalid compression method %u.", + index, hdrP->compression_method); + + assert(hdrP->bits_per_pixel >= 16); + + switch (hdrP->bits_per_pixel) { + case 16: + bytesPerSample = 2; + bitfields[RED] = 0x7C00; + bitfields[GRN] = 0x03E0; + bitfields[BLU] = 0x001F; + bitfields[ALPHA] = 0x0000; + break; + + case 24: + bytesPerSample = 3; + bitfields[RED] = 0xFF0000; + bitfields[GRN] = 0x00FF00; + bitfields[BLU] = 0x0000FF; + bitfields[ALPHA] = 0x000000; + break; + + case 32: + bytesPerSample = 4; + bitfields[RED] = 0x00FF0000; + bitfields[GRN] = 0x0000FF00; + bitfields[BLU] = 0x000000FF; + bitfields[ALPHA] = 0xFF000000; + break; + + default: + pm_error("image %2u: bits per pixel is one we don't understand: %u.", + index, hdrP->bits_per_pixel); + bytesPerSample = 0; + } + + bitmapCursor = &bitmap[0]; /* initial value */ + sizeRemaining = maxSize; /* initial value */ + + /* read bit fields from image data */ + if (hdrP->compression_method == BI_BITFIELDS) { + if (sizeRemaining < 12) + pm_error("image %2u: " + "reading bit fields: image truncated.", index); + + bitfields[RED] = u32_le(bitmapCursor, 0); + bitfields[GRN] = u32_le(bitmapCursor, 4); + bitfields[BLU] = u32_le(bitmapCursor, 8); + bitfields[ALPHA] = 0; + + bitmapCursor += 12; + sizeRemaining -= 12; + bytesConsumed += 12; + } + + /* determine shift and maxval from bit field for each channel */ + { + unsigned int i; + + for (i = 0; 4 > i; ++i) { + if (bitfields[i] == 0) { + maxval[i] = 1; + shift [i] = 0; + } else { + unsigned int j; + + maxval[i] = bitfields[i]; + + for (j = 0; 32 > j; ++j) { + if ((maxval[i] & 0x1) != 0) + break; + maxval[i] >>= 1; + } + shift[i] = j; + } + + } + } + + /* read the XOR mask */ + { + uint32_t const xorSize = (uint32_t) + (((hdrP->bits_per_pixel * hdrP->bm_width + 31) / 32) + * 4 * hdrP->bm_height / 2); + + if (sizeRemaining < xorSize) { + pm_message("image %2u: " + "reading XOR mask: image truncated.", index); + truncatedXorSize = sizeRemaining; + } else + truncatedXorSize = xorSize; + } + + bytesPerRow = ((hdrP->bits_per_pixel * hdrP->bm_width + 31) / 32) * 4; + MEMSZERO(alphas); + + for (row = 0, allOpaque = true, allTransparent = true; + hdrP->bm_height / 2 > row; + ++row) { + + uint32_t offset; + + if (hdrP->top_down) + offset = row * bytesPerRow; + else + offset = (hdrP->bm_height / 2 - row - 1) * bytesPerRow; + + if (offset + bytesPerRow <= truncatedXorSize) { + unsigned int col; + for (col = 0; col < hdrP->bm_width; ++col) { + uint32_t const pixel = u32_le(bitmapCursor, offset); + offset += bytesPerSample; + + tuples[row][col][PAM_RED_PLANE] = + pnm_scalesample((pixel & bitfields[RED]) >> shift[RED], + maxval[RED], 255); + tuples[row][col][PAM_GRN_PLANE] = + pnm_scalesample((pixel & bitfields[GRN]) >> shift[GRN], + maxval[GRN], 255); + tuples [row][col][PAM_BLU_PLANE] + = pnm_scalesample((pixel & bitfields[BLU]) >> shift[BLU], + maxval[BLU], 255); + + if (bitfields [ALPHA] != 0) { + tuples[row][col][PAM_TRN_PLANE] + = pnm_scalesample( + (pixel & bitfields[ALPHA]) >> shift[ALPHA], + maxval[ALPHA], 255); + + if (tuples[row][col][PAM_TRN_PLANE] != 0) + allTransparent = false; + + if (tuples [row][col][PAM_TRN_PLANE] != 255) + allOpaque = false; + + alphas[tuples[row][col][PAM_TRN_PLANE]] = !0; + } + } + } + } + + bitmapCursor += truncatedXorSize; + sizeRemaining -= truncatedXorSize; + bytesConsumed += truncatedXorSize; + + /* A fully transparent alpha channel (all zero) in XOR mask is + defined to be void by Microsoft, and a fully opaque alpha + channel (all maxval) is trivial and will be dropped. + */ + *haveAlphaP = !allTransparent && !allOpaque; + + if (!allTransparent && verbose) { + unsigned int i; + unsigned int c; + + for (i = 0, c = 0; 256 > i; ++i) { + if (alphas[i] != 0) + ++c; + } + pm_message("image %2u: %u distinct transparency value%s", + index, c, (c == 1) ? "": "s"); + } + *bytesConsumedP = bytesConsumed; +} + + + +static void +readAnd(struct BitmapInfoHeader * const hdrP, + const unsigned char * const bitmap, + uint32_t const maxSize, + tuple ** const tuples, + uint16_t const index, + unsigned int const plane, + sample const maxval) { + + int16_t row; + uint32_t bytesConsumed; + uint32_t bytesPerRow; + uint32_t sizeRemaining; + uint32_t truncatedAndSize; + + sizeRemaining = maxSize; /* initial value */ + bytesConsumed = 0; /* initial value */ + + { + uint32_t const andSize = (uint32_t) + (((1 * hdrP->bm_width + 31) / 32) * 4 * hdrP->bm_height / 2); + + if (sizeRemaining < andSize) { + pm_message ("image %2u: " + "Input image ends %u bytes into the %u-byte " + "AND mask. Implying remainder of mask", + index, sizeRemaining, andSize); + truncatedAndSize = sizeRemaining; + } else + truncatedAndSize = andSize; + } + + bytesPerRow = ((1 * hdrP->bm_width + 31) / 32) * 4; + + for (row = 0; row < hdrP->bm_height / 2; ++row) { + uint32_t offset; + + if (hdrP->top_down) + offset = row * bytesPerRow; + else + offset = (hdrP->bm_height / 2 - row - 1) * bytesPerRow; + + if (offset + bytesPerRow <= sizeRemaining) { + unsigned int col; + + for (col = 0; col < hdrP->bm_width; ++col) { + tuples[row][col][plane] = + ((u8_le(bitmap, offset + col/8) + & (1 << (7 - (col & 0x7)))) == 0x00) ? + maxval : 0 + ; + } + } + } + sizeRemaining -= truncatedAndSize; + bytesConsumed += truncatedAndSize; +} + + + +static void +dumpBmpHeader(struct BitmapInfoHeader const hdr, + unsigned int const imageIndex) { + + pm_message("BMP header for Image %u:", imageIndex); + + pm_message("header size: %u", hdr.header_size); + pm_message("bitmap width: %u", hdr.bm_width); + pm_message("bitmap height * 2: %u", hdr.bm_height); + pm_message("row order: %s", hdr.top_down ? "top down" : "bottom up"); + pm_message("# color planes: %u", hdr.color_planes); + pm_message("bits per pixel: %u", hdr.bits_per_pixel); + pm_message("image size: %u", hdr.image_size); + pm_message("horizontal resolution: %u", hdr.horizontal_resolution); + pm_message("vertical resolution: %u", hdr.vertical_resolution); + pm_message("# colors in palette: %u", hdr.colors_in_palette); + pm_message("# important colors: %u", hdr.important_colors); +} + + + +static void +readBmpHeader(const unsigned char * const image, + uint32_t const size, + unsigned int const imageIndex, + bool const needHeaderDump, + struct BitmapInfoHeader * const hdrP) { + + /* BITMAPINFOHEADER structure */ + + if (size < 40) + pm_error("image %2u: reading BITMAPINFOHEADER: not enough data.", + imageIndex); + + hdrP->header_size = u32_le(image, 0); + hdrP->bm_width = s32_le(image, 4); + hdrP->bm_height = s32_le(image, 8); + hdrP->color_planes = u16_le(image, 12); + hdrP->bits_per_pixel = u16_le(image, 14); + hdrP->compression_method = u32_le(image, 16); + hdrP->image_size = u32_le(image, 20); + hdrP->horizontal_resolution = s32_le(image, 24); + hdrP->vertical_resolution = s32_le(image, 28); + hdrP->colors_in_palette = u32_le(image, 32); + hdrP->important_colors = u32_le(image, 36); + + if (hdrP->bm_height > 0) { + hdrP->top_down = false; + } else { + hdrP->top_down = true; + hdrP->bm_height *= -1; + } + + if (hdrP->header_size < 36 + || hdrP->bm_width == 0 || hdrP->bm_height == 0 + || (hdrP->bm_height & 1) != 0x0000) { + pm_error("image %2u: format violation: invalid BMP header.", + imageIndex); + } + + if (needHeaderDump) + dumpBmpHeader(*hdrP, imageIndex); +} + + + +static void +readXorMask(struct BitmapInfoHeader * const hdrP, + const unsigned char * const imageCursor, + uint32_t const imageSize, + tuple ** const tuples, + uint16_t const index, + bool const needHeaderDump, + bool * const haveAlphaP, + uint32_t * const bytesConsumedP) { +/*---------------------------------------------------------------------------- + Read the so-called XOR mask (for non-monochrome images, this is the + color pixmap) +-----------------------------------------------------------------------------*/ + /* preset the PAM with fully opaque black (just in case the image + is truncated and not all pixels are filled in below). + */ + { + unsigned int row; + + for (row = 0; row < hdrP->bm_height / 2; ++row) { + unsigned int col; + for (col = 0; col < hdrP->bm_width; ++col) { + tuples[row][col][PAM_RED_PLANE] = 0; + tuples[row][col][PAM_GRN_PLANE] = 0; + tuples[row][col][PAM_BLU_PLANE] = 0; + tuples[row][col][PAM_TRN_PLANE] = 255; + } + } + } + + if (hdrP->bits_per_pixel < 16) { + readXorPalette(hdrP, imageCursor, imageSize, tuples, index, + needHeaderDump, + bytesConsumedP); + *haveAlphaP = false; + } else + readXorBitfields(hdrP, imageCursor, imageSize, tuples, index, + haveAlphaP, bytesConsumedP); +} + + + +static void +reportImage(unsigned int const imageIndex, + struct BitmapInfoHeader const hdr, + bool const haveAlpha) { + + const char * const style = + haveAlpha ? "RGB +alpha" : + hdr.bits_per_pixel < 16 ? "RGB/palette" : + "RGB" + ; + + pm_message("image %2u: " + "BMP %3u x %3u x %2u (%s)", + imageIndex, + hdr.bm_width, hdr.bm_height / 2, hdr.bits_per_pixel, + style); +} + + + +static void +convertBmp(const unsigned char * const image, + FILE * const ofP, + struct IconDirEntry * const dirEntryP, + bool const needHeaderDump, + bool const wantAndMaskPlane) { + + struct BitmapInfoHeader hdr; + uint32_t offset; + bool haveAlpha; + uint32_t xorByteCt; + + struct pam outpam; + tuple ** tuples; + + readBmpHeader(image, dirEntryP->size, dirEntryP->index, needHeaderDump, + &hdr); + + offset = hdr.header_size; /* Start after header */ + + if ((dirEntryP->width != hdr.bm_width) + || (dirEntryP->height != hdr.bm_height / 2)) { + pm_message("image %2u: " + "mismatch in header and image dimensions " + "(%u x %u vs. %u x %u)", + dirEntryP->index, + dirEntryP->width, + dirEntryP->height, + hdr.bm_width, + hdr.bm_height / 2); + } + + if ((dirEntryP->bits_per_pixel != 0) + && (dirEntryP->bits_per_pixel != hdr.bits_per_pixel)) { + pm_message("image %2u " + "mismatch in header and image bpp value" + "(%u vs. %u)", + dirEntryP->index, + dirEntryP->bits_per_pixel, + hdr.bits_per_pixel); + } + + outpam.size = sizeof(struct pam); + outpam.len = PAM_STRUCT_SIZE(allocation_depth); + outpam.file = ofP; + outpam.format = PAM_FORMAT; + outpam.width = hdr.bm_width; + outpam.height = hdr.bm_height / 2; + outpam.maxval = 255; + outpam.allocation_depth = 5; + outpam.depth = 0; + /* Just for tuple array allocation; we set the value for the actual + output image below. + */ + + tuples = pnm_allocpamarray(&outpam); + + readXorMask(&hdr, &image[offset], + dirEntryP->size - offset, + tuples, dirEntryP->index, needHeaderDump, + &haveAlpha, &xorByteCt); + + offset += xorByteCt; + + { + /* If there is no alpha channel in XOR mask, store the AND mask to + the transparency plane. Else, here are two transparency + maps. If requested, store the AND mask to a fifth PAM plane + */ + bool haveAnd; + unsigned int andPlane; + + if (!haveAlpha) { + haveAnd = true; + andPlane = PAM_TRN_PLANE; + strcpy (outpam.tuple_type, "RGB_ALPHA"); + outpam.depth = 4; + } else if (wantAndMaskPlane) { + haveAnd = true; + andPlane = PAM_TRN_PLANE + 1; + outpam.depth = 5; + strcpy(outpam.tuple_type, "RGB_ALPHA_ANDMASK"); + } else { + haveAnd = false; + strcpy (outpam.tuple_type, "RGB_ALPHA"); + outpam.depth = 4; + } + if (haveAnd) { + readAnd(&hdr, &image[offset], dirEntryP->size - offset, + tuples, dirEntryP->index, andPlane, outpam.maxval); + } + } + pnm_writepam(&outpam, tuples); + pnm_freepamarray(tuples, &outpam); + + reportImage(dirEntryP->index, hdr, haveAlpha); +} + + + +static void +reportPngInfo(const unsigned char * const image, + struct IconDirEntry * const dirEntryP) { + + struct PngIhdr ihdr; + + ihdr.length = u32_be (image, sizeof(pngHeader) +0); + ihdr.signature = u32_xx (image, sizeof(pngHeader) +4); + ihdr.width = u32_be (image, sizeof(pngHeader) +8); + ihdr.height = u32_be (image, sizeof(pngHeader) +12); + ihdr.bit_depth = u8_be (image, sizeof(pngHeader) +16); + ihdr.color_type = u8_be (image, sizeof(pngHeader) +17); + ihdr.compression = u8_be (image, sizeof(pngHeader) +18); + ihdr.filter = u8_be (image, sizeof(pngHeader) +19); + ihdr.interlace = u8_be (image, sizeof(pngHeader) +20); + + if ((ihdr.length != 13) + || ihdr.signature != *(uint32_t*)"IHDR") { + pm_message("image %2u: PNG (uncommonly formatted)", + dirEntryP->index); + } else { + uint32_t depth; + const char * colorType; + + switch (ihdr.color_type) { + case 0: + colorType = "grayscale"; + depth = ihdr.bit_depth; + break; + + case 2: + colorType = "RGB"; + depth = ihdr.bit_depth * 3; + break; + + case 3: + colorType = "RGB/palette"; + depth = 8; + break; + + case 4: + colorType = "grayscale + alpha"; + depth = ihdr.bit_depth * 2; + break; + + case 6: + colorType = "RGB + alpha"; + depth = ihdr.bit_depth * 4; + break; + + default: + colorType = "unknown color system"; + depth = 0; + break; + } + pm_message("image %2u: PNG %3u x %3u x %2u (%s)", + dirEntryP->index, + ihdr.width, ihdr.height, depth, colorType); + + if ((dirEntryP->width != ihdr.width) + || (dirEntryP->height != ihdr.height)) { + pm_message("image %2u:" + " mismatch in header and image dimensions" + " (%u x %u vs %u x %u)", + dirEntryP->index, dirEntryP->width, dirEntryP->height, + ihdr.width, ihdr.height); + } + /* Mismatch between dirEntryP->bits_per_pixel and 'depth' is + normal, because the creator of the winicon file doesn't necessarily + know the true color resolution. + */ + } +} + + + +static void +convertPng(const unsigned char * const image, + FILE * const ofP, + struct IconDirEntry * const dirEntryP) { + + struct bufferDesc imageBuffer; + + reportPngInfo(image, dirEntryP); + + imageBuffer.size = dirEntryP->size; + imageBuffer.buffer = (unsigned char *)image; + + fflush (stdout); + pm_system(pm_feed_from_memory, &imageBuffer, + NULL /* stdout accepter */, NULL, + "pngtopam -alphapam"); +} + + + +static uint32_t +bestImage(struct IconDir * const dirP) { + + uint32_t imageIndex; + uint32_t bestPixelCt; + uint32_t bestColorCt; + uint16_t best; + + bestPixelCt = 0; /* initial value */ + bestColorCt = 0; /* initial value */ + best = 0; /* initial value */ + + for (imageIndex = 0; dirP->count > imageIndex; ++imageIndex) { + struct IconDirEntry * const dirEntryP = &dirP->entries[imageIndex]; + + uint32_t const pixelCt = dirEntryP->width * dirEntryP->height; + + uint32_t colorCt; + + /* 32-bit icons have 24 bit color information only. + + Since NT 5.1 (aka WinXP), it is allowed to place 8-bit + transparency information in the remaining bits (to check, + you have to read all these bits in the image!), so I prefer + 32-bit images over 24-bit images (which violate the + spec. anyway). + */ + if (dirEntryP->bits_per_pixel > 24) + colorCt = 1u << 25; + else + colorCt = 1u << dirEntryP->bits_per_pixel; + + if (dirEntryP->color_count != 0 && colorCt > dirEntryP->color_count) + colorCt = dirEntryP->color_count; + + if ((pixelCt > bestPixelCt) + || ((pixelCt == bestPixelCt) && (colorCt > bestColorCt))) { + /* This is a new best */ + bestPixelCt = pixelCt; + bestColorCt = colorCt; + best = imageIndex; + } + } + return best; +} + + + +static void +convertImage(struct File * const icoP, + struct IconDirEntry * const dirEntryP, + FILE * const ofP, + bool const needHeaderDump, + bool const wantAndMaskPlane) { + + const unsigned char * image; /* malloced */ + + image = readImage(icoP, dirEntryP); + + if (MEMEQ(image, pngHeader, sizeof (pngHeader))) + convertPng(image, ofP, dirEntryP); + else + convertBmp(image, ofP, dirEntryP, needHeaderDump, wantAndMaskPlane); + + free((void *)image); +} + + + +int +main (int argc, const char *argv []) { + + struct File ico; + struct IconDir * dirP; + struct CmdlineInfo cmdline; + + pm_proginit (&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + verbose = cmdline.verbose; + + ico.name = + streq(cmdline.inputFileName, "-") ? "" : cmdline.inputFileName; + ico.pos = 0; + ico.fileP = pm_openr(cmdline.inputFileName); + + dirP = readIconDir(&ico, cmdline.headerdump); + + if (cmdline.allimages) { + unsigned int i; + for (i = 0; i < dirP->count; ++i) + convertImage(&ico, &dirP->entries[i], stdout, + cmdline.headerdump, cmdline.andmasks); + } else if (cmdline.imageSpec) { + unsigned int i; + bool found; + for (i = 0, found = false; i < dirP->count; ++i) { + if (dirP->entries[i].index == cmdline.image) { + found = true; + convertImage(&ico, &dirP->entries[i], stdout, + cmdline.headerdump, cmdline.andmasks); + } + } + if (!found) + pm_error("no image index %u in.input", cmdline.image); + } else { + convertImage(&ico, &dirP->entries[bestImage(dirP)], stdout, + cmdline.headerdump, cmdline.andmasks); + } + + freeIconDir(dirP); + + if (ico.fileP != stdin) + pm_close(ico.fileP); + + return 0; +} + + + diff --git a/converter/other/xwdtopnm.c b/converter/other/xwdtopnm.c index 2cf1d39b..d49a2b09 100644 --- a/converter/other/xwdtopnm.c +++ b/converter/other/xwdtopnm.c @@ -113,7 +113,7 @@ parseCommandLine(int argc, char ** argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We may have parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (argc - 1 == 0) @@ -837,7 +837,7 @@ typedef struct { 'nBitsLeft' tells how many bits are in the buffer now. It's zero when nothing has ever been read from the file. Only - the least signficant 'nBitsLeft' bits are meaningful. + the least significant 'nBitsLeft' bits are meaningful. The numeric value of the member is the number whose pure binary representation is the bit string in the buffer. @@ -974,7 +974,7 @@ readItem(pixelReader * const rdrP) { static unsigned long const lsbmask[] = { /*---------------------------------------------------------------------------- - lsbmask[i] is the mask you use to select the i least signficant bits + lsbmask[i] is the mask you use to select the i least significant bits of a bit string. -----------------------------------------------------------------------------*/ 0x00000000, diff --git a/converter/other/yuy2topam.c b/converter/other/yuy2topam.c new file mode 100644 index 00000000..40ab98b3 --- /dev/null +++ b/converter/other/yuy2topam.c @@ -0,0 +1,266 @@ +/* Convert an YUY2 image to a PAM image + * + * See + * http://msdn.microsoft.com/en-us/library/aa904813%28VS.80%29.aspx#yuvformats_2 + * and http://www.digitalpreservation.gov/formats/fdd/fdd000364.shtml for + * details. + * + * By Michael Haardt 2014. + * + * Contributed to the public domain by its author. + * + * Recoded in Netpbm style by Bryan Henderson + */ + +#include +#include + +#include "pm_c_util.h" +#include "mallocvar.h" +#include "pm.h" +#include "pam.h" +#include "shhopt.h" + + + +struct CmdlineInfo { + const char * inputFileName; + unsigned int width; + unsigned int height; +}; + + + +static void +parseCommandLine(int argc, const char ** argv, + struct CmdlineInfo * const cmdlineP) { +/* -------------------------------------------------------------------------- + Parse program command line described in Unix standard form by argc + and argv. Return the information in the options as *cmdlineP. + + If command line is internally inconsistent (invalid options, etc.), + issue error message to stderr and abort program. + + Note that the strings we return are stored in the storage that + was passed to us as the argv array. We also trash *argv. +--------------------------------------------------------------------------*/ + optEntry * option_def; + /* Instructions to pm_optParseOptions3 on how to parse our options. */ + optStruct3 opt; + + unsigned int widthSpec, heightSpec; + unsigned int option_def_index; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENT3 */ + OPTENT3(0, "width", OPT_UINT, + &cmdlineP->width, &widthSpec, 0); + OPTENT3(0, "height", OPT_UINT, + &cmdlineP->height, &heightSpec, 0); + + opt.opt_table = option_def; + opt.short_allowed = false; /* We have no short (old-fashioned) options */ + opt.allowNegNum = false; /* We have no parms that are negative numbers */ + + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + if (!widthSpec) + pm_error("You must specify the image width with -width"); + if (cmdlineP->width == 0) + pm_error("-width cannot be zero"); + + if (cmdlineP->width % 2 != 0) + pm_error("-width %u is odd, but YUY2 images must have an even width.", + cmdlineP->width); + + if (!heightSpec) + pm_error("You must specify the image height with -height"); + if (cmdlineP->height == 0) + pm_error("-height cannot be zero"); + + if (argc-1 < 1) + cmdlineP->inputFileName = "-"; + else { + cmdlineP->inputFileName = argv[1]; + + if (argc-1 > 1) + pm_error("Too many arguments (%u). The only non-option argument " + "is the input file name.", argc-1); + } +} + + + +typedef struct { + int y0; + int y1; + int u; + int v; +} Yuy2Pixel; + + + +static Yuy2Pixel +readPixel(FILE * const ifP) { +/*---------------------------------------------------------------------------- + Read one pixel from the YUY2 input. YUY2 represents a pixel in 4 bytes. +-----------------------------------------------------------------------------*/ + Yuy2Pixel retval; + unsigned char c; + + pm_readcharu(ifP, &c); retval.y0 = c - 16; + pm_readcharu(ifP, &c); retval.u = c - 128; + pm_readcharu(ifP, &c); retval.y1 = c - 16; + pm_readcharu(ifP, &c); retval.v = c - 128; + + return retval; +} + + + +typedef struct { + int a1; + int a2; + int a3; + int a4; +} UvCoeff; + +typedef struct { + int a0a; + int a0b; + UvCoeff uv; +} Coeff; + + + +static Coeff +coeffFromYuy2(Yuy2Pixel const yuy2) { + + Coeff retval; + + retval.a0a = 298 * yuy2.y0; + retval.a0b = 298 * yuy2.y1; + retval.uv.a1 = 409 * yuy2.v; + retval.uv.a2 = 100 * yuy2.u; + retval.uv.a3 = 208 * yuy2.v; + retval.uv.a4 = 516 * yuy2.u; + + return retval; +} + + + +typedef struct { + int r; + int g; + int b; +} Rgb; + + + +static Rgb +rgbFromCoeff(int const a0, + UvCoeff const uv) { + + Rgb retval; + + retval.r = (a0 + uv.a1 + 128) >> 8; + retval.g = (a0 - uv.a2 - uv.a3 + 128) >> 8; + retval.b = (a0 + uv.a4 + 128) >> 8; + + return retval; +} + + + +static Rgb +rgbFromCoeff0(Coeff const coeff) { + + return rgbFromCoeff(coeff.a0a, coeff.uv); +} + + + +static Rgb +rgbFromCoeff1(Coeff const coeff) { + + return rgbFromCoeff(coeff.a0b, coeff.uv); +} + + + +static void +rgbToTuple(Rgb const rgb, + tuple const out) { + + out[PAM_RED_PLANE] = MIN(255, MAX(0, rgb.r)); + out[PAM_GRN_PLANE] = MIN(255, MAX(0, rgb.g)); + out[PAM_BLU_PLANE] = MIN(255, MAX(0, rgb.b)); +} + + + +static void +yuy2topam(const char * const fileName, + unsigned int const width, + unsigned int const height) { + + FILE * ifP; + struct pam outpam; + tuple * tuplerow; + unsigned int row; + + outpam.size = sizeof(struct pam); + outpam.len = PAM_STRUCT_SIZE(allocation_depth); + outpam.file = stdout; + outpam.format = PAM_FORMAT; + outpam.plainformat = 0; + outpam.width = width; + outpam.height = height; + outpam.depth = 3; + outpam.maxval = 255; + outpam.bytes_per_sample = 1; + strcpy(outpam.tuple_type, PAM_PPM_TUPLETYPE); + outpam.allocation_depth = 3; + + ifP = pm_openr(fileName); + + pnm_writepaminit(&outpam); + + tuplerow = pnm_allocpamrow(&outpam); + + for (row = 0; row < outpam.height; ++row) { + unsigned int col; + + for (col = 0; col < outpam.width; col += 2) { + Yuy2Pixel const yuy2 = readPixel(ifP); + + Coeff const coeff = coeffFromYuy2(yuy2); + + rgbToTuple(rgbFromCoeff0(coeff), tuplerow[col]); + rgbToTuple(rgbFromCoeff1(coeff), tuplerow[col+1]); + } + pnm_writepamrow(&outpam, tuplerow); + } + pnm_freepamrow(tuplerow); + + pm_closer(ifP); +} + + + +int +main(int argc, const char *argv[]) { + + struct CmdlineInfo cmdline; + + pm_proginit(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + yuy2topam(cmdline.inputFileName, cmdline.width, cmdline.height); + + return 0; +} diff --git a/converter/pbm/Makefile b/converter/pbm/Makefile index c859b105..602cb156 100644 --- a/converter/pbm/Makefile +++ b/converter/pbm/Makefile @@ -7,12 +7,13 @@ VPATH=.:$(SRCDIR)/$(SUBDIR) include $(BUILDDIR)/config.mk -PORTBINARIES = atktopbm brushtopbm cmuwmtopbm ddbugtopbm g3topbm escp2topbm \ - icontopbm macptopbm mdatopbm mgrtopbm mrftopbm \ +PORTBINARIES = atktopbm brushtopbm cistopbm cmuwmtopbm \ + ddbugtopbm g3topbm escp2topbm \ + macptopbm mdatopbm mgrtopbm mrftopbm \ pbmto10x pbmto4425 pbmtoascii pbmtoatk \ - pbmtobbnbg pbmtocmuwm pbmtodjvurle \ + pbmtobbnbg pbmtocis pbmtocmuwm pbmtodjvurle \ pbmtoepsi pbmtoepson pbmtoescp2 \ - pbmtog3 pbmtogem pbmtogo pbmtoibm23xx pbmtoicon pbmtolj \ + pbmtog3 pbmtogem pbmtogo pbmtoibm23xx pbmtosunicon pbmtolj \ pbmtoln03 pbmtolps \ pbmtomacp pbmtomatrixorbital pbmtomda pbmtomgr pbmtomrf \ pbmtonokia \ @@ -72,6 +73,14 @@ thinkjettopbm.c:%.c:%.c1 $(SRCDIR)/lib/util/lexheader grep -v "^[[:space:]]*int yywrap(void);" \ >$@ +install.bin: install.bin.local +.PHONY: install.bin.local +install.bin.local: $(PKGDIR)/bin +# Remember that $(SYMLINK) might just be a copy command. +# In December 2010 (Actually January 2011), pbmtosunicon replaced pbmtoicon + cd $(PKGDIR)/bin ; \ + $(SYMLINK) pbmtosunicon$(EXE) pbmtoicon$(EXE) + thisdirclean: localclean .PHONY: localclean localclean: diff --git a/converter/pbm/atktopbm.c b/converter/pbm/atktopbm.c index 62664999..807e4f4a 100644 --- a/converter/pbm/atktopbm.c +++ b/converter/pbm/atktopbm.c @@ -61,17 +61,24 @@ */ /* macros to generate case entries for switch statement */ -#define case1(v) case v -#define case4(v) case v: case (v)+1: case (v)+2: case(v)+3 -#define case6(v) case4(v): case ((v)+4): case ((v)+5) -#define case8(v) case4(v): case4((v)+4) +#define CASE1(v) case v +#define CASE4(v) case v: case (v)+1: case (v)+2: case(v)+3 +#define CASE6(v) CASE4(v): case ((v)+4): case ((v)+5) +#define CASE8(v) CASE4(v): CASE4((v)+4) + + static long -ReadRow(FILE * const file, unsigned char * const row, long const length) { +ReadRow(FILE * const file, + unsigned char * const row, + long const length) { /*---------------------------------------------------------------------------- 'file' is where to get them from. 'row' is where to put bytes. 'length' is how many bytes in row must be filled. + + Return the delimiter that marks the end of the row, or EOF if EOF marks + the end of the row, or NUL in some cases. -----------------------------------------------------------------------------*/ /* Each input character is processed by the central loop. There are ** some input codes which require two or three characters for @@ -80,18 +87,23 @@ ReadRow(FILE * const file, unsigned char * const row, long const length) { ** to the Ready state whenever a character unacceptable to the ** current state is read. */ - enum stateCode { - Ready, /* any input code is allowed */ - HexDigitPending, /* have seen the first of a hex digit pair */ - RepeatPending, /* repeat code has been seen: - must be followed by two hex digits */ - RepeatAndDigit}; /* have seen repeat code and its first - following digit */ - enum stateCode InputState; /* current state */ - register int c; /* the current input character */ - register long repeatcount = 0; /* current repeat value */ - register long hexval; /* current hex value */ - long pendinghex = 0; /* the first of a pair of hex characters */ + enum StateCode { + Ready, + /* any input code is allowed */ + HexDigitPending, + /* have seen the first of a hex digit pair */ + RepeatPending, + /* repeat code has been seen: must be followed by two hex digits + */ + RepeatAndDigit + /* have seen repeat code and its first following digit */ + }; + + enum StateCode InputState; /* current state */ + int c; /* the current input character */ + long repeatcount; /* current repeat value */ + long hexval; /* current hex value */ + long pendinghex; /* the first of a pair of hex characters */ int lengthRemaining; unsigned char * cursor; @@ -101,262 +113,239 @@ ReadRow(FILE * const file, unsigned char * const row, long const length) { ** zero, we ungetc the byte. */ - lengthRemaining = length; - cursor = row; + repeatcount = 0; /* initial value */ + pendinghex = 0; /* initial value */ + + lengthRemaining = length; /* initial value */ + cursor = row; /* initial value */ + InputState = Ready; /* initial value */ - InputState = Ready; while ((c=getc(file)) != EOF) switch (c) { - case8(0x0): - case8(0x8): - case8(0x10): - case8(0x18): - case1(' '): - /* control characters and space are legal and ignored */ - break; - case1(0x40): /* '@' */ - case1(0x5B): /* '[' */ - case4(0x5D): /* ']' '^' '_' '`' */ - case4(0x7D): /* '}' '~' DEL 0x80 */ - default: /* all above 0x80 */ - /* error code: Ignored at present. Reset InputState. */ - InputState = Ready; - break; - - case1(0x7B): /* '{' */ - case1(0x5C): /* '\\' */ - /* illegal end of line: exit anyway */ - ungetc(c, file); /* retain terminator in stream */ - /* DROP THROUGH */ - case1(0x7C): /* '|' */ - /* legal end of row: may have to pad */ - while (lengthRemaining-- > 0) - *cursor++ = WHITEBYTE; - return c; + CASE8(0x0): + CASE8(0x8): + CASE8(0x10): + CASE8(0x18): + CASE1(' '): + /* control characters and space are legal and ignored */ + break; + CASE1(0x40): /* '@' */ + CASE1(0x5B): /* '[' */ + CASE4(0x5D): /* ']' '^' '_' '`' */ + CASE4(0x7D): /* '}' '~' DEL 0x80 */ + default: /* all above 0x80 */ + /* error code: Ignored at present. Reset InputState. */ + InputState = Ready; + break; + + CASE1(0x7B): /* '{' */ + CASE1(0x5C): /* '\\' */ + /* illegal end of line: exit anyway */ + ungetc(c, file); /* retain terminator in stream */ + /* DROP THROUGH */ + CASE1(0x7C): /* '|' */ + /* legal end of row: may have to pad */ + while (lengthRemaining-- > 0) + *cursor++ = WHITEBYTE; + return c; - case1(0x21): - case6(0x22): - case8(0x28): - /* punctuation characters: repeat byte given by two - ** succeeding hex chars - */ - if (lengthRemaining <= 0) { - ungetc(c, file); - return('\0'); - } - repeatcount = c - OTHERZERO; - InputState = RepeatPending; - break; - - case8(0x30): - case8(0x38): - /* digit (or following punctuation) - hex digit */ - hexval = c - 0x30; - goto hexdigit; - case6(0x41): - /* A ... F - hex digit */ - hexval = c - (0x41 - 0xA); - goto hexdigit; - case6(0x61): - /* a ... f - hex digit */ - hexval = c - (0x61 - 0xA); - goto hexdigit; - - case8(0x67): - case8(0x6F): - case4(0x77): - /* g ... z - multiple WHITE bytes */ - if (lengthRemaining <= 0) { - ungetc(c, file); - return('\0'); - } - repeatcount = c - WHITEZERO; - hexval = WHITEBYTE; - goto store; - case8(0x47): - case8(0x4F): - case4(0x57): - /* G ... Z - multiple BLACK bytes */ - if (lengthRemaining <= 0) { - ungetc(c, file); - return('\0'); - } - repeatcount = c - BLACKZERO; - hexval = BLACKBYTE; - goto store; - -hexdigit: - /* process a hex digit. Use InputState to determine - what to do with it. */ - if (lengthRemaining <= 0) { - ungetc(c, file); - return('\0'); - } - switch(InputState) { - case Ready: - InputState = HexDigitPending; - pendinghex = hexval << 4; + CASE1(0x21): + CASE6(0x22): + CASE8(0x28): + /* punctuation characters: repeat byte given by two + ** succeeding hex chars + */ + if (lengthRemaining <= 0) { + ungetc(c, file); + return('\0'); + } + repeatcount = c - OTHERZERO; + InputState = RepeatPending; break; - case HexDigitPending: - hexval |= pendinghex; - repeatcount = 1; + + CASE8(0x30): + CASE8(0x38): + /* digit (or following punctuation) - hex digit */ + hexval = c - 0x30; + goto hexdigit; + CASE6(0x41): + /* A ... F - hex digit */ + hexval = c - (0x41 - 0xA); + goto hexdigit; + CASE6(0x61): + /* a ... f - hex digit */ + hexval = c - (0x61 - 0xA); + goto hexdigit; + + CASE8(0x67): + CASE8(0x6F): + CASE4(0x77): + /* g ... z - multiple WHITE bytes */ + if (lengthRemaining <= 0) { + ungetc(c, file); + return('\0'); + } + repeatcount = c - WHITEZERO; + hexval = WHITEBYTE; goto store; - case RepeatPending: - InputState = RepeatAndDigit; - pendinghex = hexval << 4; - break; - case RepeatAndDigit: - hexval |= pendinghex; + CASE8(0x47): + CASE8(0x4F): + CASE4(0x57): + /* G ... Z - multiple BLACK bytes */ + if (lengthRemaining <= 0) { + ungetc(c, file); + return('\0'); + } + repeatcount = c - BLACKZERO; + hexval = BLACKBYTE; goto store; - } - break; - -store: - /* generate byte(s) into the output row - Use repeatcount, depending on state. */ - if (lengthRemaining < repeatcount) - /* reduce repeat count if it would exceed - available space */ - repeatcount = lengthRemaining; - lengthRemaining -= repeatcount; /* do this before repeatcount-- */ - while (repeatcount-- > 0) + + hexdigit: + /* process a hex digit. Use InputState to determine + what to do with it. */ + if (lengthRemaining <= 0) { + ungetc(c, file); + return('\0'); + } + switch(InputState) { + case Ready: + InputState = HexDigitPending; + pendinghex = hexval << 4; + break; + case HexDigitPending: + hexval |= pendinghex; + repeatcount = 1; + goto store; + case RepeatPending: + InputState = RepeatAndDigit; + pendinghex = hexval << 4; + break; + case RepeatAndDigit: + hexval |= pendinghex; + goto store; + } + break; + + store: + /* generate byte(s) into the output row + Use repeatcount, depending on state. */ + if (lengthRemaining < repeatcount) + /* reduce repeat count if it would exceed + available space */ + repeatcount = lengthRemaining; + lengthRemaining -= repeatcount; /* do this before repeatcount-- */ + while (repeatcount-- > 0) *cursor++ = hexval; - InputState = Ready; - break; + InputState = Ready; + break; - } /* end of while( - )switch( - ) */ + } /* end of while( - )switch( - ) */ return EOF; } -#undef case1 -#undef case4 -#undef case6 -#undef case8 +#undef CASE1 +#undef CASE4 +#undef CASE6 +#undef CASE8 static void -ReadATKRaster(FILE * const file, - int * const rwidth, - int * const rheight, - unsigned char ** const destaddrP) { +ReadATKRaster(FILE * const ifP) { - int row, rowlen; /* count rows; byte length of row */ + int row; /* count rows; byte length of row */ int version; char keyword[6]; int discardid; int objectid; /* id read for the incoming pixel image */ long tc; /* temp */ int width, height; /* dimensions of image */ + bit * bitrow; - if (fscanf(file, "\\begindata{raster,%d", &discardid) != 1 - || getc(file) != '}' || getc(file) != '\n') - pm_error ("input file not Andrew raster object"); + if (fscanf(ifP, "\\begindata{raster,%d", &discardid) != 1 + || getc(ifP) != '}' || getc(ifP) != '\n') + pm_error ("input file not Andrew raster object"); - fscanf(file, " %d ", &version); + fscanf(ifP, " %d ", &version); if (version < 2) - pm_error ("version too old to parse"); + pm_error ("version too old to parse"); { unsigned int options; long xscale, yscale; long xoffset, yoffset, subwidth, subheight; /* ignore all these features: */ - fscanf(file, " %u %ld %ld %ld %ld %ld %ld", + fscanf(ifP, " %u %ld %ld %ld %ld %ld %ld", &options, &xscale, &yscale, &xoffset, &yoffset, &subwidth, &subheight); } /* scan to end of line in case this is actually something beyond V2 */ - while (((tc=getc(file)) != '\n') && (tc != '\\') && (tc != EOF)) {} + while (((tc=getc(ifP)) != '\n') && (tc != '\\') && (tc != EOF)) {} /* read the keyword */ - fscanf(file, " %5s", keyword); + fscanf(ifP, " %5s", keyword); if (!streq(keyword, "bits")) - pm_error ("keyword is not 'bits'!"); + pm_error ("keyword is not 'bits'!"); - fscanf(file, " %d %d %d ", &objectid, &width, &height); + fscanf(ifP, " %d %d %d ", &objectid, &width, &height); if (width < 1 || height < 1 || width > 1000000 || height > 1000000) - pm_error ("bad width or height"); - - *rwidth = width; - *rheight = height; - rowlen = (width + 7) / 8; - MALLOCARRAY(*destaddrP, height * rowlen); - if (destaddrP == NULL) - pm_error("Unable to allocate %u bytes for the input image.", - height * rowlen); - for (row = 0; row < height; row++) - { - long c; - - c = ReadRow(file, *destaddrP + (row * rowlen), rowlen); - if (c != '|') - { - if (c == EOF) - pm_error ("premature EOF"); - else - pm_error ("bad format"); - break; - } - } - while (! feof(file) && getc(file) != '\\') {}; /* scan for \enddata */ - if (fscanf(file, "enddata{raster,%d", &discardid) != 1 - || getc(file) != '}' || getc(file) != '\n') - pm_error ("missing end-of-object marker"); -} + pm_error("bad width or height"); + pbm_writepbminit(stdout, width, height, 0); + bitrow = pbm_allocrow_packed(width); + for (row = 0; row < height; ++row) { + unsigned int const rowlen = (width + 7) / 8; + long const nextChar = ReadRow(ifP, bitrow, rowlen); -int -main(int argc, char **argv) { + switch (nextChar) { + case '|': + pbm_writepbmrow_packed(stdout, bitrow, width, 0); + break; + case EOF: + pm_error("premature EOF"); + break; + default: + pm_error("bad format"); + } + } - FILE *ifp; - register bit *bitrow, *bP; - int rows, cols, row, col, charcount; - unsigned char *data, mask; + pbm_freerow_packed(bitrow); + while (! feof(ifP) && getc(ifP) != '\\') {}; /* scan for \enddata */ - pbm_init ( &argc, argv ); + if (fscanf(ifP, "enddata{raster,%d", &discardid) != 1 + || getc(ifP) != '}' || getc(ifP) != '\n') + pm_error("missing end-of-object marker"); +} - if ( argc > 2 ) - pm_usage( "[raster obj]" ); - - if ( argc == 2 ) - ifp = pm_openr( argv[1] ); - else - ifp = stdin; - ReadATKRaster( ifp, &cols, &rows, &data ); - pm_close( ifp ); +int +main(int argc, const char ** argv) { - pbm_writepbminit( stdout, cols, rows, 0 ); - bitrow = pbm_allocrow( cols ); + FILE * ifP; - for ( row = 0; row < rows; ++row ) - { - charcount = 0; - mask = 0x80; - for ( col = 0, bP = bitrow; col < cols; ++col, ++bP ) - { - if ( charcount >= 8 ) - { - ++data; - charcount = 0; - mask = 0x80; - } - *bP = ( *data & mask ) ? PBM_BLACK : PBM_WHITE; - ++charcount; - mask >>= 1; - } - ++data; - pbm_writepbmrow( stdout, bitrow, cols, 0 ); + pm_proginit(&argc, argv); + + if (argc-1 < 1) + ifP = stdin; + else { + ifP = pm_openr(argv[1]); + + if (argc-1 > 1) + pm_error("Too many arguments. The only possible argument is " + "the input file name"); } - pm_close( stdout ); - exit( 0 ); -} + ReadATKRaster(ifP); + + pm_close(ifP); + pm_close(stdout); + + return 0; +} diff --git a/converter/pbm/brushtopbm.c b/converter/pbm/brushtopbm.c index 0cffaa4d..ebd817be 100644 --- a/converter/pbm/brushtopbm.c +++ b/converter/pbm/brushtopbm.c @@ -1,4 +1,4 @@ -/* brushtopbm.c - read a doodle brush file and write a portable bitmap +/* brushtopbm.c - read a doodle brush file and write a PBM image ** ** Copyright (C) 1988 by Jef Poskanzer. ** @@ -12,96 +12,96 @@ #include "pbm.h" -static void getinit ARGS(( FILE* file, int* colsP, int* rowsP )); -static bit getbit ARGS(( FILE* file )); +#define HEADERSIZE 16 /* 16 is just a guess at the header size */ -int -main( argc, argv ) - int argc; - char* argv[]; - { - FILE* ifp; - bit* bitrow; - register bit* bP; - int rows, cols, padright, row, col; - - - pbm_init( &argc, argv ); - - if ( argc > 2 ) - pm_usage( "[brushfile]" ); - - if ( argc == 2 ) - ifp = pm_openr( argv[1] ); - else - ifp = stdin; - - getinit( ifp, &cols, &rows ); - - pbm_writepbminit( stdout, cols, rows, 0 ); - bitrow = pbm_allocrow( cols ); - - /* Compute padding to round cols up to the next multiple of 16. */ - padright = ( ( cols + 15 ) / 16 ) * 16 - cols; - - for ( row = 0; row < rows; ++row ) - { - /* Get data. */ - for ( col = 0, bP = bitrow; col < cols; ++col, ++bP ) - *bP = getbit( ifp ); - /* Discard line padding. */ - for ( col = 0; col < padright; ++col ) - (void) getbit( ifp ); - /* Write row. */ - pbm_writepbmrow( stdout, bitrow, cols, 0 ); - } - - pm_close( ifp ); - pm_close( stdout ); - - exit( 0 ); - } -static int item, bitsperitem, bitshift; +static void +getinit(FILE * const ifP, + unsigned int * const colsP, + unsigned int * const rowsP) { + + unsigned char header[HEADERSIZE]; + size_t bytesRead; + + bytesRead = fread(header, sizeof(header), 1, ifP); + if (bytesRead !=1) + pm_error("Error reading header"); + + if (header[0] != 1) + pm_error("bad magic number 1"); + if (header[1] != 0) + pm_error("bad magic number 2"); + + *colsP = (header[2] << 8) + header[3]; /* Max 65535 */ + *rowsP = (header[4] << 8) + header[5]; /* Max 65535 */ +} + + static void -getinit( file, colsP, rowsP ) - FILE* file; - int* colsP; - int* rowsP; - { - int i; - - if ( getc( file ) != 1 ) - pm_error( "bad magic number 1" ); - if ( getc( file ) != 0 ) - pm_error( "bad magic number 2" ); - *colsP = getc( file ) << 8; - *colsP += getc( file ); - *rowsP = getc( file ) << 8; - *rowsP += getc( file ); - bitsperitem = 8; - - /* Junk rest of header. */ - for ( i = 0; i < 10; ++i ) /* 10 is just a guess at the header size */ - (void) getc( file ); - } +validateEof(FILE * const ifP) { + + int rc; + rc = getc(ifP); + if (rc != EOF) + pm_message("Extraneous data at end of file"); +} + + +/* + The routine for converting the raster closely resembles the pbm + case of pnminvert. Input is padded up to 16 bit border. + afu December 2013 + */ + + -static bit -getbit( file ) - FILE* file; - { - bit b; - - if ( bitsperitem == 8 ) - { - item = getc( file ); - bitsperitem = 0; - bitshift = 7; - } - ++bitsperitem; - b = ( ( item >> bitshift) & 1 ) ? PBM_WHITE : PBM_BLACK; - --bitshift; - return b; +int +main(int argc, const char ** argv) { + + FILE * ifP; + bit * bitrow; + unsigned int rows, cols, row; + + pm_proginit(&argc, argv); + + if (argc-1 > 0) { + ifP = pm_openr(argv[1]); + if (argc-1 > 1) + pm_error("Too many arguments (%u). " + "The only argument is the brush file name.", argc-1); + } else + ifP = stdin; + + getinit(ifP, &cols, &rows); + + pbm_writepbminit(stdout, cols, rows, 0); + + bitrow = pbm_allocrow_packed(cols + 16); + + for (row = 0; row < rows; ++row) { + unsigned int const inRowBytes = ((cols + 15) / 16) * 2; + unsigned int i; + size_t bytesRead; + + bytesRead = fread (bitrow, 1, inRowBytes, ifP); + if (bytesRead != inRowBytes) + pm_error("Error reading a row of data from brushfile"); + + for (i = 0; i < inRowBytes; ++i) + bitrow[i] = ~bitrow[i]; + + /* Clean off remainder of fractional last character */ + pbm_cleanrowend_packed(bitrow, cols); + + pbm_writepbmrow_packed(stdout, bitrow, cols, 0); } + + validateEof(ifP); + + pm_close(ifP); + pm_close(stdout); + + return 0; +} diff --git a/converter/pbm/cistopbm.c b/converter/pbm/cistopbm.c new file mode 100644 index 00000000..591e2aa5 --- /dev/null +++ b/converter/pbm/cistopbm.c @@ -0,0 +1,180 @@ +/* + * cistopbm: Convert images in the CompuServe RLE format to PBM + * Copyright (C) 2009 John Elliott + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include + +#include "pbm.h" + + +static void syntax(const char *prog) +{ + pm_usage(" { options } { input }\n\n" + "Input file should be in CompuServe RLE format.\n" + "Output file will be in PBM format.\n" + "Options:\n" + "-i, --inverse: Reverse black and white.\n" + "--: End of options\n\n" +"cistopbm v1.01, Copyright 2009 John Elliott \n" +"This program is redistributable under the terms of the GNU General Public\n" +"License, version 2 or later.\n" + ); +} + +int main(int argc, const char **argv) +{ + FILE *ifP; + int c[3]; + int inoptions = 1; + int n, x, y; + int bw = PBM_BLACK; /* Default colouring is white on black */ + const char *inpname = NULL; + int height, width; + bit **bits; + + pm_proginit(&argc, argv); + + for (n = 1; n < argc; n++) + { + if (!strcmp(argv[n], "--")) + { + inoptions = 0; + continue; + } + if (inoptions) + { + if (pm_keymatch(argv[n], "-h", 2) || + pm_keymatch(argv[n], "-H", 2) || + pm_keymatch(argv[n], "--help", 6)) + { + syntax(argv[0]); + return EXIT_SUCCESS; + } + if (pm_keymatch(argv[n], "-i", 2) || + pm_keymatch(argv[n], "-I", 2) || + pm_keymatch(argv[n], "--inverse", 9)) + { + bw ^= (PBM_WHITE ^ PBM_BLACK); + continue; + } + if (argv[n][0] == '-' && argv[n][1] != 0) + { + pm_message("Unknown option: %s", argv[n]); + syntax(argv[0]); + return EXIT_FAILURE; + } + } + + if (inpname == NULL) inpname = argv[n]; + else { syntax(argv[0]); return EXIT_FAILURE; } + } + if (inpname == NULL) inpname = "-"; + ifP = pm_openr(inpname); + + /* There may be junk before the magic number. If so, skip it. */ + x = 0; + c[0] = c[1] = c[2] = EOF; + + /* Read until the array c[] holds the magic number. */ + do + { + c[0] = c[1]; + c[1] = c[2]; + c[2] = fgetc(ifP); + + /* If character read was EOF, end of file was reached and magic number + * not found. + */ + if (c[2] == EOF) + { + pm_error("Input file is not in CompuServe RLE format"); + } + ++x; + } while (c[0] != 0x1B || c[1] != 0x47); + + /* x = number of bytes read. Should be 3 if signature is at the start */ + if (x > 3) + { + pm_message("Warning: %d bytes of junk skipped before image", + x - 3); + } + /* Parse the resolution */ + switch(c[2]) + { + case 0x48: height = 192; width = 256; break; + case 0x4D: height = 96; width = 128; break; + default: pm_error("Unknown resolution 0x%02x", c[2]); + break; + } + /* Convert the data */ + bits = pbm_allocarray(width, height); + x = y = 0; + do + { + c[0] = fgetc(ifP); + + /* Stop if we hit EOF or Escape */ + if (c[0] == EOF) break; /* EOF */ + if (c[0] == 0x1B) break; /* End of graphics */ + /* Other non-printing characters are ignored; some files contain a + * BEL + */ + if (c[0] < 0x20) continue; + + /* Each character gives the number of pixels to draw in the appropriate + * colour. + */ + for (n = 0x20; n < c[0]; n++) + { + if (x < width && y < height) bits[y][x] = bw; + x++; + /* Wrap at end of line */ + if (x >= width) + { + x = 0; + y++; + } + } + /* And toggle colours */ + bw ^= (PBM_WHITE ^ PBM_BLACK); + } + while (1); + + /* See if the end-graphics signature (ESC G N) is present. */ + c[1] = EOF; + if (c[0] == 0x1B) + { + c[1] = fgetc(ifP); + c[2] = fgetc(ifP); + } + if (c[0] != 0x1B || c[1] != 0x47 || c[2] != 0x4E) + { + pm_message("Warning: End-graphics signature not found"); + } + /* See if we decoded the right number of pixels */ + if (x != 0 || y != height) + { + pm_message("Warning: %d pixels found, should be %d", + y * width + x, width * height); + } + pbm_writepbm(stdout, bits, width, height, 0); + pm_close(ifP); + return 0; +} diff --git a/converter/pbm/cmuwm.h b/converter/pbm/cmuwm.h deleted file mode 100644 index e667f25e..00000000 --- a/converter/pbm/cmuwm.h +++ /dev/null @@ -1,17 +0,0 @@ -/* cmuwm.h - definitions for the CMU window manager format -*/ - -#ifndef CMUWM_H_INCLUDED -#define CMUWM_H_INCLUDED - -struct cmuwm_header - { - long magic; - long width; - long height; - short depth; - }; - -#define CMUWM_MAGIC 0xf10040bbL - -#endif diff --git a/converter/pbm/cmuwmtopbm.c b/converter/pbm/cmuwmtopbm.c index eabff40c..ccf8cfc9 100644 --- a/converter/pbm/cmuwmtopbm.c +++ b/converter/pbm/cmuwmtopbm.c @@ -20,9 +20,17 @@ #include "pbm.h" -#include "cmuwm.h" +/*-------------------------- + CMUWN Header format: + 32 bit const magic = 0xf10040bb ; + 32 bit int width; + 32 bit int height; + 16 bit int depth; + + values are big-endian. +--------------------------*/ static void readCmuwmHeader(FILE * const ifP, @@ -32,6 +40,7 @@ readCmuwmHeader(FILE * const ifP, const char * const initReadError = "CMU window manager header EOF / read error"; + uint32_t const cmuwmMagic = 0xf10040bb; long l; short s; @@ -39,20 +48,20 @@ readCmuwmHeader(FILE * const ifP, rc = pm_readbiglong(ifP, &l); if (rc == -1 ) - pm_error(initReadError); - if ((uint32_t)l != CMUWM_MAGIC) + pm_error("%s", initReadError); + if ((uint32_t)l != cmuwmMagic) pm_error("bad magic number in CMU window manager file"); rc = pm_readbiglong(ifP, &l); if (rc == -1) - pm_error(initReadError); + pm_error("%s", initReadError); *colsP = l; rc = pm_readbiglong(ifP, &l); if (rc == -1 ) - pm_error(initReadError); + pm_error("%s", initReadError); *rowsP = l; rc = pm_readbigshort(ifP, &s); if (rc == -1) - pm_error(initReadError); + pm_error("%s", initReadError); *depthP = s; } diff --git a/converter/pbm/escp2topbm.c b/converter/pbm/escp2topbm.c index 28296da9..632e6345 100644 --- a/converter/pbm/escp2topbm.c +++ b/converter/pbm/escp2topbm.c @@ -14,65 +14,266 @@ ** copyright notice and this permission notice appear in supporting ** documentation. This software is provided "as is" without express or ** implied warranty. + +** Major changes were made in July 2015 by Akira Urushibata. +** Most notably the output functions were rewritten. +** The -plain option is honored as in other programs. + +* Implementation note (July 2015) +* +* The input file does not have a global header. Image data is divided +* into stripes (or data blocks). Each stripe has a header with +* local values for width, height, horizontal/vertical resolution +* and compression mode. +* +* We calculate the global height by adding up the local (stripe) +* height values, which may vary. +* +* The width value in the first stripe is used throughout; if any +* subsequent stripe reports a different value we abort. +* +* We ignore the resolution fields. Changes in compression mode +* are tolerated; they pose no problem. +* +* The official manual says resolution changes within an image are +* not allowed. It does not mention whether changes in stripe height or +* width values should be allowed. +* +* A different implementation approach would be to write temporary +* PBM files for each stripe and concatenate them at the final stage +* with a system call to "pnmcat -tb". This method has the advantage +* of being capable of handling variations in width. */ -#include -#include "pbm.h" +#include + #include "mallocvar.h" +#include "pbm.h" + +#define ESC 033 + + + +static int +huntEsc(FILE * const ifP) { +/*----------------------------------------------------------------------------- + Hunt for valid start of image stripe in input. + + Return values: + ESC: start of image stripe (data block) + EOF: end of file + 0: any other char or sequence +-----------------------------------------------------------------------------*/ + int const ch1 = getc(ifP); + + switch (ch1) { + case EOF: return EOF; + case ESC: { + int const ch2 = getc(ifP); + + switch (ch2) { + case EOF: return EOF; + case '.': return ESC; + default: return 0; + } + } break; + default: return 0; + } +} + + + +static unsigned char +readChar(FILE * const ifP) { + + int const ch = getc(ifP); + + if (ch == EOF) + pm_error("EOF encountered while reading image data."); + + return (unsigned char) ch; +} + + + +static void +readStripeHeader(unsigned int * const widthThisStripeP, + unsigned int * const rowsThisStripeP, + unsigned int * const compressionP, + FILE * const ifP) { + + unsigned char stripeHeader[6]; + unsigned int widthThisStripe, rowsThisStripe; + unsigned int compression; + + if (fread(stripeHeader, sizeof(stripeHeader), 1, ifP) != 1) + pm_error("Error reading image data."); + + compression = stripeHeader[0]; + /* verticalResolution = stripeHeader[1]; */ + /* horizontalResolution = stripeHeader[2]; */ + rowsThisStripe = stripeHeader[3]; + widthThisStripe = stripeHeader[5] * 256 + stripeHeader[4]; + + if (widthThisStripe == 0 || rowsThisStripe == 0) + pm_error("Error: Abnormal value in data block header: " + "Says stripe has zero width or height"); + + if (compression != 0 && compression != 1) + pm_error("Error: Unknown compression mode %u", compression); + + *widthThisStripeP = widthThisStripe; + *rowsThisStripeP = rowsThisStripe; + *compressionP = compression; +} + + /* RLE decoder */ -static unsigned int -dec_epson_rle(unsigned const int k, - unsigned const char * in, - unsigned char * const out) { +static void +decEpsonRLE(unsigned int const blockSize, + unsigned char * const outBuffer, + FILE * const ifP) { - unsigned int i; - unsigned int pos; unsigned int dpos; - pos = 0; /* initial value */ - dpos = 0; /* initial value */ + for (dpos = 0; dpos < blockSize; ) { + unsigned char const flag = readChar(ifP); - while (dpos < k) { - if (in[pos] < 128) { - for (i = 0; i < in[pos] + 1; ++i) - out[dpos+i] = in[pos + i + 1]; + if (flag < 128) { /* copy through */ - pos += i + 1; + + unsigned int const nonrunLength = flag + 1; + + unsigned int i; + + for (i = 0; i < nonrunLength; ++i) + outBuffer[dpos+i] = readChar(ifP); + + dpos += nonrunLength; + } else if (flag == 128) { + pm_message("Code 128 detected in compressed input data: ignored"); } else { - for (i = 0; i < 257 - in[pos]; ++i) - out[dpos + i] = in[pos + 1]; /* inflate this run */ - pos += 2; + + unsigned int const runLength = 257 - flag; + unsigned char const repeatChar = readChar( ifP ); + + unsigned int i; + + for (i = 0; i < runLength; ++i) + outBuffer[dpos + i] = repeatChar; + dpos += runLength; } - dpos += i; } - if(dpos > k) - pm_error("Corrupt compressed block"); - return pos; /* return number of treated input bytes */ + if (dpos != blockSize) + pm_error("Corruption detected in compressed input data"); } -int -main(int argc, - char * argv[]) { +static void +processStripeRaster(unsigned char ** const bitarray, + unsigned int const rowsThisStripe, + unsigned int const width, + unsigned int const compression, + FILE * const ifP, + unsigned int * const rowIdxP) { + + unsigned int const initialRowIdx = *rowIdxP; + unsigned int const widthInBytes = pbm_packed_bytes(width); + unsigned int const blockSize = rowsThisStripe * widthInBytes; + unsigned int const margin = compression==1 ? 256 : 0; + + unsigned char * imageBuffer; + unsigned int i; + unsigned int rowIdx; - unsigned int const size = 4096; /* arbitrary value */ + /* We allocate a new buffer each time this function is called. Add some + margin to the buffer for compressed mode to cope with overruns caused + by corrupt input data. + */ + + MALLOCARRAY(imageBuffer, blockSize + margin); + + if (imageBuffer == NULL) + pm_error("Failed to allocate buffer for a block of size %u", + blockSize); + + if (compression == 0) { + if (fread(imageBuffer, blockSize, 1, ifP) != 1) + pm_error("Error reading image data"); + } else /* compression == 1 */ + decEpsonRLE(blockSize, imageBuffer, ifP); + + /* Hand over image data to output by pointer assignment */ + for (i = 0, rowIdx = initialRowIdx; i < rowsThisStripe; ++i) + bitarray[rowIdx++] = &imageBuffer[i * widthInBytes]; + + *rowIdxP = rowIdx; +} - FILE *ifP; - unsigned int i, len, pos, opos, width, height; - unsigned char *input, *output; - const char * fileName; - pbm_init(&argc, argv); - MALLOCARRAY(input, size); - MALLOCARRAY(output, size); - - if (input == NULL || output == NULL) - pm_error("Cannot allocate memory"); +static void +expandBitarray(unsigned char *** const bitarrayP, + unsigned int * const bitarraySizeP) { + + unsigned int const heightIncrement = 5120; + unsigned int const heightMax = 5120 * 200; + /* 5120 rows is sufficient for US legal at 360 DPI */ + + *bitarraySizeP += heightIncrement; + if (*bitarraySizeP > heightMax) + pm_error("Image too tall"); + else + REALLOCARRAY_NOFAIL(*bitarrayP, *bitarraySizeP); +} + + + +static void +writePbmImage(unsigned char ** const bitarray, + unsigned int const width, + unsigned int const height) { + + unsigned int row; + + if (height == 0) + pm_error("No image"); + + pbm_writepbminit(stdout, width, height, 0); + + for (row = 0; row < height; ++row) { + pbm_cleanrowend_packed(bitarray[row], width); + pbm_writepbmrow_packed(stdout, bitarray[row], width, 0); + } +} + + + +int +main(int argc, + const char * argv[]) { + + FILE * ifP; + unsigned int width; + /* Width of the image, or zero to mean width is not yet known. + (We get the width from the first stripe in the input; until + we've seen that stripe, we don't know the width) + */ + unsigned int height; + /* Height of the image as seen so far. (We process a stripe at a + time, increasing this value as we go). + */ + unsigned int rowIdx; + unsigned char ** bitarray; + unsigned int bitarraySize; + const char * fileName; + bool eof; + + pm_proginit(&argc, argv); if (argc-1 > 1) pm_error("Too many arguments (%u). Only argument is filename.", @@ -85,69 +286,64 @@ main(int argc, ifP = pm_openr(fileName); - /* read the whole file */ - len = 0; /* initial value */ - for (i = 0; !feof(ifP); ++i) { - size_t bytesRead; - REALLOCARRAY(input, (i+1) * size); - if (input == NULL) - pm_error("Cannot allocate memory"); - bytesRead = fread(input + i * size, 1, size, ifP); - len += bytesRead; - } + /* Initialize bitarray */ + bitarray = NULL; bitarraySize = 0; + expandBitarray(&bitarray, &bitarraySize); - /* filter out raster data */ - height = 0; /* initial value */ - width = 0; /* initial value */ - pos = 0; /* initial value */ - opos = 0; /* initial value */ - - while (pos < len) { - /* only ESC sequences are regarded */ - if (input[pos] == '\x1b' && input[pos+1] == '.') { - unsigned int const k = - input[pos+5] * ((input[pos+7] * 256 + input[pos+6] + 7) / 8); - unsigned int const margin = 256; - if(input[pos+5] == 0) - pm_error("Abnormal height value in escape sequence"); - height += input[pos+5]; - if(width == 0) /* initialize */ - width = input[pos+7] * 256 + input[pos+6]; - else if(width != input[pos+7] * 256 + input[pos+6]) - pm_error("Abnormal width value in escape sequence"); - - REALLOCARRAY(output, opos + k + margin); - if (output == NULL) - pm_error("Cannot allocate memory"); - - switch (input[pos+2]) { - case 0: - /* copy the data block */ - memcpy(output + opos, input + pos + 8, k); - pos += k + 8; - opos += k; - break; - case 1: { - /* inflate the data block */ - unsigned int l; - l = dec_epson_rle(k,input+pos+8,output+opos); - pos += l + 8; - opos += k; - } - break; - default: - pm_error("unknown compression mode"); - break; + for (eof = false, width = 0, height = 0, rowIdx = 0; !eof; ) { + int const r = huntEsc(ifP); + + if (r == EOF) + eof = true; + else { + if (r == ESC) { + unsigned int compression; + unsigned int rowsThisStripe; + unsigned int widthThisStripe; + + readStripeHeader(&widthThisStripe, &rowsThisStripe, + &compression, ifP); + + if (rowsThisStripe == 0) + pm_error("Abnormal data block height value: 0"); + else if (rowsThisStripe != 24 && rowsThisStripe != 8 && + rowsThisStripe != 1) { + /* The official Epson manual says valid values are 1, 8, + 24 but we just print a warning message and continue if + other values are detected. + */ + pm_message("Abnormal data block height value: %u " + "(ignoring)", + rowsThisStripe); + } + if (width == 0) { + /* Get width from 1st stripe header */ + width = widthThisStripe; + } else if (width != widthThisStripe) { + /* width change not allowed */ + pm_error("Error: Width changed in middle of image " + "from %u to %u", + width, widthThisStripe); + } + height += rowsThisStripe; + if (height > bitarraySize) + expandBitarray(&bitarray, &bitarraySize); + + processStripeRaster(bitarray, rowsThisStripe, width, + compression, ifP, &rowIdx); + } else { + /* r != ESC; do nothing */ } } - else - ++pos; /* skip bytes outside the ESCX sequence */ } - pbm_writepbminit(stdout, width, height, 0); - fwrite(output, opos, 1, stdout); - free(input); free(output); - fclose(stdout); fclose(ifP); + writePbmImage(bitarray, width, height); + + fclose(stdout); + fclose(ifP); return 0; } + + + diff --git a/converter/pbm/g3topbm.c b/converter/pbm/g3topbm.c index 7bb95c92..b0d08f9e 100644 --- a/converter/pbm/g3topbm.c +++ b/converter/pbm/g3topbm.c @@ -97,7 +97,7 @@ parseCommandLine(int argc, char ** const argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We may have parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (widthSpec && paper_sizeSpec) @@ -169,7 +169,7 @@ readBit(struct bitStream * const bitStreamP, if ((bitStreamP->shbit & 0xff) == 0) { bitStreamP->shdata = getc(bitStreamP->fileP); if (bitStreamP->shdata == EOF) - asprintfN(errorP, "EOF or error reading file"); + pm_asprintf(errorP, "EOF or error reading file"); else { bitStreamP->shbit = 0x80; if ( bitStreamP->reversebits ) @@ -195,6 +195,8 @@ readBitAndDetectEol(struct bitStream * const bitStreamP, /*---------------------------------------------------------------------------- Same as readBit(), but iff the bit read is the final bit of an EOL mark, return *eolP == TRUE. + + An EOL mark is 11 zero bits followed by a one. -----------------------------------------------------------------------------*/ readBit(bitStreamP, bitP, errorP); if (!*errorP) { @@ -265,19 +267,19 @@ addtohash(g3TableEntry * hash[], -static g3TableEntry* +static g3TableEntry * hashfind(g3TableEntry * hash[], - int const length, - int const code, - int const a, - int const b) { + int const length, + int const code, + int const a, + int const b) { unsigned int pos; g3TableEntry * te; pos = ((length + a) * (code + b)) % HASHSIZE; te = hash[pos]; - return ((te && te->length == length && te->code == code) ? te : 0); + return ((te && te->length == length && te->code == code) ? te : NULL); } @@ -316,7 +318,13 @@ static g3TableEntry * g3code(unsigned int const curcode, unsigned int const curlen, bit const color) { +/*---------------------------------------------------------------------------- + Return the position in the code tables mtable and ttable of the + G3 code which is the 'curlen' bits long with value 'curcode'. + Note that it is the _position_ in the table that determines the meaning + of the code. The contents of the table entry do not. +-----------------------------------------------------------------------------*/ g3TableEntry * retval; switch (color) { @@ -379,7 +387,11 @@ processG3Code(const g3TableEntry * const teP, unsigned int * const colP, bit * const colorP, unsigned int * const countP) { - +/*---------------------------------------------------------------------------- + 'teP' is a pointer into the mtable/ttable. Note that the thing it points + to is irrelevant to us; it is only the position in the table that + matters. +-----------------------------------------------------------------------------*/ enum g3tableId const teId = (teP > mtable ? 2 : 0) + (teP - ttable) % 2; @@ -395,17 +407,17 @@ processG3Code(const g3TableEntry * const teP, switch (teId) { case TERMWHITE: case TERMBLACK: { - unsigned int runLengthSoFar; + unsigned int totalRunLength; unsigned int col; col = *colP; - runLengthSoFar = MIN(*countP + teCount, MAXCOLS - col); + totalRunLength = MIN(*countP + teCount, MAXCOLS - col); - if (runLengthSoFar > 0) { + if (totalRunLength > 0) { if (*colorP == PBM_BLACK) - writeBlackBitSpan(packedBitrow, runLengthSoFar, col); + writeBlackBitSpan(packedBitrow, totalRunLength, col); /* else : Row was initialized to white, so we just skip */ - col += runLengthSoFar; + col += totalRunLength; } *colorP = !*colorP; *countP = 0; @@ -428,12 +440,12 @@ formatBadCodeException(const char ** const exceptionP, unsigned int const curlen, unsigned int const curcode) { - asprintfN(exceptionP, - "bad code word at Column %u. " - "No prefix of the %u bits 0x%x matches any recognized " - "code word and no code words longer than 13 bits are " - "defined. ", - col, curlen, curcode); + pm_asprintf(exceptionP, + "bad code word at Column %u. " + "No prefix of the %u bits 0x%x matches any recognized " + "code word and no code words longer than 13 bits are " + "defined. ", + col, curlen, curcode); } @@ -485,8 +497,8 @@ readFaxRow(struct bitStream * const bitStreamP, while (!done) { if (col >= MAXCOLS) { - asprintfN(exceptionP, "Line is too long for this program to " - "handle -- longer than %u columns", MAXCOLS); + pm_asprintf(exceptionP, "Line is too long for this program to " + "handle -- longer than %u columns", MAXCOLS); done = TRUE; } else { unsigned int bit; @@ -507,7 +519,7 @@ readFaxRow(struct bitStream * const bitStreamP, done = TRUE; else { curcode = (curcode << 1) | bit; - curlen++; + ++curlen; if (curlen > 13) { formatBadCodeException(exceptionP, col, curlen, curcode); @@ -516,7 +528,8 @@ readFaxRow(struct bitStream * const bitStreamP, const g3TableEntry * const teP = g3code(curcode, curlen, currentColor); /* Address of structure that describes the - current G3 code + current G3 code. Null means 'curcode' isn't + a G3 code yet (probably just the beginning of one) */ if (teP) { processG3Code(teP, packedBitrow, @@ -570,7 +583,7 @@ handleRowException(const char * const exception, row, exception); else pm_error("Problem reading Row %u. Aborting. %s", row, exception); - strfree(exception); + pm_strfree(exception); } if (error) { @@ -579,7 +592,7 @@ handleRowException(const char * const exception, row, error); else pm_error("Unable to read Row %u. Aborting. %s", row, error); - strfree(error); + pm_strfree(error); } } @@ -626,16 +639,16 @@ analyzeLineSize(lineSizeAnalyzer * const analyzerP, if (analyzerP->expectedLineSize && thisLineSize != analyzerP->expectedLineSize) - asprintfN(&error, "Image contains a line of %u pixels. " - "You specified lines should be %u pixels.", - thisLineSize, analyzerP->expectedLineSize); + pm_asprintf(&error, "Image contains a line of %u pixels. " + "You specified lines should be %u pixels.", + thisLineSize, analyzerP->expectedLineSize); else { if (analyzerP->maxLineSize && thisLineSize != analyzerP->maxLineSize) - asprintfN(&error, "There are at least two different " - "line lengths in this image, " - "%u pixels and %u pixels. " - "This is a violation of the G3 standard. ", - thisLineSize, analyzerP->maxLineSize); + pm_asprintf(&error, "There are at least two different " + "line lengths in this image, " + "%u pixels and %u pixels. " + "This is a violation of the G3 standard. ", + thisLineSize, analyzerP->maxLineSize); else error = NULL; } @@ -649,7 +662,7 @@ analyzeLineSize(lineSizeAnalyzer * const analyzerP, } else pm_error("%s", error); - strfree(error); + pm_strfree(error); } analyzerP->maxLineSize = MAX(thisLineSize, analyzerP->maxLineSize); } @@ -693,8 +706,8 @@ readFax(struct bitStream * const bitStreamP, unsigned int lineSize; if (row >= MAXROWS) - asprintfN(&error, "Image is too tall. This program can " - "handle at most %u rows", MAXROWS); + pm_asprintf(&error, "Image is too tall. This program can " + "handle at most %u rows", MAXROWS); else { const char * exception; @@ -714,9 +727,9 @@ readFax(struct bitStream * const bitStreamP, if (stretch) { ++row; if (row >= MAXROWS) - asprintfN(&error, "Image is too tall. This " - "program can handle at most %u rows " - "after stretching", MAXROWS); + pm_asprintf(&error, "Image is too tall. This " + "program can handle at most %u rows " + "after stretching", MAXROWS); else packedBits[row] = packedBits[row-1]; } diff --git a/converter/pbm/icontopbm.c b/converter/pbm/icontopbm.c deleted file mode 100644 index a0d1bd2b..00000000 --- a/converter/pbm/icontopbm.c +++ /dev/null @@ -1,159 +0,0 @@ -/* icontopbm.c - read a Sun icon file and produce a portable bitmap -** -** Copyright (C) 1988 by Jef Poskanzer. -** -** Permission to use, copy, modify, and distribute this software and its -** documentation for any purpose and without fee is hereby granted, provided -** that the above copyright notice appear in all copies and that both that -** copyright notice and this permission notice appear in supporting -** documentation. This software is provided "as is" without express or -** implied warranty. -*/ - -#include - -#include "nstring.h" -#include "pbm.h" - -/* size in bytes of a bitmap */ -#define BitmapSize(width, height) (((((width) + 15) >> 3) &~ 1) * (height)) - -static void -ReadIconFile(FILE * const file, - int * const widthP, - int * const heightP, - short unsigned int ** const dataP) { - - char variable[80+1]; - int ch; - int status, value, i, data_length, gotsome; - - gotsome = 0; - *widthP = *heightP = -1; - for ( ; ; ) - { - while ( ( ch = getc( file ) ) == ',' || ch == '\n' || ch == '\t' || - ch == ' ' ) - ; - for ( i = 0; - ch != '=' && ch != ',' && ch != '\n' && ch != '\t' && - ch != ' ' && (i < (sizeof(variable) - 1)); - i++ ) - { - variable[i] = ch; - if ((ch = getc( file )) == EOF) - pm_error( "invalid input file -- premature EOF" ); - } - variable[i] = '\0'; - - if ( streq( variable, "*/" )&& gotsome ) - break; - - if ( fscanf( file, "%d", &value ) != 1 ) - continue; - - if ( streq( variable, "Width" ) ) - { - *widthP = value; - gotsome = 1; - } - else if ( streq( variable, "Height" ) ) - { - *heightP = value; - gotsome = 1; - } - else if ( streq( variable, "Depth" ) ) - { - if ( value != 1 ) - pm_error( "invalid depth" ); - gotsome = 1; - } - else if ( streq( variable, "Format_version" ) ) - { - if ( value != 1 ) - pm_error( "invalid Format_version" ); - gotsome = 1; - } - else if ( streq( variable, "Valid_bits_per_item" ) ) - { - if ( value != 16 ) - pm_error( "invalid Valid_bits_per_item" ); - gotsome = 1; - } - } - - if ( *widthP <= 0 ) - pm_error( "invalid width (must be positive): %d", *widthP ); - if ( *heightP <= 0 ) - pm_error( "invalid height (must be positive): %d", *heightP ); - - data_length = BitmapSize( *widthP, *heightP ); - *dataP = (short unsigned int *) malloc( data_length ); - if ( *dataP == NULL ) - pm_error( "out of memory" ); - data_length /= sizeof( short ); - - for ( i = 0 ; i < data_length; i++ ) - { - if ( i == 0 ) - status = fscanf( file, " 0x%4hx", *dataP ); - else - status = fscanf( file, ", 0x%4hx", *dataP + i ); - if ( status != 1 ) - pm_error( "error 4 scanning bits item" ); - } -} - - - -int -main(int argc, char ** argv) { - - FILE* ifp; - bit* bitrow; - register bit* bP; - int rows, cols, row, col, shortcount, mask; - short unsigned int * data; - - - pbm_init( &argc, argv ); - - if ( argc > 2 ) - pm_usage( "[iconfile]" ); - - if ( argc == 2 ) - ifp = pm_openr( argv[1] ); - else - ifp = stdin; - - ReadIconFile( ifp, &cols, &rows, &data ); - - pm_close( ifp ); - - pbm_writepbminit( stdout, cols, rows, 0 ); - bitrow = pbm_allocrow( cols ); - - for ( row = 0; row < rows; row++ ) - { - shortcount = 0; - mask = 0x8000; - for ( col = 0, bP = bitrow; col < cols; col++, bP++ ) - { - if ( shortcount >= 16 ) - { - data++; - shortcount = 0; - mask = 0x8000; - } - *bP = ( *data & mask ) ? PBM_BLACK : PBM_WHITE; - shortcount++; - mask = mask >> 1; - } - data++; - pbm_writepbmrow( stdout, bitrow, cols, 0 ); - } - - pm_close( stdout ); - exit( 0 ); -} - diff --git a/converter/pbm/macp.h b/converter/pbm/macp.h index 26a720a2..d00dc5c9 100644 --- a/converter/pbm/macp.h +++ b/converter/pbm/macp.h @@ -1,12 +1,16 @@ -/* macp.h - header file for MacPaint files -*/ - +/*============================================================================= + macp.h +=============================================================================== + Information about MacPaint files +=============================================================================*/ #ifndef MACP_H_INCLUDED #define MACP_H_INCLUDED -#define HEADER_LENGTH 512 -#define MAX_LINES 720 -#define BYTES_WIDE 72 -#define MAX_COLS 576 /* = BYTES_WIDE * 8 */ +#define MACBIN_HEAD_LEN 128 +#define MACP_HEAD_LEN 512 +#define MACP_ROWS 720 +#define MACP_COLCHARS 72 +#define MACP_COLS ((MACP_COLCHARS) * 8) +#define MACP_BYTES ((MACP_COLCHARS) * (MACP_ROWS)) #endif diff --git a/converter/pbm/macptopbm.c b/converter/pbm/macptopbm.c index f4a341d3..db628b6c 100644 --- a/converter/pbm/macptopbm.c +++ b/converter/pbm/macptopbm.c @@ -1,6 +1,8 @@ /* macptopbm.c - read a MacPaint file and produce a portable bitmap ** ** Copyright (C) 1988 by Jef Poskanzer. +** Some code of ReadMacPaintFile() is based on the work of +** Patrick J. Naughton. (C) 1987, All Rights Reserved. ** ** Permission to use, copy, modify, and distribute this software and its ** documentation for any purpose and without fee is hereby granted, provided @@ -8,133 +10,347 @@ ** copyright notice and this permission notice appear in supporting ** documentation. This software is provided "as is" without express or ** implied warranty. + + +** Apr 2015 afu +** Changed code style (ANSI-style function definitions, etc.) +** Added automatic detection of MacBinary header. +** Added diagnostics for corruptions. +** Replaced byte-wise operations with bit-wise ones. */ #include "pbm.h" +#include "pm_c_util.h" #include "macp.h" -static void ReadMacPaintFile ARGS(( FILE* file, int extraskip, int* scanLineP, unsigned char Pic[MAX_LINES][BYTES_WIDE] )); -static unsigned char Pic[MAX_LINES][BYTES_WIDE]; + +static bool +validateMacPaintVersion( const unsigned char * const rBuff, + const int offset ) { +/*--------------------------------------------------------------------------- + Macpaint (or PNTG) files have two headers. + The 512 byte MacPaint header is mandatory. + The newer 128 byte MacBinary header is optional. If it exists, it comes + before the MacPaint header. + + Here we examine the first four bytes of the MacPaint header to get + the version number. + + Valid version numbers are 0, 2, 3. + We also allow 1. +-----------------------------------------------------------------------------*/ + + bool retval; + const unsigned char * const vNum = rBuff + offset; + + if ( ( ( vNum[0] | vNum[1] | vNum[2] ) != 0x00 ) || vNum[3] > 3 ) + retval = FALSE; + else + retval = TRUE; + + pm_message("MacPaint version (at offset %u): %02x %02x %02x %02x (%s)", + offset, vNum[0], vNum[1], vNum[2], vNum[3], + retval == TRUE ? "valid" : "not valid" ); + + return( retval ); +} + + + +static bool +scanMacBinaryHeader( const unsigned char * rBuff ) { +/*---------------------------------------------------------------------------- + We check byte 0 and 1, and then the MacPaint header version assuming it + starts at offset 128. + + Byte 0: must be 0x00. + Byte 1: (filename length) must be 1-63. + + Other fields that may be of interest: + + Bytes 2 through 63: (Internal Filename) + See Apple Charmap for valid characters. + Unlike US-Ascii, 8-bit characters (range 0x80 - 0xFF) are valid. + 0x00-0x1F and 0x7F are control characters. 0x00 appears in some files. + Colon ':' (0x3a) should be avoided in Mac environments but in practice + does appear. + + Bytes 65 through 68: (File Type) + Four Ascii characters. Should be "PNTG". + + Bytes 82 to 85: (SizeOfDataFork) + uint32 value. It seems this is file size (in bytes) / 256 + N, N <= 4. + + Bytes 100 through 124: + Should be all zero if the header is MacBinary I. + Defined and used in MacBinary II. + + Bytes 124,125: CRC + (MacBinary II only) CRC value of bytes 0 through 123. + + All multi-byte values are big-endian. + + Reference: + http://www.fileformat.info/format/macpaint/egff.htm + Fully describes the fields. However, the detection method described + does not work very well. + + Also see: + http://fileformats.archiveteam.org/wiki/MacPaint +-----------------------------------------------------------------------------*/ + bool foundMacBinaryHeader; + + /* Examine byte 0. It should be 0x00. Note that the first + byte of a valid MacPaint header should also be 0x00. + */ + if ( rBuff[0] != 0x00 ) { + foundMacBinaryHeader = FALSE; + } + + /* Examine byte 1, the length of the filename. + It should be in the range 1 - 63. + */ + else if( rBuff[1] == 0 || rBuff[1] > 63 ) { + foundMacBinaryHeader = FALSE; + } + + /* Check the MacPaint header version starting at offset 128. */ + else if ( validateMacPaintVersion ( rBuff, MACBIN_HEAD_LEN ) == FALSE) { + foundMacBinaryHeader = FALSE; + } + else + foundMacBinaryHeader = TRUE; + + if( foundMacBinaryHeader == TRUE) + pm_message("Input file contains a MacBinary header " + "followed by a MacPaint header."); + else + pm_message("Input file does not start with a MacBinary header."); + + return ( foundMacBinaryHeader ); +} + + + + +static void +skipHeader( FILE * const ifP ) { +/*-------------------------------------------------------------------------- + Determine whether the MacBinary header exists. + If it does, read off the initial 640 (=128 + 512) bytes of the file. + If it doesn't, read off 512 bytes. + + In the latter case we check the MacHeader version number, but just issue + a warning if the value is invalid. This is for backward comaptibility. +---------------------------------------------------------------------------*/ + unsigned int re; + const unsigned int buffsize = MAX( MACBIN_HEAD_LEN, MACP_HEAD_LEN ); + unsigned char * const rBuff = malloc(buffsize); + + if( rBuff == NULL ) + pm_error("Out of memory."); + + /* Read 512 bytes. + See if MacBinary header exists in the first 128 bytes and + the next 4 bytes signal the start of a MacPaint header. */ + re = fread ( rBuff, MACP_HEAD_LEN, 1, ifP); + if (re < 1) + pm_error("EOF/error while reading header."); + + if ( scanMacBinaryHeader( rBuff ) == TRUE ) { + /* MacBinary header found. Read another 128 bytes to complete the + MacPaint header, but don't conduct any further analysis. */ + re = fread ( rBuff, MACBIN_HEAD_LEN, 1, ifP); + if (re < 1) + pm_error("EOF/error while reading MacPaint header."); + + } else { + /* MacBinary header not found. We assume file starts with + MacPaint header. Check MacPaint version but dismiss error. */ + if (validateMacPaintVersion( rBuff, 0 ) == TRUE) + pm_message("Input file starts with valid MacPaint header."); + else + pm_message(" - Ignoring invalid version number."); + } + free( rBuff ); +} + + + +static void +skipExtraBytes( FILE * const ifP, + int const extraskip) { +/*-------------------------------------------------------------------------- + This function exists for backward compatibility. Its purpose is to + manually delete the MacBinary header. + + We check the MacHeader version number, but just issue a warning if the + value is invalid. +---------------------------------------------------------------------------*/ + unsigned int re; + unsigned char * const rBuff = malloc(MAX (extraskip, MACP_HEAD_LEN)); + + if( rBuff == NULL ) + pm_error("Out of memory."); + + re = fread ( rBuff, 1, extraskip, ifP); + if (re < extraskip) + pm_error("EOF/error while reading off initial %u bytes" + "specified by -extraskip.", extraskip); + re = fread ( rBuff, MACP_HEAD_LEN, 1, ifP); + if (re < 1) + pm_error("EOF/error while reading MacPaint header."); + + /* Check the MacPaint version number. Dismiss error. */ + if (validateMacPaintVersion( rBuff, 0 ) == TRUE) + pm_message("Input file starts with valid MacPaint header."); + else + pm_message(" - Ignoring invalid version number."); + + free( rBuff ); +} + + + +static unsigned char +readChar( FILE * const ifP ) { + + int const ch = getc( ifP ); + + if (ch ==EOF) + pm_error("EOF encountered while unpacking image data."); + + /* else */ + return ((unsigned char) ch); +} + + + + +static void +ReadMacPaintFile( FILE * const ifP, + int * outOfSyncP, + int * pixelCntP ) { +/*--------------------------------------------------------------------------- + Unpack image data. Compression method is called "Packbits". + This run-length encoding scheme has also been adopted by + Postscript and TIFF. See source: converter/other/pnmtops.c + + Unpacked raster array is raw PBM. No conversion is required. + + One source says flag byte should not be 0xFF (255), but we don't reject + the value, for in practice, it is widely used. + + Sequences should never cross row borders. + Violations of this rule are recorded in outOfSync. + + Note that pixelCnt counts bytes, not bits, so it is the number of pixels + multiplied by 8. This counter exists to detect corruptions. +---------------------------------------------------------------------------*/ + int pixelCnt = 0; /* Initial value */ + int outOfSync = 0; /* Initial value */ + unsigned int flag; /* Read from input */ + unsigned int i; + unsigned char * const bitrow = pbm_allocrow_packed(MACP_COLS); + + while ( pixelCnt < MACP_BYTES ) { + flag = (unsigned int) readChar( ifP ); /* Flag (count) byte */ + if ( flag < 0x80 ) { + /* Unpack next (flag + 1) chars as is */ + for ( i = 0; i <= flag; i++ ) + if( pixelCnt < MACP_BYTES) { + int const colChar = pixelCnt % MACP_COLCHARS; + pixelCnt++; + bitrow[colChar] = readChar( ifP ); + if (colChar == MACP_COLCHARS-1) + pbm_writepbmrow_packed( stdout, bitrow, MACP_COLS, 0 ); + if (colChar == 0 && i > 0 ) + outOfSync++; + } + } + else { + /* Repeat next char (2's complement of flagCnt) times */ + unsigned int const flagCnt = 256 - flag; + unsigned char const ch = readChar( ifP ); + for ( i = 0; i <= flagCnt; i++ ) + if( pixelCnt < MACP_BYTES) { + int const colChar = pixelCnt % MACP_COLCHARS; + pixelCnt++; + bitrow[colChar] = ch; + if (colChar == MACP_COLCHARS-1) + pbm_writepbmrow_packed( stdout, bitrow, MACP_COLS, 0 ); + if (colChar == 0 && i > 0 ) + outOfSync++; + } + } + } + pbm_freerow_packed ( bitrow ); + *outOfSyncP = outOfSync; + *pixelCntP = pixelCnt; +} + int -main( argc, argv ) - int argc; - char* argv[]; - { - FILE* ifp; - bit* bitrow; - int argn, extraskip, scanLine, rows, cols, row, bcol, i; - const char* usage = "[-extraskip N] [macpfile]"; +main( int argc, char * argv[]) { + FILE * ifp; + int argn, extraskip; + const char * const usage = "[-extraskip N] [macpfile]"; + int outOfSync; + int pixelCnt; pbm_init( &argc, argv ); - argn = 1; - extraskip = 0; + argn = 1; /* initial value */ + extraskip = 0; /* initial value */ /* Check for flags. */ - if ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) - { - if ( pm_keymatch( argv[argn], "-extraskip", 2 ) ) - { - argn++; - if ( argn == argc || sscanf( argv[argn], "%d", &extraskip ) != 1 ) - pm_usage( usage ); - } - else - pm_usage( usage ); - argn++; - } - - if ( argn < argc ) - { - ifp = pm_openr( argv[argn] ); - argn++; - } + if ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) { + if ( pm_keymatch( argv[argn], "-extraskip", 2 ) ) { + argn++; + if ( argn == argc || sscanf( argv[argn], "%d", &extraskip ) != 1 ) + pm_usage( usage ); + } + else + pm_usage( usage ); + argn++; + } + + if ( argn < argc ) { + ifp = pm_openr( argv[argn] ); + argn++; + } else - ifp = stdin; + ifp = stdin; if ( argn != argc ) - pm_usage( usage ); + pm_usage( usage ); - ReadMacPaintFile( ifp, extraskip, &scanLine, Pic ); + if ( extraskip > 256 * 1024 ) + pm_error("-extraskip value too large"); + else if ( extraskip > 0 ) + skipExtraBytes( ifp, extraskip); + else + skipHeader( ifp ); + pbm_writepbminit( stdout, MACP_COLS, MACP_ROWS, 0 ); + + ReadMacPaintFile( ifp, &outOfSync, &pixelCnt ); + /* We may not be at EOF. + Macpaint files often have extra bytes after image data. */ pm_close( ifp ); - cols = BYTES_WIDE * 8; - rows = scanLine; - pbm_writepbminit( stdout, cols, rows, 0 ); - bitrow = pbm_allocrow( cols ); + if ( pixelCnt == 0 ) + pm_error("No image data."); + + else if ( pixelCnt < MACP_BYTES ) + pm_error("Compressed image data terminated prematurely."); - for ( row = 0; row < rows; row++ ) - { - for ( bcol = 0; bcol < BYTES_WIDE; bcol++ ) - for ( i = 0; i < 8; i++ ) - bitrow[bcol * 8 + i] = - ( (Pic[row][bcol] >> (7 - i)) & 1 ) ? PBM_BLACK : PBM_WHITE; - pbm_writepbmrow( stdout, bitrow, cols, 0 ); - } + else if ( outOfSync > 0 ) + pm_message("Warning: Corrupt image data. %d rows misaligned.", + outOfSync); pm_close( stdout ); exit( 0 ); - } - -/* -** Some of the following routine is: -** -** Copyright 1987 by Patrick J. Naughton -** All Rights Reserved -** Permission to use, copy, modify, and distribute this software and its -** documentation for any purpose and without fee is hereby granted, -** provided that the above copyright notice appear in all copies and that -** both that copyright notice and this permission notice appear in -** supporting documentation. -*/ - -static void -ReadMacPaintFile( file, extraskip, scanLineP, Pic ) - FILE* file; - int extraskip; - int* scanLineP; - unsigned char Pic[MAX_LINES][BYTES_WIDE]; - { - unsigned int i, j, k; - unsigned char ch; - - /* Skip over the header. */ - for ( i = 0; i < extraskip; i++ ) - getc( file ); - for ( i = 0; i < HEADER_LENGTH; i++ ) - getc( file ); - - *scanLineP = 0; - k = 0; - - while ( *scanLineP < MAX_LINES ) - { - ch = (unsigned char) getc( file ); /* Count byte */ - i = (unsigned int) ch; - if ( ch < 0x80 ) - { /* Unpack next (I+1) chars as is */ - for ( j = 0; j <= i; j++ ) - if ( *scanLineP < MAX_LINES ) - { - Pic[*scanLineP][k++] = (unsigned char) getc( file ); - if ( ! (k %= BYTES_WIDE) ) - *scanLineP += 1; - } - } - else - { /* Repeat next char (2's comp I) times */ - ch = getc( file ); - for ( j = 0; j <= 256 - i; j++ ) - if ( *scanLineP < MAX_LINES ) - { - Pic[*scanLineP][k++] = (unsigned char) ch; - if ( ! (k %= BYTES_WIDE) ) - *scanLineP += 1; - } - } - } - } +} diff --git a/converter/pbm/pbmto10x.c b/converter/pbm/pbmto10x.c index f8a38b5d..d040b3ed 100644 --- a/converter/pbm/pbmto10x.c +++ b/converter/pbm/pbmto10x.c @@ -12,16 +12,14 @@ ** Modified to shorten stripes and eliminate blank stripes. Dec 1994. */ +#include + #include "pbm.h" #include "mallocvar.h" #define LOW_RES_ROWS 8 /* printed per pass */ #define HIGH_RES_ROWS 16 /* printed per pass */ -static int highres = 0; -static FILE *ifp; -static int rows, cols, format; - static void @@ -29,8 +27,6 @@ outstripe(char * const stripe, char * const sP, int const reschar) { - int ncols; - char * p; p = sP; /* initial value */ @@ -41,10 +37,14 @@ outstripe(char * const stripe, ++p; break; } - ncols = p - stripe; - if (ncols > 0) { - printf("\033%c%c%c", reschar, ncols % 256, ncols / 256); - fwrite(stripe, sizeof(char), ncols, stdout); + + { + unsigned int const ncols = p - stripe; + + if (ncols > 0) { + printf("\033%c%c%c", reschar, ncols % 256, ncols / 256); + fwrite(stripe, sizeof(char), ncols, stdout); + } } putchar('\n'); /* flush buffer */ } @@ -52,26 +52,44 @@ outstripe(char * const stripe, static void -res_60x72(void) { - int i, item, npins, row, col; - bit *bitrows[LOW_RES_ROWS], *bP[LOW_RES_ROWS]; - char *stripe, *sP; +res_60x72(FILE * const ifP, + int const rows, + int const cols, + int const format) { + + int row; + unsigned int i; + bit * bitrows[LOW_RES_ROWS]; + char *stripe; + char *sP; MALLOCARRAY(stripe, cols); if (stripe == NULL) pm_error("Unable to allocate %u bytes for a stripe buffer.", - cols * sizeof(stripe[0])); + (unsigned)(cols * sizeof(stripe[0]))); + for (i = 0; i < LOW_RES_ROWS; ++i) bitrows[i] = pbm_allocrow(cols); + printf("\033A\010"); /* '\n' = 8/72 */ + for (row = 0, sP = stripe; row < rows; row += LOW_RES_ROWS, sP = stripe) { + unsigned int col; + unsigned int i; + unsigned int npins; + bit * bP[LOW_RES_ROWS]; + if (row + LOW_RES_ROWS <= rows) npins = LOW_RES_ROWS; else npins = rows - row; + for (i = 0; i < npins; ++i) - pbm_readpbmrow(ifp, bP[i] = bitrows[i], cols, format); + pbm_readpbmrow(ifP, bP[i] = bitrows[i], cols, format); + for (col = 0; col < cols; ++col) { + unsigned int item; + item = 0; for (i = 0; i < npins; ++i) if (*(bP[i]++) == PBM_BLACK) @@ -81,32 +99,52 @@ res_60x72(void) { outstripe(stripe, sP, 'K'); } printf("\033@"); + + for (i = 0; i < LOW_RES_ROWS; ++i) + pbm_freerow(bitrows[i]); + free(stripe); } static void -res_120x144(void) { - int i, pin, item, npins, row, col; - bit *bitrows[HIGH_RES_ROWS], *bP[HIGH_RES_ROWS]; - char *stripe, *sP; +res_120x144(FILE * const ifP, + int const rows, + int const cols, + int const format) { + + unsigned int i; + int row; + char *stripe; + char * sP; + bit * bitrows[HIGH_RES_ROWS]; MALLOCARRAY(stripe, cols); if (stripe == NULL) pm_error("Unable to allocate %u bytes for a stripe buffer.", - cols * sizeof(stripe[0])); + (unsigned)(cols * sizeof(stripe[0]))); + for (i = 0; i < HIGH_RES_ROWS; ++i) bitrows[i] = pbm_allocrow(cols); + printf("\0333\001"); /* \n = 1/144" */ + for (row = 0, sP = stripe; row < rows; row += HIGH_RES_ROWS, sP = stripe) { + unsigned int i; + unsigned int col; + bit * bP[HIGH_RES_ROWS]; + unsigned int npins; + if (row + HIGH_RES_ROWS <= rows) npins = HIGH_RES_ROWS; else npins = rows - row; for (i = 0; i < npins; ++i) - pbm_readpbmrow(ifp, bP[i] = bitrows[i], cols, format); + pbm_readpbmrow(ifP, bP[i] = bitrows[i], cols, format); for (col = 0; col < cols; ++col) { + unsigned int pin; + unsigned int item; item = 0; /* even rows */ for (pin = i = 0; i < npins; i += 2, ++pin) @@ -115,8 +153,9 @@ res_120x144(void) { *sP++ = item; } outstripe(stripe, sP, 'L'); - sP = stripe; - for (col = 0; col < cols; ++col) { + for (col = 0, sP = stripe; col < cols; ++col) { + unsigned int pin; + unsigned int item; item = 0; /* odd rows */ for (i = 1, pin = 0; i < npins; i += 2, ++pin) @@ -128,20 +167,29 @@ res_120x144(void) { printf("\033J\016"); /* 14/144 down, \n did 1/144 */ } printf("\033@"); + + for (i = 0; i < LOW_RES_ROWS; ++i) + pbm_freerow(bitrows[i]); + free(stripe); } int -main(int argc, char * argv[]) { +main(int argc, const char ** argv) { const char * fname; + static FILE * ifP; + int rows, cols, format; + + bool isHighRes; - pbm_init( &argc, argv ); + pm_proginit(&argc, argv); + isHighRes = false; /* initial assumption */ if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'h') { - highres = 1; + isHighRes = true; --argc; ++argv; } @@ -152,17 +200,18 @@ main(int argc, char * argv[]) { else fname = "-"; - ifp = pm_openr(fname); + ifP = pm_openr(fname); - pbm_readpbminit(ifp, &cols, &rows, &format); + pbm_readpbminit(ifP, &cols, &rows, &format); - if (highres) - res_120x144(); + if (isHighRes) + res_120x144(ifP, rows, cols, format); else - res_60x72(); + res_60x72(ifP, rows, cols, format); + + pm_close(ifP); - pm_close(ifp); - exit(0); + return 0; } diff --git a/converter/pbm/pbmtoascii.c b/converter/pbm/pbmtoascii.c index 0472f809..fd590aa6 100644 --- a/converter/pbm/pbmtoascii.c +++ b/converter/pbm/pbmtoascii.c @@ -1,4 +1,4 @@ -/* pbmtoascii.c - read a portable bitmap and produce ASCII graphics +/* pbmtoascii.c - read a PBM image and produce ASCII graphics ** ** Copyright (C) 1988, 1992 by Jef Poskanzer. ** @@ -10,8 +10,33 @@ ** implied warranty. */ +#include +#include "mallocvar.h" #include "pbm.h" +/* + The algorithm is based on describing the 2 or 8 pixels in a cell with a + single integer called a signature, which we use as an index into an array to + get the character whose glyph best matches those pixels. The encoding is as + follows. Make a string of bits, with each bit being one pixel of the cell, + 1 = black, 0 = white. The order of the string is left to right across the + top row, then the next row down, etc. Considering that string to be a + binary cipher, the integer it represents is the signature. + + Example: the 2x4 cell consists of these pixels: (* = black) + + * * + * + + * + The bit string to represent this is 11100001. So the signature for this + cell is the integer 0xE1 (225). + + You index the array carr2x4 with 0xE1, and get '?' as the character to + represent that cell. (We don't really try very hard to match the shape; + it's mostly important to match the density). +*/ + #define SQQ '\'' #define BSQ '\\' @@ -19,7 +44,7 @@ ** 1 ** 2 */ -static char carr1x2[4] = { +static char const carr1x2[4] = { /* 0 1 2 3 */ ' ', '"', 'o', 'M' }; @@ -35,47 +60,177 @@ static char carr1x2[4] = { #define D06 '&' #define D05 '$' #define D04 '?' -static char carr2x4[256] = { +static char const carr2x4[256] = { /*0 1 2 3 4 5 6 7 8 9 A B C D E F */ -' ',SQQ, '`','"', '-',SQQ, SQQ,SQQ, '-','`', '`','`', '-','^', '^','"',/*00-0F*/ -'.',':', ':',':', '|','|', '/',D04, '/','>', '/','>', '~','+', '/','*',/*10-1F*/ -'.',':', ':',':', BSQ,BSQ, '<','<', '|',BSQ, '|',D04, '~',BSQ, '+','*',/*20-2F*/ -'-',':', ':',':', '~',D04, '<','<', '~','>', D04,'>', '=','b', 'd','#',/*30-3F*/ -'.',':', ':',':', ':','!', '/',D04, ':',':', '/',D04, ':',D04, D04,'P',/*40-4F*/ -',','i', '/',D04, '|','|', '|','T', '/',D04, '/','7', 'r','}', '/','P',/*50-5F*/ -',',':', ';',D04, '>',D04, 'S','S', '/',')', '|','7', '>',D05, D05,D06,/*60-6F*/ -'v',D04, D04,D05, '+','}', D05,'F', '/',D05, '/',D06, 'p','D', D06,D07,/*70-7F*/ -'.',':', ':',':', ':',BSQ, ':',D04, ':',BSQ, '!',D04, ':',D04, D04,D05,/*80-8F*/ -BSQ,BSQ, ':',D04, BSQ,'|', '(',D05, '<','%', D04,'Z', '<',D05, D05,D06,/*90-9F*/ -',',BSQ, 'i',D04, BSQ,BSQ, D04,BSQ, '|','|', '|','T', D04,BSQ, '4','9',/*A0-AF*/ -'v',D04, D04,D05, BSQ,BSQ, D05,D06, '+',D05, '{',D06, 'q',D06, D06,D07,/*B0-BF*/ -'_',':', ':',D04, ':',D04, D04,D05, ':',D04, D04,D05, ':',D05, D05,D06,/*C0-CF*/ -BSQ,D04, D04,D05, D04,'L', D05,'[', '<','Z', '/','Z', 'c','k', D06,'R',/*D0-DF*/ -',',D04, D04,D05, '>',BSQ, 'S','S', D04,D05, 'J',']', '>',D06, '1','9',/*E0-EF*/ -'o','b', 'd',D06, 'b','b', D06,'6', 'd',D06, 'd',D07, '#',D07, D07,D08 /*F0-FF*/ - }; +' ',SQQ, '`','"', '-',SQQ, SQQ,SQQ, '-','`', '`','`', '-','^','^','"',/*00-0F*/ +'.',':', ':',':', '|','|', '/',D04, '/','>', '/','>', '~','+','/','*',/*10-1F*/ +'.',':', ':',':', BSQ,BSQ, '<','<', '|',BSQ, '|',D04, '~',BSQ,'+','*',/*20-2F*/ +'-',':', ':',':', '~',D04, '<','<', '~','>', D04,'>', '=','b','d','#',/*30-3F*/ +'.',':', ':',':', ':','!', '/',D04, ':',':', '/',D04, ':',D04,D04,'P',/*40-4F*/ +',','i', '/',D04, '|','|', '|','T', '/',D04, '/','7', 'r','}','/','P',/*50-5F*/ +',',':', ';',D04, '>',D04, 'S','S', '/',')', '|','7', '>',D05,D05,D06,/*60-6F*/ +'v',D04, D04,D05, '+','}', D05,'F', '/',D05, '/',D06, 'p','D',D06,D07,/*70-7F*/ +'.',':', ':',':', ':',BSQ, ':',D04, ':',BSQ, '!',D04, ':',D04,D04,D05,/*80-8F*/ +BSQ,BSQ, ':',D04, BSQ,'|', '(',D05, '<','%', D04,'Z', '<',D05,D05,D06,/*90-9F*/ +',',BSQ, 'i',D04, BSQ,BSQ, D04,BSQ, '|','|', '|','T', D04,BSQ,'4','9',/*A0-AF*/ +'v',D04, D04,D05, BSQ,BSQ, D05,D06, '+',D05, '{',D06, 'q',D06,D06,D07,/*B0-BF*/ +'_',':', ':',D04, ':',D04, D04,D05, ':',D04, D04,D05, ':',D05,D05,D06,/*C0-CF*/ +BSQ,D04, D04,D05, D04,'L', D05,'[', '<','Z', '/','Z', 'c','k',D06,'R',/*D0-DF*/ +',',D04, D04,D05, '>',BSQ, 'S','S', D04,D05, 'J',']', '>',D06,'1','9',/*E0-EF*/ +'o','b', 'd',D06, 'b','b', D06,'6', 'd',D06, 'd',D07, '#',D07,D07,D08 /*F0-FF*/ +}; -int -main( argc, argv ) -int argc; -char* argv[]; +static void +makeRowOfSigs(FILE * const ifP, + unsigned int const cols, + unsigned int const rows, + int const format, + unsigned int const cellWidth, + unsigned int const cellHeight, + unsigned int const row, + unsigned int * const sig, + unsigned int const ccols) { +/*---------------------------------------------------------------------------- + Compute the signatures for every cell in a row. + + Read the pixels from *ifP, which is positioned to the first pixel row + of the cell row, which is row number 'row'. The image dimensions are + 'cols' x 'rows' pixels. + + Each cell is 'cellWidth' x 'cellHeight'. + + Return the signatures as sig[], which is 'ccols' wide because that's how + many cells you get from 'cols' pixels divided into cells 'cellWidth' pixels + wide. +-----------------------------------------------------------------------------*/ + unsigned int b; + unsigned int subrow; /* row within cell */ + bit * bitrow; /* malloc'ed array */ + + bitrow = pbm_allocrow(cols); { - FILE* ifp; - int argn, gridx, gridy, rows, cols, format; - int ccols, lastcol, row, subrow, subcol; - register int col, b; - bit* bitrow; - register bit* bP; - int* sig; - register int* sP; - char* line; - register char* lP; - char* carr; + unsigned int col; + for (col = 0; col < ccols; ++col) + sig[col] = 0; + } + + b = 0x1; /* initial value */ + for (subrow = 0; subrow < cellHeight; ++subrow) { + if (row + subrow < rows) { + unsigned int subcol; /* col within cell */ + pbm_readpbmrow(ifP, bitrow, cols, format); + for (subcol = 0; subcol < cellWidth; ++subcol) { + unsigned int col, ccol; + for (col = subcol, ccol = 0; + col < cols; + col += cellWidth, ++ccol) { + if (bitrow[col] == PBM_BLACK) + sig[ccol] |= b; + } + b <<= 1; + } + } + } + pbm_freerow(bitrow); +} + + + +static void +findRightMargin(const unsigned int * const sig, + unsigned int const ccols, + const char * const carr, + unsigned int * const endColP) { +/*---------------------------------------------------------------------------- + Find the first cell of the right margin, i.e. a contiguous set of + all-white cells at the right end of the row. +-----------------------------------------------------------------------------*/ + unsigned int endcol; + + for (endcol = ccols; endcol > 0; --endcol) { + if (carr[sig[endcol-1]] != ' ') + break; + } + *endColP = endcol; +} + + + +static void +assembleCellRow(const unsigned int * const sig, + unsigned int const ccols, + const char * const carr, + char * const line) { +/*---------------------------------------------------------------------------- + Return as line[] the line of ASCII codes for the characters of one + row of cells, ready for printing. +-----------------------------------------------------------------------------*/ + unsigned int col; + + for (col = 0; col < ccols; ++col) + line[col] = carr[sig[col]]; + + line[ccols] = '\0'; +} + + + +static void +pbmtoascii(FILE * const ifP, + unsigned int const cellWidth, + unsigned int const cellHeight, + const char * const carr) { + + int cols, rows, format; + unsigned int ccols; + char * line; /* malloc'ed array */ + unsigned int row; + unsigned int * sig; /* malloc'ed array */ + /* This describes in a single integer the pixels of a cell, + as described above. + */ + assert(cellWidth * cellHeight <= sizeof(sig[0]*8)); + + pbm_readpbminit(ifP, &cols, &rows, &format); + + ccols = (cols + cellWidth - 1) / cellWidth; + + MALLOCARRAY(sig, ccols); + if (sig == NULL) + pm_error("No memory for %u columns", ccols); + MALLOCARRAY_NOFAIL(line, ccols+1); + if (line == NULL) + pm_error("No memory for %u columns", ccols); + + for (row = 0; row < rows; row += cellHeight) { + unsigned int endCol; + + makeRowOfSigs(ifP, cols, rows, format, cellWidth, cellHeight, + row, sig, ccols); + + findRightMargin(sig, ccols, carr, &endCol); + + assembleCellRow(sig, endCol, carr, line); + + puts(line); + } + free(sig); + free(line); +} + + + +int +main(int argc, const char ** argv) { + + FILE * ifP; + int argn, gridx, gridy; + const char * carr; const char* usage = "[-1x2|-2x4] [pbmfile]"; - pbm_init( &argc, argv ); + pm_proginit(&argc, argv); /* Set up default parameters. */ argn = 1; @@ -85,81 +240,38 @@ char* argv[]; /* Check for flags. */ while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) - { - if ( pm_keymatch( argv[argn], "-1x2", 2 ) ) - { - gridx = 1; - gridy = 2; - carr = carr1x2; - } - else if ( pm_keymatch( argv[argn], "-2x4", 2 ) ) - { - gridx = 2; - gridy = 4; - carr = carr2x4; - } - else - pm_usage( usage ); - ++argn; - } + { + if ( pm_keymatch( argv[argn], "-1x2", 2 ) ) + { + gridx = 1; + gridy = 2; + carr = carr1x2; + } + else if ( pm_keymatch( argv[argn], "-2x4", 2 ) ) + { + gridx = 2; + gridy = 4; + carr = carr2x4; + } + else + pm_usage( usage ); + ++argn; + } if ( argn < argc ) - { - ifp = pm_openr( argv[argn] ); - ++argn; - } + { + ifP = pm_openr( argv[argn] ); + ++argn; + } else - ifp = stdin; + ifP = stdin; if ( argn != argc ) pm_usage( usage ); - pbm_readpbminit( ifp, &cols, &rows, &format ); - ccols = ( cols + gridx - 1 ) / gridx; - bitrow = pbm_allocrow( cols ); - sig = (int*) pm_allocrow( ccols, sizeof(int) ); - line = (char*) pm_allocrow( ccols + 1, sizeof(char) ); - - for ( row = 0; row < rows; row += gridy ) - { - /* Get a character-row's worth of sigs. */ - for ( col = 0; col < ccols; ++col ) - sig[col] = 0; - b = 1; - for ( subrow = 0; subrow < gridy; ++subrow ) - { - if ( row + subrow < rows ) - { - pbm_readpbmrow( ifp, bitrow, cols, format ); - for ( subcol = 0; subcol < gridx; ++subcol ) - { - for ( col = subcol, bP = &(bitrow[subcol]), sP = sig; - col < cols; - col += gridx, bP += gridx, ++sP ) - if ( *bP == PBM_BLACK ) - *sP |= b; - b <<= 1; - } - } - } - /* Ok, now remove trailing blanks. */ - for ( lastcol = ccols - 1; lastcol >= 0; --lastcol ) - if ( carr[sig[lastcol]] != ' ' ) - break; - /* Copy chars to an array and print. */ - for ( col = 0, sP = sig, lP = line; col <= lastcol; ++col, ++sP, ++lP ) - *lP = carr[*sP]; - *lP++ = '\0'; - puts( line ); - } - - pm_close( ifp ); - pbm_freerow( bitrow ); - pm_freerow( (char*) sig ); - pm_freerow( (char*) line ); - - /* If the program failed, it previously aborted with nonzero completion - code, via various function calls. - */ + pbmtoascii(ifP, gridx, gridy, carr); + + pm_close(ifP); + return 0; - } +} diff --git a/converter/pbm/pbmtoatk.c b/converter/pbm/pbmtoatk.c index 9399f602..ea5b7abe 100644 --- a/converter/pbm/pbmtoatk.c +++ b/converter/pbm/pbmtoatk.c @@ -118,63 +118,52 @@ process_atk_byte(int * const pcurcount, int -main(int argc, char *argv[]) { +main(int argc, const char ** argv) { - FILE *ifd; - bit *bitrow; - register bit *bP; - int rows, cols, format, row; - int col; - unsigned char curbyte, newbyte; - int curcount, gather; + FILE * ifP; + bit * bitrow; + int rows, cols, format; + unsigned int row; + unsigned char curbyte; + int curcount; - pbm_init ( &argc, argv ); + pm_proginit(&argc, argv); if (argc-1 > 1) pm_error("Too many arguments. Only argument is file name"); else if (argc-1 == 1) { - ifd = pm_openr( argv[1] ); + ifP = pm_openr(argv[1]); } else { - ifd = stdin; + ifP = stdin; } - pbm_readpbminit(ifd, &cols, &rows, &format); - bitrow = pbm_allocrow(cols); + pbm_readpbminit(ifP, &cols, &rows, &format); + bitrow = pbm_allocrow_packed(cols); - printf ("\\begindata{raster,%d}\n", 1); - printf ("%d %d %d %d ", RASTERVERSION, 0, DEFAULTSCALE, DEFAULTSCALE); - printf ("%d %d %d %d\n", 0, 0, cols, rows); /* subraster */ - printf ("bits %d %d %d\n", 1, cols, rows); + printf("\\begindata{raster,%d}\n", 1); + printf("%d %d %d %d ", RASTERVERSION, 0, DEFAULTSCALE, DEFAULTSCALE); + printf("%d %d %d %d\n", 0, 0, cols, rows); /* subraster */ + printf("bits %d %d %d\n", 1, cols, rows); for (row = 0; row < rows; ++row) { - pbm_readpbmrow(ifd, bitrow, cols, format); - bP = bitrow; - gather = 0; - newbyte = 0; - curbyte = 0; - curcount = 0; - col = 0; - while (col < cols) { - if (gather > 7) { - process_atk_byte (&curcount, &curbyte, stdout, newbyte, FALSE); - gather = 0; - newbyte = 0; - } - newbyte = (newbyte << 1) | (*bP++); - gather += 1; - col += 1; - } - - if (gather > 0) { - newbyte = (newbyte << (8 - gather)); - process_atk_byte (&curcount, &curbyte, stdout, newbyte, TRUE); + unsigned int const byteCt = pbm_packed_bytes(cols); + unsigned int i; + + pbm_readpbmrow_packed(ifP, bitrow, cols, format); + pbm_cleanrowend_packed(bitrow, cols); + + for (i = 0, curbyte = 0, curcount = 0; i < byteCt; ++i) { + process_atk_byte(&curcount, &curbyte, stdout, + bitrow[i], + i + 1 < byteCt ? FALSE : TRUE ); } } - pm_close( ifd ); + pbm_freerow_packed(bitrow); + pm_close(ifP); - printf ("\\enddata{raster, %d}\n", 1); + printf("\\enddata{raster, %d}\n", 1); return 0; } diff --git a/converter/pbm/pbmtocis.c b/converter/pbm/pbmtocis.c new file mode 100644 index 00000000..9bb42c56 --- /dev/null +++ b/converter/pbm/pbmtocis.c @@ -0,0 +1,170 @@ +/* + * cistopbm: Convert images in the CompuServe RLE format to PBM + * Copyright (C) 2009 John Elliott + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include + +#include "pbm.h" + +/* The maximum length of a run. Limit it to 0x5E bytes so that it is always + * represented by a printable character 0x20-0x7E */ +#define MAXRUNLENGTH 0x5E + +static void syntax(const char *prog) +{ + pm_usage(" { options } { input } }\n\n" + "Input file should be in PBM format.\n" + "Output will be in CompuServe RLE format.\n" + "Options:\n" + "-i, --inverse: Reverse black and white.\n" + "-w, --whitebg: White background.\n" + "--: End of options\n\n" +"pbmtocis v1.00, Copyright 2009 John Elliott \n" +"This program is redistributable under the terms of the GNU General Public\n" +"License, version 2 or later.\n" + ); +} + +int main(int argc, const char **argv) +{ + FILE *ofP = stdout; + FILE *ifP; + int inoptions = 1; + int n, x, y; + int bg = PBM_BLACK; /* Default colouring is white on black */ + int inverse = 0; + int cell, last, run; + const char *inpname = NULL; + + int outh, outw; + int height, width; + bit **bits; + + pm_proginit(&argc, argv); + + for (n = 1; n < argc; n++) + { + if (!strcmp(argv[n], "--")) + { + inoptions = 0; + continue; + } + if (inoptions) + { + if (pm_keymatch(argv[n], "-h", 2) || + pm_keymatch(argv[n], "-H", 2) || + pm_keymatch(argv[n], "--help", 6)) + { + syntax(argv[0]); + return EXIT_SUCCESS; + } + if (pm_keymatch(argv[n], "-i", 2) || + pm_keymatch(argv[n], "-I", 2) || + pm_keymatch(argv[n], "--inverse", 9)) + { + inverse = 1; + continue; + } + if (pm_keymatch(argv[n], "-w", 2) || + pm_keymatch(argv[n], "-W", 2) || + pm_keymatch(argv[n], "--whitebg", 9)) + { + bg = PBM_WHITE; + continue; + } + if (argv[n][0] == '-' && argv[n][1] != 0) + { + pm_message("Unknown option: %s", argv[n]); + syntax(argv[0]); + return EXIT_FAILURE; + } + } + + if (inpname == NULL) inpname = argv[n]; + else { syntax(argv[0]); return EXIT_FAILURE; } + } + if (inpname == NULL) inpname = "-"; + ifP = pm_openr(inpname); + + /* Load the PBM */ + bits = pbm_readpbm(ifP, &width, &height); + + if (width <= 128 && height <= 96) { outw = 128; outh = 96; } + else if (width <= 256 && height <= 192) { outw = 256; outh = 192; } + else + { + outw = 256; + outh = 192; + pm_message("Warning: Input file is larger than 256x192. " + "It will be cropped."); + } + /* Write the magic number */ + fputc(0x1B, ofP); + fputc(0x47, ofP); + fputc((outw == 128) ? 0x4D : 0x48, ofP); + + /* And now start encoding */ + y = x = 0; + last = PBM_BLACK; + run = 0; + while (y < outh) + { + if (x < width && y < height) + { + cell = bits[y][x]; + if (inverse) cell ^= (PBM_BLACK ^ PBM_WHITE); + } + else cell = bg; + + if (cell == last) /* Cell is part of current run */ + { + ++run; + if (run > MAXRUNLENGTH) + { + fputc(0x20 + MAXRUNLENGTH, ofP); + fputc(0x20, ofP); + run -= MAXRUNLENGTH; + } + } + else /* change */ + { + fputc(run + 0x20, ofP); + last = last ^ (PBM_BLACK ^ PBM_WHITE); + run = 1; + } + ++x; + if (x >= outw) { x = 0; ++y; } + } + if (last == bg) /* Last cell written was background. Write foreground */ + { + fputc(run + 0x20, ofP); + } + else if (run) /* Write background and foreground */ + { + fputc(run + 0x20, ofP); + fputc(0x20, ofP); + } + /* Write the end-graphics signature */ + fputc(0x1B, ofP); + fputc(0x47, ofP); + fputc(0x4E, ofP); + pm_close(ifP); + return 0; +} diff --git a/converter/pbm/pbmtocmuwm.c b/converter/pbm/pbmtocmuwm.c index 773d988b..983ea491 100644 --- a/converter/pbm/pbmtocmuwm.c +++ b/converter/pbm/pbmtocmuwm.c @@ -18,18 +18,20 @@ */ #include "pbm.h" -#include "cmuwm.h" + + static void putinit(unsigned int const rows, unsigned int const cols) { - const char * const initWriteError = + const char initWriteError[] = "CMU window manager header write error"; + uint32_t const cmuwmMagic = 0xf10040bb; int rc; - rc = pm_writebiglong(stdout, CMUWM_MAGIC); + rc = pm_writebiglong(stdout, cmuwmMagic); if (rc == -1) pm_error(initWriteError); rc = pm_writebiglong(stdout, cols); diff --git a/converter/pbm/pbmtoepsi.c b/converter/pbm/pbmtoepsi.c index 5eccc298..87985a1f 100644 --- a/converter/pbm/pbmtoepsi.c +++ b/converter/pbm/pbmtoepsi.c @@ -16,19 +16,24 @@ ** implied warranty. */ +/* + * + * Official guide from Adobe: + * + * Encapsulated PostScript File Format Specification + * http://partners.adobe.com/public/developer/en/ps/5002.EPSF_Spec.pdf + * +*/ + #include "pm_c_util.h" #include "pbm.h" #include "shhopt.h" -#if !defined(MAXINT) -#define MAXINT (0x7fffffff) -#endif - struct cmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ - const char *inputFilespec; /* Filespecs of input files */ + const char *inputFileName; unsigned int dpiX; /* horiz component of DPI option */ unsigned int dpiY; /* vert component of DPI option */ @@ -40,8 +45,9 @@ struct cmdlineInfo { static void -parse_dpi(char * const dpiOpt, - unsigned int * const dpiXP, unsigned int * const dpiYP) { +parseDpi(char * const dpiOpt, + unsigned int * const dpiXP, + unsigned int * const dpiYP) { char *dpistr2; unsigned int dpiX, dpiY; @@ -72,7 +78,7 @@ parse_dpi(char * const dpiOpt, static void -parseCommandLine(int argc, char ** const argv, +parseCommandLine(int argc, const char ** const argv, struct cmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- Note that the file spec array we return is stored in the storage that @@ -97,48 +103,58 @@ parseCommandLine(int argc, char ** const argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (dpiOptSpec) - parse_dpi(dpiOpt, &cmdlineP->dpiX, &cmdlineP->dpiY); + parseDpi(dpiOpt, &cmdlineP->dpiX, &cmdlineP->dpiY); else cmdlineP->dpiX = cmdlineP->dpiY = 72; if ((argc-1) > 1) - pm_error("Too many arguments (%d). Only argument is input filespec", + pm_error("Too many arguments (%d). Only argument is input file name", argc-1); if (argc-1 == 0) - cmdlineP->inputFilespec = "-"; + cmdlineP->inputFileName = "-"; else - cmdlineP->inputFilespec = argv[1]; + cmdlineP->inputFileName = argv[1]; } static void -findPrincipalImage(bit ** const bits, - int const rows, - int const cols, - int * const topP, - int * const bottomP, - int * const leftP, - int * const rightP) { +findPrincipalImage(bit ** const bits, + unsigned int const rows, + unsigned int const cols, + unsigned int * const topP, + unsigned int * const bottomP, + unsigned int * const leftP, + unsigned int * const rightP) { +/*---------------------------------------------------------------------------- + Find the foreground image on a white background. + + Find the image in the pixels bits[][], which is 'rows' rows by + 'cols' columns. - int top, bottom, left, right; - int row; + Return the boundaries of the foreground image as *topP, *bottomP, *leftP, + and *rightP. + + If the image is all white, consider the entire image foreground. +-----------------------------------------------------------------------------*/ + unsigned int top, bottom, left, right; + unsigned int row; /* Initial values */ - top = MAXINT; - bottom = -MAXINT; - left = MAXINT; - right = -MAXINT; + top = rows; + bottom = 0; + left = cols; + right = 0; - for (row = 0; row < rows; row++) { - int col; - for (col = 0; col < cols; col++) { + for (row = 0; row < rows; ++row) { + unsigned int col; + for (col = 0; col < cols; ++col) { if (bits[row][col] == PBM_BLACK) { if (row < top) top = row; @@ -152,16 +168,19 @@ findPrincipalImage(bit ** const bits, } } - if(bottom == -MAXINT) { /* No black pixels encountered */ + if (top > bottom) { + /* No black pixels encountered */ pm_message("Blank page"); - top = left = 0; - bottom = rows-1; right = cols-1; - } + top = 0; + left = 0; + bottom = rows - 1; + right = cols - 1; + } - *topP = top; + *topP = top; *bottomP = bottom; - *leftP = left; - *rightP = right; + *leftP = left; + *rightP = right; } @@ -190,7 +209,8 @@ eightPixels(bit ** const bits, /*---------------------------------------------------------------------------- Compute a byte that represents the 8 pixels starting at Column 'col' of row 'row' of the raster 'bits'. The most significant bit of the result - represents the leftmost pixel, with 1 meaning black. + represents the leftmost pixel, with 1 meaning black. (Note that this is + the opposite of Postscript.) The row is 'cols' columns wide, so fill on the right with white if there are not eight pixels in the row starting with Column 'col'. @@ -212,23 +232,23 @@ eightPixels(bit ** const bits, int -main(int argc, char * argv[]) { +main(int argc, const char * argv[]) { struct cmdlineInfo cmdline; - FILE *ifP; - bit **bits; + FILE * ifP; + bit ** bits; int rows, cols; - int top, bottom, left, right; + unsigned int top, bottom, left, right; /* boundaries of principal part of image -- i.e. excluding white borders */ - pbm_init( &argc, argv ); + pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); - ifP = pm_openr(cmdline.inputFilespec); - bits = pbm_readpbm( ifP, &cols, &rows ); + ifP = pm_openr(cmdline.inputFileName); + bits = pbm_readpbm(ifP, &cols, &rows); pm_close(ifP); findPrincipalImage(bits, rows, cols, &top, &bottom, &left, &right); @@ -244,24 +264,26 @@ main(int argc, char * argv[]) { right - left + 1, bottom - top + 1, bottom - top + 1); for (row = top; row <= bottom; row++) { - int col; - int outChars = 2; - printf("%% "); + unsigned int col; + unsigned int outChars; + printf("%% "); + + outChars = 2; /* initial value */ for (col = left; col <= right; col += 8) { if (outChars == 72) { - printf("\n%% "); - outChars = 2; - } + printf("\n%% "); + outChars = 2; + } printf("%02x", eightPixels(bits, row, col, cols)); outChars += 2; - } - if (outChars > 0) + } + if (outChars > 0) printf("\n"); } printf("%%%%EndImage\n"); printf("%%%%EndPreview\n"); } - exit(0); + return 0; } diff --git a/converter/pbm/pbmtoepson.c b/converter/pbm/pbmtoepson.c index 86185d15..bb36791d 100644 --- a/converter/pbm/pbmtoepson.c +++ b/converter/pbm/pbmtoepson.c @@ -11,13 +11,12 @@ ** implied warranty. */ -#define _BSD_SOURCE /* Make sure strcasecmp() is in string.h */ - +#define _BSD_SOURCE /* Make sure strcaseeq() is in nstring.h */ #include -#include #include "pm_c_util.h" #include "mallocvar.h" +#include "nstring.h" #include "shhopt.h" #include "pbm.h" @@ -29,22 +28,22 @@ enum epsonProtocol {ESCP9, ESCP}; enum adjacence {ADJACENT_ANY, ADJACENT_YES, ADJACENT_NO}; -struct cmdlineInfo { +struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ - const char *inputFilespec; /* '-' if stdin */ - unsigned int dpi; /* zero means "any" */ - enum adjacence adjacence; + const char * inputFileName; /* '-' if stdin */ + unsigned int dpi; /* zero means "any" */ + enum adjacence adjacence; enum epsonProtocol protocol; }; static void -parseCommandLine(int argc, - char ** argv, - struct cmdlineInfo *cmdlineP ) { +parseCommandLine(int argc, + const char ** argv, + struct CmdlineInfo * cmdlineP ) { /*---------------------------------------------------------------------------- Parse program command line described in Unix standard form by argc and argv. Return the information in the options as *cmdlineP. @@ -56,7 +55,7 @@ parseCommandLine(int argc, was passed to us as the argv array. We also trash *argv. -----------------------------------------------------------------------------*/ optEntry *option_def; - /* Instructions to optParseOptions3 on how to parse our options. + /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; @@ -69,20 +68,20 @@ parseCommandLine(int argc, MALLOCARRAY_NOFAIL(option_def, 100); option_def_index = 0; /* incremented by OPTENT3 */ - OPTENT3(0, "protocol", OPT_STRING, &protocol, + OPTENT3(0, "protocol", OPT_STRING, &protocol, &protocolSpec, 0); - OPTENT3(0, "dpi", OPT_UINT, &cmdlineP->dpi, - &dpiSpec, 0); - OPTENT3(0, "adjacent", OPT_FLAG, NULL, + OPTENT3(0, "dpi", OPT_UINT, &cmdlineP->dpi, + &dpiSpec, 0); + OPTENT3(0, "adjacent", OPT_FLAG, NULL, &adjacentSpec, 0); - OPTENT3(0, "nonadjacent", OPT_FLAG, NULL, - &nonadjacentSpec, 0); + OPTENT3(0, "nonadjacent", OPT_FLAG, NULL, + &nonadjacentSpec, 0); opt.opt_table = option_def; opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3( &argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3( &argc, (char **)argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ @@ -96,11 +95,11 @@ parseCommandLine(int argc, if (!protocolSpec) cmdlineP->protocol = ESCP9; else { - if (strcasecmp(protocol, "escp9") == 0) + if (strcaseeq(protocol, "escp9")) cmdlineP->protocol = ESCP9; - else if (strcasecmp(protocol, "escp") == 0) + else if (strcaseeq(protocol, "escp")) cmdlineP->protocol = ESCP; - else if (strcasecmp(protocol, "escp2") == 0) + else if (strcaseeq(protocol, "escp2")) pm_error("This program cannot do ESC/P2. Try Pbmtoescp2."); else pm_error("Unrecognized value '%s' for -protocol. " @@ -118,13 +117,15 @@ parseCommandLine(int argc, cmdlineP->adjacence = ADJACENT_ANY; if (argc-1 < 1) - cmdlineP->inputFilespec = "-"; + cmdlineP->inputFileName = "-"; else { - cmdlineP->inputFilespec = argv[1]; + cmdlineP->inputFileName = argv[1]; if (argc-1 > 1) pm_error("Too many arguments (%d). The only non-option argument " "is the file name", argc-1); } + + free(option_def); } @@ -273,7 +274,7 @@ convertToEpson(const bit ** const bits, enum adjacence const adjacence) { unsigned int const rowsPerStripe = 8; - unsigned int const stripes = (rows + rowsPerStripe-1) / rowsPerStripe; + unsigned int const stripeCt = (rows + rowsPerStripe-1) / rowsPerStripe; unsigned int stripe; char m; @@ -288,7 +289,7 @@ convertToEpson(const bit ** const bits, stripe can be fewer than 8 rows. */ - for (stripe = 0; stripe < stripes; ++stripe) { + for (stripe = 0; stripe < stripeCt; ++stripe) { const bit ** const stripeBits = &bits[stripe*rowsPerStripe]; unsigned int const stripeRows = MIN(rowsPerStripe, rows - stripe * rowsPerStripe); @@ -313,18 +314,18 @@ convertToEpson(const bit ** const bits, int -main(int argc, char *argv[]) { +main(int argc, const char ** argv) { - struct cmdlineInfo cmdline; - FILE* ifP; + struct CmdlineInfo cmdline; + FILE * ifP; const bit** bits; int rows, cols; - pbm_init(&argc, argv); + pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); - ifP = pm_openr(cmdline.inputFilespec); + ifP = pm_openr(cmdline.inputFileName); bits = (const bit **)pbm_readpbm(ifP, &cols, &rows); diff --git a/converter/pbm/pbmtoescp2.c b/converter/pbm/pbmtoescp2.c index e280b3df..6f284f3c 100644 --- a/converter/pbm/pbmtoescp2.c +++ b/converter/pbm/pbmtoescp2.c @@ -1,4 +1,4 @@ -/* pbmtoescp2.c - read a portable bitmap and produce Epson ESC/P2 raster + /* pbmtoescp2.c - read a portable bitmap and produce Epson ESC/P2 raster ** graphics output data for Epson Stylus printers ** ** Copyright (C) 2003 by Ulrich Walcher (u.walcher@gmx.de) @@ -10,45 +10,65 @@ ** copyright notice and this permission notice appear in supporting ** documentation. This software is provided "as is" without express or ** implied warranty. +** +** Major changes were made in July 2015 by Akira Urushibata. +** Added 720 DPI capability. +** Added -formfeed, -raw and -stripeheight. +** Replaced Packbits run length encoding function. (Use library function.) +* +* ESC/P Reference Manual (1997) +* ftp://download.epson-europe.com/pub/download/182/epson18162eu.zip */ -/* I used the Epson ESC/P Reference Manual (1997) in writing this. */ - #include #include "pm_c_util.h" -#include "pbm.h" +#include "mallocvar.h" #include "shhopt.h" +#include "runlength.h" +#include "pbm.h" + + static char const esc = 033; -struct cmdlineInfo { +struct CmdlineInfo { const char * inputFileName; unsigned int resolution; unsigned int compress; + unsigned int stripeHeight; + bool raw; + bool formfeed; }; static void -parseCommandLine(int argc, char ** argv, - struct cmdlineInfo *cmdlineP) { +parseCommandLine(int argc, const char ** argv, + struct CmdlineInfo *cmdlineP) { optStruct3 opt; unsigned int option_def_index = 0; - optEntry *option_def = malloc(100*sizeof(optEntry)); + optEntry * option_def = malloc(100*sizeof(optEntry)); - unsigned int compressSpec, resolutionSpec; + unsigned int compressSpec, resolutionSpec, stripeHeightSpec, + rawSpec, formfeedSpec; opt.opt_table = option_def; opt.short_allowed = FALSE; opt.allowNegNum = FALSE; OPTENT3(0, "compress", OPT_UINT, &cmdlineP->compress, - &compressSpec, 0); + &compressSpec, 0); OPTENT3(0, "resolution", OPT_UINT, &cmdlineP->resolution, - &resolutionSpec, 0); + &resolutionSpec, 0); + OPTENT3(0, "stripeheight", OPT_UINT, &cmdlineP->stripeHeight, + &stripeHeightSpec, 0); + OPTENT3(0, "raw", OPT_FLAG, NULL, + &rawSpec, 0); + OPTENT3(0, "formfeed", OPT_FLAG, NULL, + &formfeedSpec, 0); - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); if (argc-1 > 1) pm_error("Too many arguments: %d. " @@ -62,79 +82,81 @@ parseCommandLine(int argc, char ** argv, cmdlineP->compress = 1; if (resolutionSpec) { - if (cmdlineP->resolution != 360 && cmdlineP->resolution != 180) + if (cmdlineP->resolution != 720 && cmdlineP->resolution != 360 && + cmdlineP->resolution != 180) pm_error("Invalid -resolution value: %u. " - "Only 180 and 360 are valid.", cmdlineP->resolution); + "Only 180, 360 and 720 are valid.", cmdlineP->resolution); } else cmdlineP->resolution = 360; + if (stripeHeightSpec) { + if (cmdlineP->stripeHeight == 0 || + cmdlineP->stripeHeight > 255) + pm_error("Invalid -stripeheight value: %u. " + "Should be 24, 8, or 1, and must be in the range 1-255", + cmdlineP->stripeHeight); + else if (cmdlineP->stripeHeight != 24 && + cmdlineP->stripeHeight != 8 && + cmdlineP->stripeHeight != 1) + pm_message("Proceeding with irregular -stripeheight value: %u. " + "Should be 24, 8, or 1.", cmdlineP->stripeHeight); + else if (cmdlineP->resolution == 720 && + cmdlineP->stripeHeight != 1) + /* The official Epson manual mandates single-row stripes for + 720 dpi high-resolution images. + */ + pm_message("Proceeding with irregular -stripeheight value: %u. " + "Because resolution i 720dpi, should be 1.", + cmdlineP->stripeHeight); + } else + cmdlineP->stripeHeight = cmdlineP->resolution == 720 ? 1 : 24; + + if (rawSpec && formfeedSpec) + pm_error("You cannot specify both -raw and -formfeed"); + else { + cmdlineP->raw = rawSpec ? true : false ; + cmdlineP->formfeed = formfeedSpec ? true : false ; + } + if (argc-1 == 1) cmdlineP->inputFileName = argv[1]; else cmdlineP->inputFileName = "-"; + + free(option_def); } -static unsigned int -enc_epson_rle(unsigned int const l, - const unsigned char * const src, - unsigned char * const dest) { -/*---------------------------------------------------------------------------- - compress l data bytes from src to dest and return the compressed - length ------------------------------------------------------------------------------*/ - unsigned int i; /* index */ - unsigned int state; /* run state */ - unsigned int pos; /* source position */ - unsigned int dpos; /* destination position */ - - pos = dpos = state = 0; - while ( pos < l ) - { - for (i=0; i<128 && pos+i 127) /* Limit in official Epson manual */ + pm_error("Image width is too large"); - h = v = 3600/cmdline.resolution; + outColByteCt = pbm_packed_bytes(cols); + stripeByteCt = cmdline.stripeHeight * outColByteCt; - /* Set raster graphic mode. */ - printf("%c%c%c%c%c%c", esc, '(', 'G', 1, 0, 1); + MALLOCARRAY(inBuff, stripeByteCt); + if (inBuff == NULL) + pm_error("Out of memory trying to create input buffer of %u bytes", + stripeByteCt); - /* Set line spacing in units of 1/360 inches. */ - printf("%c%c%c", esc, '+', 24*h/10); - - /* Write out raster stripes 24 rows high. */ - for (row = 0; row < rows; row += 24) { - unsigned int const linesThisStripe = (rows-row<24) ? rows%24 : 24; - printf("%c%c%c%c%c%c%c%c", esc, '.', cmdline.compress, - v, h, linesThisStripe, - cols%256, cols/256); - /* Read pbm rows, each padded to full byte */ - for (idx = 0; idx < 24 && row+idx < rows; ++idx) - pbm_readpbmrow_packed(ifP,bytes+idx*pbm_packed_bytes(cols), - cols,format); - /* Add delimiter to end of rows, using inverse of final - data byte to prevent match. */ - *(bytes+idx*pbm_packed_bytes(cols)) = - ~ *(bytes+idx*pbm_packed_bytes(cols)-1); - - /* Write raster data. */ - if (cmdline.compress != 0) { - /* compressed */ - len = enc_epson_rle(linesThisStripe * pbm_packed_bytes(cols), - bytes, cprbytes); - fwrite(cprbytes,len,1,stdout); - } else - /* uncompressed */ - fwrite(bytes, pbm_packed_bytes(cols), linesThisStripe, stdout); - - if (rows-row >= 24) putchar('\n'); + if (cmdline.compress != 0) + pm_rlenc_allocoutbuf(&compressedData, stripeByteCt, PM_RLE_PACKBITS); + else + compressedData = NULL; + + for (idx = 0; idx <= cmdline.stripeHeight; ++idx) + bitrow[idx]= &inBuff[idx * outColByteCt]; + + hres = vres = 3600 / cmdline.resolution; + /* Possible values for hres, vres: 20, 10, 5 */ + + if (!cmdline.raw) + writeSetup(hres); + + /* Write out raster stripes */ + + for (row = 0; row < rows; row += cmdline.stripeHeight ) { + unsigned int const rowsThisStripe = + MIN(rows - row, cmdline.stripeHeight); + unsigned int const outCols = outColByteCt * 8; + + if (rowsThisStripe > 0) { + unsigned int idx; + + printf("%c%c%c%c%c%c%c%c", esc, '.', cmdline.compress, vres, hres, + cmdline.stripeHeight, outCols % 256, outCols / 256); + + /* Read pbm rows, each padded to full byte */ + + for (idx = 0; idx < rowsThisStripe; ++idx) { + pbm_readpbmrow_packed (ifP, bitrow[idx], cols, format); + pbm_cleanrowend_packed(bitrow[idx], cols); + } + + /* If at bottom pad with empty rows up to stripe height */ + if (rowsThisStripe < cmdline.stripeHeight ) + memset(bitrow[rowsThisStripe], 0, + (cmdline.stripeHeight - rowsThisStripe) * outColByteCt); + + /* Write raster data */ + if (cmdline.compress != 0) { /* compressed */ + size_t compressedDataCt; + + pm_rlenc_compressbyte(inBuff, compressedData, PM_RLE_PACKBITS, + stripeByteCt, &compressedDataCt); + fwrite(compressedData, compressedDataCt, 1, stdout); + } else /* uncompressed */ + fwrite(inBuff, stripeByteCt, 1, stdout); + + /* Emit newline to print the stripe */ + putchar('\n'); + } } - free(bytes); free(cprbytes); + + free(inBuff); + free(compressedData); pm_close(ifP); - /* Reset printer. */ - printf("%c%c", esc, '@'); + /* Form feed */ + if (cmdline.formfeed) + putchar('\f'); + + if (!cmdline.raw) { + /* Reset printer. a*/ + printf("%c%c", esc, '@'); + } return 0; } diff --git a/converter/pbm/pbmtog3.c b/converter/pbm/pbmtog3.c index c0dd8c64..f0fd1252 100644 --- a/converter/pbm/pbmtog3.c +++ b/converter/pbm/pbmtog3.c @@ -65,7 +65,7 @@ struct outStream { static struct outStream out; -struct cmdlineInfo { +struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ @@ -79,7 +79,7 @@ struct cmdlineInfo { static void parseCommandLine(int argc, char ** const argv, - struct cmdlineInfo * const cmdlineP) { + struct CmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- Note that the file spec array we return is stored in the storage that was passed to us as the argv array. @@ -108,7 +108,7 @@ parseCommandLine(int argc, char ** const argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = TRUE; /* We may have parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ free(option_def); @@ -407,7 +407,7 @@ int main(int argc, char * argv[]) { - struct cmdlineInfo cmdline; + struct CmdlineInfo cmdline; FILE * ifP; unsigned char * bitrow; /* This is the bits of the current row, as read from the input and diff --git a/converter/pbm/pbmtog3.test b/converter/pbm/pbmtog3.test deleted file mode 100644 index 9ca45079..00000000 --- a/converter/pbm/pbmtog3.test +++ /dev/null @@ -1,23 +0,0 @@ -echo Test 1. Should print 3697098186 144 -./pbmtog3 ../../testgrid.pbm | cksum -echo Test 2. Should print 1248301383 122 -./pbmtog3 -nofixedwidth ../../testgrid.pbm | cksum -echo Test 3. Should print 686713716 144 -./pbmtog3 -reverse ../../testgrid.pbm | cksum -echo Test 4. Should print 215463240 122 -./pbmtog3 -nofixedwidth -reverse ../../testgrid.pbm | cksum -echo Test 5. Should print 28792587 47 -pbmmake -w 10 10 | ./pbmtog3 | cksum -echo Test 6. Should print 277456854 32 -pbmmake -w 10 10 | ./pbmtog3 -nofixedwidth | cksum -echo Test 7. Should print 28792587 47 -pbmmake -w 10000 10 | ./pbmtog3 | cksum -echo Test 8. Should print 871281767 162 -pbmmake -w 10000 10 | ./pbmtog3 -nofixedwidth | cksum -echo Test 9. Should print 3736247115 62 -pbmmake -b 10 10 | ./pbmtog3 | cksum -echo Test 10. Should print 2820255307 2191856 -pbmmake -g 1700 2286 | ./pbmtog3 | cksum -echo Test 11. Should print 4159089282 2226575 -pbmmake -g 1800 2286 | ./pbmtog3 | cksum -echo Tests done. diff --git a/converter/pbm/pbmtogem.c b/converter/pbm/pbmtogem.c index cefbdc95..9eab0416 100644 --- a/converter/pbm/pbmtogem.c +++ b/converter/pbm/pbmtogem.c @@ -27,17 +27,21 @@ * removed rounding of the imagewidth to the next word boundary * removed arbitrary limit to imagewidth * changed pattern length to 1 to simplify locating of compressable parts -* in real world images +* in real world images * add solid run and pattern run compression * * Deficiencies: * Compression of repeated scanlines not added * -* Johann Haider (jh@fortec.tuwien.ac.at) +* Johann Haider (jh@fortec.tuwien.ac.at) * * 94/01/31 Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de) * Changed to remove architecture dependencies * Added compression of repeated scanlines +* +* Feb 2010 afu +* Added dimension check to prevent short int from overflowing +* Changed code style (ANSI-style function definitions, etc.) */ #include @@ -47,59 +51,11 @@ #define SOLID_0 0 #define SOLID_1 0xff #define MINRUN 4 +#define INT16MAX 32767 + #define putsolid(v,c) putc((v&0x80)|c, stdout) #define putpattern(v,c) putc(0, stdout);putc(c, stdout);putc(v, stdout) -static void putinit ARGS ((int rows, int cols)); -static void putbit ARGS(( bit b )); -static void putitem ARGS(( void )); -static void putrow ARGS(( void )); -static void flushrow ARGS ((void)); -static void putstring ARGS((register unsigned char *p, register int n)); - -int -main( argc, argv ) - int argc; - char* argv[]; - { - FILE* ifp; - bit* bitrow; - register bit* bP; - int rows, cols, format, row, col; - - pbm_init( &argc, argv ); - - if ( argc > 2 ) - pm_usage( "[pbmfile]" ); - - if ( argc == 2 ) - ifp = pm_openr( argv[1] ); - else - ifp = stdin; - - pbm_readpbminit( ifp, &cols, &rows, &format ); - - bitrow = pbm_allocrow( cols ); - - putinit (rows, cols); - for ( row = 0; row < rows; ++row ) - { -#ifdef DEBUG - fprintf (stderr, "row %d\n", row); -#endif - pbm_readpbmrow( ifp, bitrow, cols, format ); - for ( col = 0, bP = bitrow; col < cols; ++col, ++bP ) - putbit( *bP ); - putrow( ); - } - flushrow (); - - pm_close( ifp ); - - - exit( 0 ); - } - static short item; static int outcol, outmax; static short bitsperitem, bitshift; @@ -107,9 +63,9 @@ static short linerepeat; static unsigned char *outrow, *lastrow; static void -putinit (rows, cols) - int rows, cols; +putinit (int const rows, int const cols) { + if (pm_writebigshort (stdout, (short) 1) == -1 /* Image file version */ || pm_writebigshort (stdout, (short) 8) == -1 /* Header length */ || pm_writebigshort (stdout, (short) 1) == -1 /* Number of planes */ @@ -129,17 +85,6 @@ putinit (rows, cols) linerepeat = -1; } -static void -putbit( bit b ) - { - if ( bitsperitem == 8 ) - putitem( ); - ++bitsperitem; - if ( b == PBM_BLACK ) - item += 1 << bitshift; - --bitshift; - } - static void putitem( ) { @@ -149,19 +94,93 @@ putitem( ) bitshift = 7; } + +static void +putbit( bit const b ) + { + if ( bitsperitem == 8 ) + putitem( ); + ++bitsperitem; + if ( b == PBM_BLACK ) + item += 1 << bitshift; + --bitshift; + } + + static void -putstring (p, n) -register unsigned char *p; -register int n; +putstring ( unsigned char *p, int n) { #ifdef DEBUG fprintf (stderr, "Bitstring, length: %d, pos %d\n", n, outcol); #endif (void) putc((char) 0x80, stdout); /* a Bit string */ - (void) putc(n, stdout); /* count */ + (void) putc(n, stdout); /* count */ fwrite( p, n, 1, stdout ); } + +static void +flushrow( ) + { + unsigned char *outp, *p, *q; + int count; + int col = outmax; + + if (linerepeat > 1) + { + /* Put out line repeat count */ + fwrite ("\0\0\377", 3, 1, stdout); + putchar (linerepeat); + } + for (outp = p = lastrow; col > 0;) + { + for (q = p, count=0; (count < col) && (*q == *p); q++,count++); + if (count > MINRUN) + { + if (p > outp) + { + putstring (outp, p-outp); + outp = p; + } + col -= count; + switch (*p) + { + case SOLID_0: +#ifdef DEBUG +/* if (outcol > 0) */ + fprintf (stderr, "Solid run 0, length: %d\n", count); +#endif + putsolid (SOLID_0, count); + break; + + case SOLID_1: +#ifdef DEBUG + fprintf (stderr, "Solid run 1, length: %d, pos %d\n", count, outcol); +#endif + putsolid (SOLID_1, count); + break; + default: +#ifdef DEBUG + fprintf (stderr, "Pattern run, length: %d\n", count); +#endif + putpattern (*p, count); + break; + } + outp = p = q; + } + else + { + p++; + col--; + } + } + if (p > outp) + putstring (outp, p-outp); + if (ferror (stdout)) + pm_error ("write error"); +} + + static void putrow( ) { @@ -173,7 +192,7 @@ putrow( ) { unsigned char *temp; if (linerepeat != -1) /* Unless first line */ - flushrow (); + flushrow (); /* Swap the pointers */ temp = outrow; outrow = lastrow; lastrow = temp; linerepeat = 1; @@ -183,64 +202,47 @@ putrow( ) linerepeat++; } -static void -flushrow( ) - { - register unsigned char *outp, *p, *q; - register int count; - int col = outmax; - if (linerepeat > 1) - { - /* Put out line repeat count */ - fwrite ("\0\0\377", 3, 1, stdout); - putchar (linerepeat); - } - for (outp = p = lastrow; col > 0;) +int +main( int argc, char* argv[]) { - for (q = p, count=0; (count < col) && (*q == *p); q++,count++); - if (count > MINRUN) - { - if (p > outp) - { - putstring (outp, p-outp); - outp = p; - } - col -= count; - switch (*p) - { - case SOLID_0: -#ifdef DEBUG -/* if (outcol > 0) */ - fprintf (stderr, "Solid run 0, length: %d\n", count); -#endif - putsolid (SOLID_0, count); - break; + FILE* ifp; + bit* bitrow; + int rows, cols, format, row, col; - case SOLID_1: -#ifdef DEBUG - fprintf (stderr, "Solid run 1, length: %d, pos %d\n", count, outcol); -#endif - putsolid (SOLID_1, count); - break; - default: + pbm_init( &argc, argv ); + + if ( argc > 2 ) + pm_usage( "[pbmfile]" ); + + if ( argc == 2 ) + ifp = pm_openr( argv[1] ); + else + ifp = stdin; + + pbm_readpbminit( ifp, &cols, &rows, &format ); + + if( rows>INT16MAX || cols>INT16MAX ) + pm_error ("Input image is too large."); + + + bitrow = pbm_allocrow( cols ); + + putinit (rows, cols); + for ( row = 0; row < rows; ++row ) + { #ifdef DEBUG - fprintf (stderr, "Pattern run, length: %d\n", count); + fprintf (stderr, "row %d\n", row); #endif - putpattern (*p, count); - break; - } - outp = p = q; - } - else - { - p++; - col--; - } - } - if (p > outp) - putstring (outp, p-outp); - if (ferror (stdout)) - pm_error ("write error"); -} + pbm_readpbmrow( ifp, bitrow, cols, format ); + for ( col = 0; col < cols; ++col ) + putbit( bitrow[col] ); + putrow( ); + } + flushrow (); + + pm_close( ifp ); + + exit( 0 ); + } diff --git a/converter/pbm/pbmtoibm23xx.c b/converter/pbm/pbmtoibm23xx.c index a83e260d..9f530b48 100644 --- a/converter/pbm/pbmtoibm23xx.c +++ b/converter/pbm/pbmtoibm23xx.c @@ -84,7 +84,7 @@ parseCommandLine(int argc, char ** const argv, opt.short_allowed = 0; opt.allowNegNum = 0; - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (!xresSpec) diff --git a/converter/pbm/pbmtoicon.c b/converter/pbm/pbmtoicon.c deleted file mode 100644 index d5fefb76..00000000 --- a/converter/pbm/pbmtoicon.c +++ /dev/null @@ -1,186 +0,0 @@ -/* pbmtoicon.c - read a PBM image and produce a Sun icon file -** -** Copyright (C) 1988 by Jef Poskanzer. -** -** Permission to use, copy, modify, and distribute this software and its -** documentation for any purpose and without fee is hereby granted, provided -** that the above copyright notice appear in all copies and that both that -** copyright notice and this permission notice appear in supporting -** documentation. This software is provided "as is" without express or -** implied warranty. -*/ - -/* 2006.10 (afu) - Changed bitrow from plain to raw, read function from pbm_readpbmrow() to - pbm_readpbmrow_packed. Applied wordint to scoop up 16 bit output items. - putitem changed to better express the output format. - Retired bitwise transformation functions. -*/ - -#include "wordaccess.h" -#include "pbm.h" - -static unsigned short int itemBuff[8]; -static unsigned int itemCnt; /* takes values 0 to 8 */ -FILE * putFp; - - - -static void -putinit(FILE * const ofP) { - putFp = ofP; - itemCnt = 0; -} - - - -static void -putitem(wordint const item) { - - if (itemCnt == 8 ) { - /* Buffer is full. Write out one line. */ - int rc; - - rc = fprintf(putFp, - "\t0x%04x,0x%04x,0x%04x,0x%04x," - "0x%04x,0x%04x,0x%04x,0x%04x,\n", - itemBuff[0],itemBuff[1],itemBuff[2],itemBuff[3], - itemBuff[4],itemBuff[5],itemBuff[6],itemBuff[7]); - if (rc < 0) - pm_error("fprintf() failed to write Icon bitmap"); - - itemCnt = 0; - } - itemBuff[itemCnt++] = item & 0xffff; /* Only lower 16 bits are used */ -} - - - -static void -putterm(void) { - - unsigned int i; - - for (i = 0; i < itemCnt; ++i) { - int rc; - rc = fprintf(putFp, "%s0x%04x%c", i == 0 ? "\t" : "", itemBuff[i], - i == itemCnt - 1 ? '\n' : ','); - if (rc < 0) - pm_error("fprintf() failed to write Icon bitmap"); - } -} - - - -static void -writeIconHeader(FILE * const ofP, - unsigned int const width, - unsigned int const height) { - - int rc; - - rc = fprintf(ofP, - "/* Format_version=1, Width=%u, Height=%u", width, height); - if (rc < 0) - pm_error("fprintf() failed to write Icon header"); - - rc = fprintf(ofP, ", Depth=1, Valid_bits_per_item=16\n */\n"); - if (rc < 0) - pm_error("fprintf() failed to write Icon header"); -} - - - -static void -writeIcon(FILE * const ifP, - unsigned int const cols, - unsigned int const rows, - int const format, - FILE * const ofP) { - - unsigned int const wordintSize = sizeof(wordint) * 8; - /* wordintSize is usually 32 or 64 bits. Must be at least 24. */ - unsigned int const items = (cols + 15) / 16; - unsigned int const bitrowBytes = pbm_packed_bytes(cols); - unsigned int const pad = items * 16 - cols; - /* 'padleft' is added to the output. 'padbyte' is for cleaning - the input - */ - unsigned int const padleft = pad / 2; - unsigned int const padbyte = bitrowBytes * 8 - cols; - unsigned int const shift = (wordintSize - 24) + padleft; - - unsigned char * bitbuffer; - unsigned char * bitrow; - unsigned int row; - - bitbuffer = pbm_allocrow_packed(cols + wordintSize); - bitrow = &bitbuffer[1]; - bitbuffer[0] = 0; - bitrow[bitrowBytes] = 0; - - writeIconHeader(ofP, cols + pad, rows); - - putinit(ofP); - - for (row = 0; row < rows; ++row) { - unsigned int itemSeq; - pbm_readpbmrow_packed(ifP, bitrow, cols, format); - - /* Clear post-data junk in final partial byte */ - if (padbyte > 0) { - bitrow[bitrowBytes-1] >>= padbyte; - bitrow[bitrowBytes-1] <<= padbyte; - } - - for (itemSeq = 0; itemSeq < items; ++itemSeq) { - /* Scoop up bits, shift-align, send to format & print function. - - An item is 16 bits, typically spread over 3 bytes due to - left-padding. We use wordint here to scoop up 4 (or more) - consecutive bytes. An item always resides within the higher - 24 bits of each scoop. It is essential to use wordint - (or rather the wordaccess function bytesToWordInt() ); - simple long, uint_32t, etc. do not work for they are not - shift-tolerant. - */ - - wordint const scoop = bytesToWordint(&bitbuffer[itemSeq*2]); - putitem (scoop >> shift); - } - } - putterm(); -} - - - -int -main(int argc, - char * argv[]) { - - FILE * ifP; - int rows, cols; - int format; - const char * inputFileName; - - pbm_init(&argc, argv); - - if (argc-1 > 1) - pm_error("Too many arguments (%u). " - "Only argument is optional input file", argc-1); - if (argc-1 == 1) - inputFileName = argv[1]; - else - inputFileName = "-"; - - ifP = pm_openr(inputFileName); - - pbm_readpbminit(ifP, &cols, &rows, &format); - - writeIcon(ifP, cols, rows, format, stdout); - - pm_close(ifP); - - return 0; -} - diff --git a/converter/pbm/pbmtolj.c b/converter/pbm/pbmtolj.c index be28f635..0cceb4fe 100644 --- a/converter/pbm/pbmtolj.c +++ b/converter/pbm/pbmtolj.c @@ -94,7 +94,7 @@ parseCommandLine(int argc, char ** argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We may have parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (argc-1 == 0) @@ -162,7 +162,7 @@ putinit(struct cmdlineInfo const cmdline) { /* Set raster graphics resolution */ printf("\033*t%dR", cmdline.dpi); - /* Start raster graphics, relative adressing */ + /* Start raster graphics, relative addressing */ printf("\033*r1A"); bitsperitem = 1; @@ -545,7 +545,7 @@ main(int argc, char * argv[]) { struct cmdlineInfo cmdline; FILE * ifP; - bool eof; + int eof; pbm_init(&argc, argv); diff --git a/converter/pbm/pbmtomacp.c b/converter/pbm/pbmtomacp.c index 600cc407..df5cbb0c 100644 --- a/converter/pbm/pbmtomacp.c +++ b/converter/pbm/pbmtomacp.c @@ -1,296 +1,443 @@ -/* pbmtomacp.c - read a portable bitmap and produce a MacPaint bitmap file -** -** Copyright (C) 1988 by Douwe vand der Schaaf. -** -** Permission to use, copy, modify, and distribute this software and its -** documentation for any purpose and without fee is hereby granted, provided -** that the above copyright notice appear in all copies and that both that -** copyright notice and this permission notice appear in supporting -** documentation. This software is provided "as is" without express or -** implied warranty. +/*============================================================================= + pbmtomacp +=============================================================================== + Read a PBM file and produce a MacPaint bitmap file + + Copyright (C) 2015 by Akira Urushibata ("douso"). + + Replacement of a previous program of the same name written in 1988 + by Douwe van der Schaaf (...!mcvax!uvapsy!vdschaaf). + + Permission to use, copy, modify, and distribute this software and its + documentation for any purpose and without fee is hereby granted, provided + that the above copyright notice appear in all copies and that both that + copyright notice and this permission notice appear in supporting + documentation. This software is provided "as is" without express or implied + warranty. +=============================================================================*/ + +/* + + Implemention notes + + Header size is 512 bytes. There is no MacBinary header. + + White margin which is added for input files with small dimensions + is treated separately from the active image raster. The margins + are directly coded based on the number of rows/columns. + + Output file size never exceeds 53072 bytes. When -norle is specified, + output is always 53072 bytes. It is conceivable that decoders which + examine the size of Macpaint files (for general validation or for + determination of header type and size) do exist. + + The uncompressed output (-norle case) fully conforms to Macpaint + specifications. No special treatment by the decoder is required. */ -#include +#include #include "pm_c_util.h" #include "pbm.h" +#include "shhopt.h" +#include "mallocvar.h" +#include "runlength.h" #include "macp.h" -#define TRUE 1 -#define FALSE 0 -#define EQUAL 1 -#define UNEQUAL 0 - #define MIN3(a,b,c) (MIN((MIN((a),(b))),(c))) -static void fillbits ARGS(( bit **bits, bit **bitsr, int top, int left, int bottom, int right )); -static void writemacp ARGS(( bit **bits )); -static int packit ARGS(( bit *pb, bit *bits )); -static void filltemp ARGS(( bit *dest, bit *src )); -static void sendbytes ARGS(( bit *pb, register int npb )); -static void header ARGS(( void )); +struct CmdlineInfo { + /* All the information the user supplied in the command line, in a form + easy for the program to use. + */ + const char * inputFileName; /* File name of input file */ + unsigned int left; + unsigned int right; + unsigned int top; + unsigned int bottom; + unsigned int leftSpec; + unsigned int rightSpec; + unsigned int topSpec; + unsigned int bottomSpec; + bool norle; +}; -static FILE *fdout; -int -main(argc, argv) -int argc; -char *argv[]; -{ FILE *ifp; - register bit **bits, **bitsr; - int argn, rows, cols; - int left,bottom,right,top; - int lflg, rflg, tflg, bflg; - const char * const usage = "[-l left] [-r right] [-b bottom] [-t top] [pbmfile]"; - - - pbm_init( &argc, argv ); - - argn = 1; - fdout = stdout; - lflg = rflg = tflg = bflg = 0; - left = right = top = bottom = 0; /* To quiet compiler warning */ - - while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) - { switch ( argv[argn][1] ) - { case 'l': - lflg++; - argn++; - left = atoi( argv[argn] ); - break; - - case 'r': - rflg++; - argn++; - right = atoi( argv[argn] ); - break; - - case 't': - tflg++; - argn++; - top = atoi( argv[argn] ); - break; - - case 'b': - bflg++; - argn++; - bottom = atoi( argv[argn] ); - break; - - case '?': - default: - pm_usage( usage ); + +static void +parseCommandLine(int argc, + const char ** const argv, + struct CmdlineInfo * const cmdlineP) { +/*---------------------------------------------------------------------------- + Parse program command line described in Unix standard form by argc + and argv. Return the information in the options as *cmdlineP. +-----------------------------------------------------------------------------*/ + optEntry * option_def; /* malloc'ed */ + /* Instructions to OptParseOptions3 on how to parse our options. */ + optStruct3 opt; + + unsigned int norleSpec; + + unsigned int option_def_index; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENTRY */ + OPTENT3(0, "left", OPT_UINT, &cmdlineP->left, + &cmdlineP->leftSpec, 0); + OPTENT3(0, "right", OPT_UINT, &cmdlineP->right, + &cmdlineP->rightSpec, 0); + OPTENT3(0, "top", OPT_UINT, &cmdlineP->top, + &cmdlineP->topSpec, 0); + OPTENT3(0, "bottom", OPT_UINT, &cmdlineP->bottom, + &cmdlineP->bottomSpec, 0); + OPTENT3(0, "norle", OPT_FLAG, NULL, + &norleSpec, 0); + + opt.opt_table = option_def; + opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ + opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ + + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + cmdlineP->norle = norleSpec; + + if (argc-1 < 1) + cmdlineP->inputFileName = "-"; + else { + cmdlineP->inputFileName = argv[1]; + if (argc-1 > 1) + pm_error("Program takes zero or one argument (filename). You " + "specified %d", argc-1); } - ++argn; - } - if ( argn == argc ) - { ifp = stdin; - } - else - { ifp = pm_openr( argv[argn] ); - ++argn; - } + free(option_def); +} - if ( argn != argc ) - pm_usage( usage ); - bitsr = pbm_readpbm( ifp, &cols, &rows ); - pm_close( ifp ); +struct CropPadDimensions { + unsigned int imageWidth; /* Active image content */ + unsigned int imageHeight; + unsigned int leftCrop; /* Cols cropped off from input */ + unsigned int topCrop; /* Rows cropped off from input */ + unsigned int topMargin; /* White padding for output */ + unsigned int bottomMargin; + unsigned int leftMargin; +}; - bits = pbm_allocarray( MAX_COLS, MAX_LINES ); - if( !lflg ) - left = 0; - if( rflg ) - right = MIN3( right, cols - 1, left + MAX_COLS - 1 ); - else - right = MIN( cols - 1, left + MAX_COLS - 1 ); +static void +calculateCropPad(struct CmdlineInfo const cmdline, + unsigned int const cols, + unsigned int const rows, + struct CropPadDimensions * const cropPadP) { +/*-------------------------------------------------------------------------- + Validate -left -right -top -bottom from command line. + + Determine what rows, columns to take from input if any of these are + specified and return it as *cropPadP. + + 'cols and 'rows' are the dimensions of the input image. + + Center image if it is smaller than the fixed Macpaint format size. +----------------------------------------------------------------------------*/ + unsigned int const left = cmdline.leftSpec ? cmdline.left : 0; + unsigned int const top = cmdline.topSpec ? cmdline.top : 0; + + unsigned int right, bottom, width, height; + + if (cmdline.leftSpec) { + if (cmdline.rightSpec && left >= cmdline.right) + pm_error("-left value must be smaller than -right value"); + else if (left + 1 > cols) + pm_error("Specified -left value is beyond right edge " + "of input image"); + } + if (cmdline.topSpec) { + if (cmdline.bottomSpec && top >= cmdline.bottom) + pm_error("-top value must be smaller than -bottom value"); + else if (top + 1 > rows) + pm_error("Specified -top value is beyond bottom edge " + "of input image"); + } + if (cmdline.rightSpec) { + if (cmdline.right + 1 > cols) + pm_message("Specified -right value %u is beyond edge of " + "input image", cmdline.right); + + right = MIN3(cmdline.right, cols - 1, left + MACP_COLS - 1); + } else + right = MIN(cols - 1, left + MACP_COLS - 1); - if( !tflg ) - top = 0; + if (cmdline.bottomSpec) { + if (cmdline.bottom + 1 > rows) + pm_message("Specified -bottom value %u is beyond edge of " + "input image", cmdline.bottom); - if( bflg ) - bottom = MIN3( bottom, rows - 1, top + MAX_LINES - 1); - else - bottom = MIN( rows - 1, top + MAX_LINES - 1 ); + bottom = MIN3(cmdline.bottom, rows - 1, top + MACP_ROWS - 1); + } else + bottom = MIN(rows - 1, top + MACP_ROWS - 1); - if( right <= left || left < 0 || right - left + 1 > MAX_COLS ) - pm_error("error in right (= %d) and/or left (=%d)",right,left ); - if( bottom <= top || top < 0 || bottom - top + 1 > MAX_LINES ) - pm_error("error in bottom (= %d) and/or top (=%d)",bottom,top ); + cropPadP->leftCrop = left; + cropPadP->topCrop = top; - fillbits( bits, bitsr, top, left, bottom, right ); + assert(right >= left); - writemacp( bits ); + width = right - left + 1; + assert(width > 0 && width <= MACP_COLS); - exit( 0 ); + cropPadP->leftMargin = (MACP_COLS - width) / 2; + if (width < cols) + pm_message("%u of %u input columns will be output", width, cols); + + height = bottom - top + 1; + assert(height > 0 && height <= MACP_ROWS); + + cropPadP->topMargin = (MACP_ROWS - height) / 2; + cropPadP->bottomMargin = cropPadP->topMargin + height - 1; + + if (height < rows) + pm_message("%u out of %u input rows will be output", height, rows); + + cropPadP->imageWidth = width; + cropPadP->imageHeight = height; } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - */ -/* centreer het over te zenden plaatje in het MacPaint document - * - * Het plaatje wordt vanaf al of niet opgegeven (left, bottom) - * in een pbm bitmap van de juist macpaint afmetingen gezet, - * en eventueel afgekapt. - */ + static void -fillbits( bits, bitsr, top, left, bottom, right ) -bit **bits, **bitsr; -int top, left, bottom, right; -{ register bit *bi, *bir; - register int i, j; - register int bottomr, leftr, topr, rightr; - int width, height; - - width = right - left + 1; - leftr = (MAX_COLS - width) / 2; - rightr = leftr + width - 1; - - height = bottom - top + 1; - topr = ( MAX_LINES - height ) / 2; - bottomr = topr + height - 1; - - for( i = 0; i < topr; i++ ) - { bi = bits[i]; - for( j = 0; j < MAX_COLS; j++ ) - *bi++ = 0; - } - - for( i = topr; i <= bottomr; i++ ) - { bi = bits[i]; - { for( j = 0; j < leftr; j++ ) - *bi++ = 0; - bir = bitsr[ i - topr + top ]; - for( j = leftr; j <= rightr; j++ ) - *bi++ = bir[j - leftr + left]; - for( j = rightr + 1; j < MAX_COLS; j++ ) - *bi++ = 0; - } } - - for( i = bottomr + 1; i < MAX_LINES; i++ ) - { bi = bits[i]; - for( j = 0; j < MAX_COLS; j++ ) - *bi++ = 0; - } -} /* fillbits */ - -/* - - - - - - - - - - - - - - - - - - - - - - - - - - */ +writeMacpHeader(FILE * const ofP) { + + char const ch = 0x00; /* header contains nothing */ + + unsigned int i; + + for (i = 0; i < MACP_HEAD_LEN; ++i) + fputc(ch, ofP); +} + + static void -writemacp( bits ) -bit **bits; -{ register int i; - bit pb[MAX_COLS * 2]; - int npb; - - header(); - for( i=0; i < MAX_LINES; i++ ) - { npb = packit( pb, bits[i] ); - sendbytes( pb, npb ); - } -} /* writemacp */ - -/* - - - - - - - - - - - - - - - - - - - - - - - - - - */ - -/* pack regel van MacPaint doc in Apple's format - * return value = # of bytes in pb - */ -static int -packit( pb, bits ) - bit *pb, *bits; -{ register int charcount, npb, newcount, flg; - bit temp[72]; - bit *count, *srcb, *destb, save; - - srcb = bits; destb = temp; - filltemp( destb, srcb ); - srcb = temp; - destb = pb; - npb = 0; - charcount = BYTES_WIDE; - flg = EQUAL; - while( charcount ) { - save = *srcb++; - charcount--; - newcount = 1; - while( charcount && (*srcb == save) ) { - srcb++; - newcount++; - charcount--; - } - if( newcount > 2 ) { - count = destb++; - *count = 257 - newcount; - *destb++ = save; - npb += 2; - flg = EQUAL; - } else { - if( flg == EQUAL ) { - count = destb++; - *count = newcount - 1; - npb++; - } else - *count += newcount; - while( newcount-- ) { - *destb++ = save; - npb++; - } - flg = UNEQUAL; - } - } - return npb; -} /* packit */ - -/* - - - - - - - - - - - - - - - - - - - - - - - - - - */ +writeMacpRowUnpacked(const bit * const imageBits, + unsigned int const leftMarginCharCt, + unsigned int const imageColCharCt, + FILE * const ofP) { +/*-------------------------------------------------------------------------- + Encode (without compression) and output one row. The row comes divided into + three parts: left margin, image, right margin. +----------------------------------------------------------------------------*/ + char const marginByte = 0x00; /* White bits for margin */ + unsigned int const rightMarginCharCt = + MACP_COLCHARS - leftMarginCharCt - imageColCharCt; + + unsigned int i; + + fputc(MACP_COLCHARS - 1, ofP); + + for (i = 0; i < leftMarginCharCt; ++i) + fputc(marginByte, ofP); + + if (imageColCharCt > 0) + fwrite(imageBits, 1, imageColCharCt, ofP); + + for (i = 0; i < rightMarginCharCt; ++i) + fputc(marginByte, ofP); +} + + static void -filltemp( dest, src ) -bit *dest, *src; -{ register unsigned char ch, zero, acht; - register int i, j; - - zero = '\0'; - acht = 8; - i = BYTES_WIDE; - while( i-- ) - { ch = zero; - j = acht; - while( j-- ) - { ch <<= 1; - if( *src++ ) - ch++; +writeMacpRowPacked(const bit * const packedBits, + unsigned int const leftMarginCharCt, + unsigned int const imageColCharCt, + unsigned int const rightMarginCharCt, + FILE * const ofP) { +/*-------------------------------------------------------------------------- + Encode one row and write it to *ofP. + + As in the unpacked case, the row comes divided into three parts: left + margin, image, right margin. Unlike the unpacked case we need to know both + the size of the packed data and the size of the right margin. +----------------------------------------------------------------------------*/ + char const marginByte = 0x00; /* White bits for margin */ + + if (leftMarginCharCt > 0) { + fputc(257 - leftMarginCharCt, ofP); + fputc(marginByte, ofP); } - *dest++ = ch; - } -} /* filltemp */ -/* - - - - - - - - - - - - - - - - - - - - - - - - - - */ + if (imageColCharCt > 0) + fwrite(packedBits, 1, imageColCharCt, ofP); + + if (rightMarginCharCt > 0) { + fputc(257 - rightMarginCharCt, ofP); + fputc(marginByte, ofP); + } +} + + static void -sendbytes( pb, npb ) -bit *pb; -register int npb; -{ register bit *b; +writeMacpRow(bit * const imageBits, + unsigned int const leftMarginCharCt, + unsigned int const imageColCharCt, + bool const norle, + FILE * const ofP) { +/*-------------------------------------------------------------------------- + Write the row 'imageBits' to Standard Output. + + Write it packed, unless packing would lead to unnecessary bloat or 'norle' + is true. +----------------------------------------------------------------------------*/ + if (norle) + writeMacpRowUnpacked(imageBits, leftMarginCharCt, imageColCharCt, ofP); + else { + unsigned int const rightMarginCharCt = + MACP_COLCHARS - leftMarginCharCt - imageColCharCt; + unsigned char packedBits[MACP_COLCHARS+1]; + size_t packedImageLength; + + if (pm_rlenc_maxbytes(MACP_COLCHARS, PM_RLE_PACKBITS) + > MACP_COLCHARS + 1) + pm_error("INTERNAL ERROR: RLE buffer too small"); + + pm_rlenc_compressbyte(imageBits, packedBits, PM_RLE_PACKBITS, + imageColCharCt, &packedImageLength); + + if (packedImageLength + + (leftMarginCharCt > 0 ? 1 : 0) * 2 + + (rightMarginCharCt > 0 ? 1 : 0) * 2 + < MACP_COLCHARS) { + /* It's smaller compressed, so do that */ + writeMacpRowPacked(packedBits, leftMarginCharCt, + packedImageLength, rightMarginCharCt, ofP); + } else { /* Extremely rare */ + /* It's larger compressed, so do it uncompressed. See note + at top of file. + */ + writeMacpRowUnpacked(imageBits, leftMarginCharCt, imageColCharCt, + ofP); + } + } +} - b = pb; - while( npb-- ) - (void) putc( *b++, fdout ); -} /* sendbytes */ -/* - - - - - - - - - - - - - - - - - - - - - - - - - - */ static void -header() -{ register int i; - register char ch; - - /* header contains nothing ... */ - ch = '\0'; - for(i = 0; i < HEADER_LENGTH; i++ ) - (void) putc( ch, fdout ); -} /* header */ +encodeRowsWithShift(bit * const bitrow, + FILE * const ifP, + int const inCols, + int const format, + bool const norle, + struct CropPadDimensions const cropPad, + FILE * const ofP) { +/*-------------------------------------------------------------------------- + Shift input rows to put only specified columns to output. Add padding on + left and right if necessary. + + No shift if the input image is the exact size (576 columns) of the Macpaint + format. If the input image is too wide and -left was not specified, extra + content on the right is discarded. +----------------------------------------------------------------------------*/ + unsigned int const offset = + (cropPad.leftMargin + 8 - cropPad.leftCrop % 8) % 8; + unsigned int const leftTrim = + cropPad.leftMargin % 8; + unsigned int const rightTrim = + (8 - (leftTrim + cropPad.imageWidth) % 8 ) % 8; + unsigned int const startChar = + (cropPad.leftCrop + offset) / 8; + unsigned int const imageCharCt = + pbm_packed_bytes(leftTrim + cropPad.imageWidth); + unsigned int const leftMarginCharCt = + cropPad.leftMargin / 8; + + unsigned int row; + + for (row = 0; row < cropPad.imageHeight; ++row) { + pbm_readpbmrow_bitoffset(ifP, bitrow, inCols, format, offset); + + /* Trim off fractional margin portion in first byte of image data */ + if (leftTrim > 0) { + bitrow[startChar] <<= leftTrim; + bitrow[startChar] >>= leftTrim; + } + /* Do the same with bits in last byte of relevant image data */ + if (rightTrim > 0) { + bitrow[startChar + imageCharCt - 1] >>= rightTrim; + bitrow[startChar + imageCharCt - 1] <<= rightTrim; + } + + writeMacpRow(&bitrow[startChar], leftMarginCharCt, + imageCharCt, norle, ofP); + } +} + + + +static void +writeMacp(unsigned int const cols, + unsigned int const rows, + int const format, + FILE * const ifP, + bool const norle, + struct CropPadDimensions const cropPad, + FILE * const ofP) { + + unsigned int row, skipRow; + bit * bitrow; + + writeMacpHeader(ofP); + + /* Write top padding */ + for (row = 0; row < cropPad.topMargin; ++row) + writeMacpRow(NULL, MACP_COLCHARS, 0, norle, ofP); + + /* Allocate PBM row with one extra byte for the shift case. */ + bitrow = pbm_allocrow_packed(cols + 8); + + for (skipRow = 0; skipRow < cropPad.topCrop; ++skipRow) + pbm_readpbmrow_packed(ifP, bitrow, cols, format); + + encodeRowsWithShift(bitrow, ifP, cols, format, norle, cropPad, ofP); + + pbm_freerow_packed(bitrow); + + /* Add bottom padding */ + for (row = cropPad.bottomMargin + 1; row < MACP_ROWS; ++row) + writeMacpRow(NULL, MACP_COLCHARS, 0, norle, ofP); +} + + + +int +main(int argc, const char *argv[]) { + + FILE * ifP; + int rows, cols; + int format; + struct CmdlineInfo cmdline; + struct CropPadDimensions cropPad; + + pm_proginit(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + ifP = pm_openr(cmdline.inputFileName); + + pbm_readpbminit(ifP, &cols, &rows, &format); + + calculateCropPad(cmdline, cols, rows, &cropPad); + + writeMacp(cols, rows, format, ifP, cmdline.norle, cropPad, stdout); + + pm_close(ifP); + + return 0; +} + diff --git a/converter/pbm/pbmtomatrixorbital.c b/converter/pbm/pbmtomatrixorbital.c index 96e1406a..41f8e260 100644 --- a/converter/pbm/pbmtomatrixorbital.c +++ b/converter/pbm/pbmtomatrixorbital.c @@ -1,3 +1,5 @@ +#include + #include "pbm.h" /* By Bryan Henderson, San Jose CA 2003.09.06. @@ -12,10 +14,10 @@ static void -generateMo(FILE * const ofP, - bit ** const bits, - int const cols, - int const rows) { +generateMo(FILE * const ofP, + bit ** const bits, + unsigned int const cols, + unsigned int const rows) { unsigned int col; @@ -51,37 +53,40 @@ generateMo(FILE * const ofP, int -main(int argc, char * argv[]) { +main(int argc, const char ** argv) { - FILE* ifp; - bit** bits; + FILE * ifP; + bit ** bits; int rows, cols; const char * inputFilename; - pbm_init(&argc, argv); + pm_proginit(&argc, argv); if (argc-1 > 1) - pm_error("Too many arguments (%d). The only valid argument is an " + pm_error("Too many arguments (%u). The only valid argument is an " "input file name.", argc-1); else if (argc-1 == 1) inputFilename = argv[1]; else inputFilename = "-"; - ifp = pm_openr(inputFilename); + ifP = pm_openr(inputFilename); - bits = pbm_readpbm(ifp, &cols, &rows); + bits = pbm_readpbm(ifP, &cols, &rows); if (rows > 255) - pm_error("Image is too high: %d rows. Max height: 255 rows", rows); + pm_error("Image is too high: %u rows. Max height: 255 rows", rows); if (cols > 255) - pm_error("Image is too wide: %d cols. Max width: 255 cols", cols); + pm_error("Image is too wide: %u cols. Max width: 255 cols", cols); generateMo(stdout, bits, cols, rows); - pm_close(ifp); + pm_close(ifP); pbm_freearray(bits, rows); - exit(0); + return 0; } + + + diff --git a/converter/pbm/pbmtomgr.c b/converter/pbm/pbmtomgr.c index d12e6635..e8e30148 100644 --- a/converter/pbm/pbmtomgr.c +++ b/converter/pbm/pbmtomgr.c @@ -89,11 +89,7 @@ main(int argc, size_t bytesWritten; pbm_readpbmrow_packed(ifP, bitrow, cols, format); - - if (padright > 0) { - bitrow[bytesPerRow-1] >>= padright; - bitrow[bytesPerRow-1] <<= padright; - } + pbm_cleanrowend_packed(bitrow, cols); bytesWritten = fwrite(bitrow, 1, bytesPerRow, stdout); if (bytesWritten != bytesPerRow ) diff --git a/converter/pbm/pbmtonokia.c b/converter/pbm/pbmtonokia.c index b8057393..bf3b9e41 100644 --- a/converter/pbm/pbmtonokia.c +++ b/converter/pbm/pbmtonokia.c @@ -4,6 +4,7 @@ Copyright information is at end of file. */ +#define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */ #define _BSD_SOURCE /* Make sure strcaseeq() is in nstring.h */ #include #include @@ -45,7 +46,7 @@ uppercase(const char * const subject) { if (buffer == NULL) pm_error("Out of memory allocating buffer for uppercasing a " - "%u-character string", strlen(subject)); + "%u-character string", (unsigned)strlen(subject)); else { unsigned int i; @@ -69,7 +70,7 @@ parseCommandLine(int argc, char ** argv, was passed to us as the argv array. -----------------------------------------------------------------------------*/ optEntry * option_def; - /* Instructions to optParseOptions3 on how to parse our options. + /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; @@ -92,7 +93,7 @@ parseCommandLine(int argc, char ** argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (fmtSpec) { @@ -117,8 +118,8 @@ parseCommandLine(int argc, char ** argv, if (netSpec) { if (strlen(netOpt) != 6) pm_error("-net option must be 6 hex digits long. " - "You specified %u characters", strlen(netOpt)); - else if (!strishex(netOpt)) + "You specified %u characters", (unsigned)strlen(netOpt)); + else if (!pm_strishex(netOpt)) pm_error("-net option must be hexadecimal. You specified '%s'", netOpt); else @@ -131,7 +132,7 @@ parseCommandLine(int argc, char ** argv, else if (strlen(cmdlineP->txt) > 120) pm_error("Text message is longer (%u characters) than " "the 120 characters allowed by the format.", - strlen(cmdlineP->txt)); + (unsigned)strlen(cmdlineP->txt)); if (argc-1 == 0) cmdlineP->inputFileName = "-"; @@ -147,7 +148,7 @@ parseCommandLine(int argc, char ** argv, static void freeCmdline(struct cmdlineInfo const cmdline) { - strfree(cmdline.networkCode); + pm_strfree(cmdline.networkCode); } @@ -253,7 +254,7 @@ convertToHexNpm(bit ** const image, unsigned int it; - fprintf(ofP, "00%04X", len); + fprintf(ofP, "00%04X", (unsigned)len); for (it = 0; it < len; ++it) fprintf(ofP, "%02X", text[it]); diff --git a/converter/pbm/pbmtopi3.c b/converter/pbm/pbmtopi3.c index 1dbf1a71..791bcb50 100644 --- a/converter/pbm/pbmtopi3.c +++ b/converter/pbm/pbmtopi3.c @@ -1,4 +1,4 @@ -/* pbmtopi3.c - read a portable bitmap and produce a Atari Degas .pi3 file +/* pbmtopi3.c - read a PBM image and produce a Atari Degas .pi3 file ** ** Module created from other pbmplus tools by David Beckemeyer. ** @@ -12,107 +12,87 @@ ** implied warranty. */ +/* Output file should always be 32034 bytes. */ + #include -#include "pbm.h" #include "pm_c_util.h" +#include "pbm.h" -static void putinit ARGS(( void )); -static void putbit ARGS(( bit b )); -static void putrest ARGS(( void )); -static void putitem ARGS(( void )); - -int -main( argc, argv ) - int argc; - char* argv[]; - { - FILE* ifp; - bit* bitrow; - register bit* bP; - int inrows, incols, format, padright, row, col; - int const outcols = 640; - int const outrows = 400; - - pbm_init( &argc, argv ); - - if ( argc > 2 ) - pm_usage( "[pbmfile]" ); - - if ( argc == 2 ) - ifp = pm_openr( argv[1] ); - else - ifp = stdin; - - pbm_readpbminit( ifp, &incols, &inrows, &format ); - bitrow = pbm_allocrow( MAX(incols, outcols) ); - - /* Compute padding to round cols up to 640 */ - if(incols < outcols) - padright = outcols - incols; - else - padright = 0; - - putinit( ); - for ( row = 0; row < MIN(inrows, outrows); ++row ) - { - pbm_readpbmrow( ifp, bitrow, incols, format ); - for ( col = 0, bP = bitrow; col < MIN(incols, outcols); ++col, ++bP ) - putbit( *bP ); - for ( col = 0; col < padright; ++col ) - putbit( 0 ); - } - while (row++ < outrows) - for ( col = 0; col < outcols; ++col) - putbit( 0 ); - - pm_close( ifp ); - - putrest( ); - - exit( 0 ); - } -static char item; -static short bitsperitem, bitshift; static void -putinit( ) - { - int i; - if (pm_writebigshort (stdout, (short) 2) == -1 - || pm_writebigshort (stdout, (short) 0x777) == -1) - pm_error ("write error"); - for (i = 1; i < 16; i++) - if (pm_writebigshort (stdout, (short) 0) == -1) - pm_error ("write error"); - item = 0; - bitsperitem = 0; - bitshift = 7; +putinit(FILE * const ofP) { + + unsigned int i; + + pm_writebigshort(ofP, (short) 2); + pm_writebigshort(ofP, (short) 0x777); + + for (i = 1; i < 16; ++i) { + pm_writebigshort (ofP, (short) 0); } +} -static void -putbit( bit b ) - { - if (bitsperitem == 8) - putitem( ); - ++bitsperitem; - if ( b == PBM_BLACK ) - item += 1 << bitshift; - --bitshift; + + +int +main(int argc, const char ** argv) { + + unsigned int const outRows = 400; + unsigned int const outCols = 640; + unsigned int const outColByteCt = pbm_packed_bytes(outCols); + + FILE * ifP; + + int inRows, inCols, format; + unsigned int row; + unsigned int inColByteCt; + unsigned int i; + bit * bitrow; + + pm_proginit(&argc, argv); + + if (argc-1 < 1) + ifP = stdin; + else { + ifP = pm_openr(argv[1]); + + if (argc-1 > 1) + pm_error("Too many arguments. The only possible argument " + "is the input file name"); } -static void -putrest( ) - { - if ( bitsperitem > 0 ) - putitem( ); + pbm_readpbminit(ifP, &inCols, &inRows, &format); + + inColByteCt = pbm_packed_bytes(inCols); + + bitrow = pbm_allocrow_packed(MAX(outCols, inCols)); + + /* Add padding to round cols up to 640 */ + for (i = inColByteCt; i < outColByteCt; ++i) + bitrow[i] = 0x00; + + putinit(stdout); + + for (row = 0; row < MIN(inRows, outRows); ++row) { + pbm_readpbmrow_packed(ifP, bitrow, inCols, format); + pbm_cleanrowend_packed(bitrow, inCols); + fwrite (bitrow, outColByteCt, 1, stdout); } + pm_close(ifP); -static void -putitem( ) - { - putc (item, stdout); - item = 0; - bitsperitem = 0; - bitshift = 7; + if (row < outRows) { + unsigned int i; + + /* Clear entire row */ + for (i = 0; i < outColByteCt; ++i) + bitrow[i] = 0x00; + + while (row++ < outRows) + fwrite(bitrow, outColByteCt, 1, stdout); } + + pbm_freerow_packed(bitrow); + + return 0; +} diff --git a/converter/pbm/pbmtopk.c b/converter/pbm/pbmtopk.c index fc94f855..3948ae0d 100644 --- a/converter/pbm/pbmtopk.c +++ b/converter/pbm/pbmtopk.c @@ -1,7 +1,12 @@ /* pbmtopk, adapted from "pxtopk.c by tomas rokicki" by AJCD 1/8/90 - compile with: cc -o pbmtopk pbmtopk.c -lm -lpbm + References (retrieved May 31 2015): + Packed (PK) Font File Format + https://www.tug.org/TUGboat/tb06-3/tb13pk.pdf + + Tex Font Metric Files (TFM) + https://www.tug.org/TUGboat/tb06-1/tb11gf.pdf */ #define _BSD_SOURCE 1 /* Make sure strdup() is in string.h */ @@ -26,6 +31,29 @@ #define MAXPARAMS 30 #define NAMELENGTH 80 +/*----------------------------------------------------------------------- +Macros to handle fixed point numbers + +This program uses uses fixed-point numbers to store data where +normally a floating-point data type (float or double) would be +employed. + +Numbers that contain fractions are stored as signed integers. +The 20 least-significant bits are for the fractional part, the rest +(12 bits assuming that int is 32 bit) are for the integer part. +The technical term for this is "Q20" or "Q12.20" notation. + +Float/double data is converted to Q20 fixed point by multiplying +by 2^20 (= 1048576). The opposite conversion is conducted by +dividing by 2^20. + +The Q20 data must be within the range -16 < r < 16. The reason +behind this restriction is unclear. The program generally writes +Q20 data to the output files in 32 bits. (Exception: in function +shipchar() there is a provision to write Q20 data in 24 bits, +provided that 24 bits is sufficient.) +---------------------------------------------------------------------*/ + #define fixword(d) ((int)((double)(d)*1048576)) #define unfixword(f) ((double)(f) / 1048576) #define fixrange(f) ((f) < 16777216 && (f) > -16777216) diff --git a/converter/pbm/pbmtoppa/Makefile b/converter/pbm/pbmtoppa/Makefile index 5f205230..cf31ded6 100644 --- a/converter/pbm/pbmtoppa/Makefile +++ b/converter/pbm/pbmtoppa/Makefile @@ -9,17 +9,18 @@ include $(BUILDDIR)/config.mk all: pbmtoppa -BINARIES = pbmtoppa +PORTBINARIES = pbmtoppa + +BINARIES = $(PORTBINARIES) MERGEBINARIES = $(BINARIES) -OBJECTS = pbmtoppa.o ppa.o pbm.o cutswath.o -MERGE_OBJECTS = pbmtoppa.o2 ppa.o pbm.o cutswath.o +ADDL_OBJECTS = ppa.o pbm.o cutswath.o -include $(SRCDIR)/common.mk +OBJECTS = pbmtoppa.o $(ADDL_OBJECTS) -pbmtoppa: $(OBJECTS) $(NETPBMLIB) $(LIBOPT) - $(LD) -o pbmtoppa $(OBJECTS) \ - -lm $(shell $(LIBOPT) $(NETPBMLIB)) $(LDFLAGS) $(LDLIBS) \ - $(RPATH) $(LADD) +MERGE_OBJECTS = pbmtoppa.o2 $(ADDL_OBJECTS) + +include $(SRCDIR)/common.mk +pbmtoppa: $(OBJECTS) diff --git a/converter/pbm/pbmtopsg3.c b/converter/pbm/pbmtopsg3.c index 54d0a0a0..8163b70a 100644 --- a/converter/pbm/pbmtopsg3.c +++ b/converter/pbm/pbmtopsg3.c @@ -60,7 +60,7 @@ parseCommandLine(int argc, char ** argv, opt.short_allowed = FALSE; opt.allowNegNum = FALSE; - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); if (argc-1 == 0) cmdlineP->inputFilespec = "-"; @@ -323,7 +323,7 @@ doPages(FILE * const ifP, unsigned int * const pagesP, double const dpi) { - bool eof; + int eof; unsigned int pagesDone; eof = FALSE; diff --git a/converter/pbm/pbmtoptx.c b/converter/pbm/pbmtoptx.c index 8cd60326..c0fb0f80 100644 --- a/converter/pbm/pbmtoptx.c +++ b/converter/pbm/pbmtoptx.c @@ -12,84 +12,79 @@ #include "pbm.h" -static void putinit ARGS(( void )); -static void putbit ARGS(( bit b )); -static void putrest ARGS(( void )); -static void putitem ARGS(( void )); +/* Follwing is obtained by reversing bit order (MFS-LFS) and adding 64. */ +/* Note the two escape sequences: \\ and \x7f . */ -int -main( argc, argv ) -int argc; -char *argv[]; - { - FILE *ifp; - register bit *bitrow, *bP; - int rows, cols, format, row, col; - const char * const usage = "[pbmfile]"; - - pbm_init( &argc, argv ); - - if ( argc > 2 ) - pm_usage( usage ); - - if ( argc == 2 ) - ifp = pm_openr( argv[1] ); - else - ifp = stdin; - - pbm_readpbminit( ifp, &cols, &rows, &format ); - bitrow = pbm_allocrow( cols ); - - putinit( ); - for ( row = 0; row < rows; row++ ) - { - pbm_readpbmrow( ifp, bitrow, cols, format ); - for ( col = 0, bP = bitrow; col < cols; col++, bP++ ) - putbit( *bP ); - putrest( ); - putchar( 5 ); - putchar( '\n' ); - } +static unsigned char const ptxchar[64] = + "@`PpHhXxDdTtLl\\|BbRrJjZzFfVvNn^~AaQqIiYyEeUuMm]}CcSsKk[{GgWwOo_\x7f"; - pm_close( ifp ); - - exit( 0 ); - } -static char item; -static int bitsperitem, bitshift; static void -putinit( ) - { - bitsperitem = 0; - item = 64; - bitshift = 0; - } +putBitrow(const bit * const bitrow, + unsigned int const cols) { +/*---------------------------------------------------------------------------- + Pick up items in 6 bit units from bitrow and convert each to ptx format. +----------------------------------------------------------------------------*/ + unsigned int itemCnt; -static void -putbit( bit b ) - { - if ( bitsperitem == 6 ) - putitem( ); - if ( b == PBM_BLACK ) - item += 1 << bitshift; - bitsperitem++; - bitshift++; + for (itemCnt = 0; itemCnt * 6 < cols; ++itemCnt) { + unsigned int const byteCnt = (itemCnt * 6) / 8; + bit const byteCur = bitrow[byteCnt]; + bit const byteNext = bitrow[byteCnt + 1]; + + unsigned int item; + + switch (itemCnt % 4) { + case 0: item = byteCur >> 2; break; + case 1: item = byteCur << 4 | byteNext >> 4; break; + case 2: item = byteCur << 2 | byteNext >> 6; break; + case 3: item = byteCur; break; + } + putchar(ptxchar[item & 0x3f]); } + putchar(5); putchar('\n'); /* end of row mark */ +} -static void -putrest( ) - { - if ( bitsperitem > 0 ) - putitem( ); + + +int +main(int argc, const char ** argv) { + + FILE * ifP; + bit * bitrow; + int rows, cols, format; + unsigned int row; + + pm_proginit(&argc, argv); + + if (argc-1 < 1) + ifP = stdin; + else { + ifP = pm_openr(argv[1]); + + if (argc-1 > 1) + pm_error("Too many arguments. The only possible argument is " + "the input fil name"); } -static void -putitem( ) - { - putchar( item ); - bitsperitem = 0; - item = 64; - bitshift = 0; + pbm_readpbminit(ifP, &cols, &rows, &format); + + bitrow = pbm_allocrow_packed(cols + 8); + + bitrow[pbm_packed_bytes(cols)] = 0x00; + + for (row = 0; row < rows; ++row) { + pbm_readpbmrow_packed(ifP, bitrow, cols, format); + pbm_cleanrowend_packed(bitrow, cols); + putBitrow(bitrow, cols); } + + pbm_freerow_packed(bitrow); + pm_close(ifP); + + return 0; +} + + + diff --git a/converter/pbm/pbmtosunicon.c b/converter/pbm/pbmtosunicon.c new file mode 100644 index 00000000..95deab7c --- /dev/null +++ b/converter/pbm/pbmtosunicon.c @@ -0,0 +1,165 @@ +/* pbmtosunicon.c - read a PBM image and produce a Sun icon file +** +** Copyright (C) 1988 by Jef Poskanzer. +** +** Permission to use, copy, modify, and distribute this software and its +** documentation for any purpose and without fee is hereby granted, provided +** that the above copyright notice appear in all copies and that both that +** copyright notice and this permission notice appear in supporting +** documentation. This software is provided "as is" without express or +** implied warranty. +*/ + +/* 2006.10 (afu) + Changed bitrow from plain to raw, read function from pbm_readpbmrow() to + pbm_readpbmrow_packed. Applied wordint to scoop up 16 bit output items. + putitem changed to better express the output format. + Retired bitwise transformation functions. +*/ + +#include "pm_config.h" +#include "pbm.h" + +static struct ItemPutter { + unsigned short int itemBuff[8]; + unsigned int itemCnt; /* takes values 0 to 8 */ + FILE * putFp; +} ip; + + + +static void +putinit(FILE * const ofP) { + ip.putFp = ofP; + ip.itemCnt = 0; +} + + + +static void +putitem(uint16_t const item) { + + if (ip.itemCnt == 8 ) { + /* Buffer is full. Write out one line. */ + int rc; + + rc = fprintf(ip.putFp, + "\t0x%04x,0x%04x,0x%04x,0x%04x," + "0x%04x,0x%04x,0x%04x,0x%04x,\n", + ip.itemBuff[0], ip.itemBuff[1], + ip.itemBuff[2], ip.itemBuff[3], + ip.itemBuff[4], ip.itemBuff[5], + ip.itemBuff[6], ip.itemBuff[7]); + if (rc < 0) + pm_error("fprintf() failed to write Icon bitmap"); + + ip.itemCnt = 0; + } + ip.itemBuff[ip.itemCnt++] = item & 0xffff; + /* Only lower 16 bits are used */ +} + + + +static void +putterm(void) { + + unsigned int i; + + for (i = 0; i < ip.itemCnt; ++i) { + int rc; + rc = fprintf(ip.putFp, "%s0x%04x%c", i == 0 ? "\t" : "", + ip.itemBuff[i], + i == ip.itemCnt - 1 ? '\n' : ','); + if (rc < 0) + pm_error("fprintf() failed to write Icon bitmap"); + } +} + + + +static void +writeIconHeader(FILE * const ofP, + unsigned int const width, + unsigned int const height) { + + int rc; + + rc = fprintf(ofP, + "/* Format_version=1, Width=%u, Height=%u", width, height); + if (rc < 0) + pm_error("fprintf() failed to write Icon header"); + + rc = fprintf(ofP, ", Depth=1, Valid_bits_per_item=16\n */\n"); + if (rc < 0) + pm_error("fprintf() failed to write Icon header"); +} + + + +static void +writeIcon(FILE * const ifP, + unsigned int const cols, + unsigned int const rows, + int const format, + FILE * const ofP) { + + unsigned int const items = (cols + 15) / 16; + unsigned int const pad = items * 16 - cols; + + unsigned char * const bitrow = pbm_allocrow_packed(items * 16); + unsigned int row; + + bitrow[0] = bitrow[items * 2 - 1] = 0; + + writeIconHeader(ofP, cols + pad, rows); + + putinit(ofP); + + for (row = 0; row < rows; ++row) { + unsigned int itemSeq; + + pbm_readpbmrow_bitoffset(ifP, bitrow, cols, format, pad/2); + + for (itemSeq = 0; itemSeq < items; ++itemSeq) { + /* Read bits from bitrow, send to format & print function. */ + + putitem((bitrow[itemSeq*2]<<8) + bitrow[itemSeq*2+1]); + } + } + putterm(); + pbm_freerow_packed(bitrow); +} + + + +int +main(int argc, + char * argv[]) { + + FILE * ifP; + int rows, cols; + int format; + const char * inputFileName; + + pbm_init(&argc, argv); + + if (argc-1 > 1) + pm_error("Too many arguments (%u). " + "Only argument is optional input file", argc-1); + if (argc-1 == 1) + inputFileName = argv[1]; + else + inputFileName = "-"; + + ifP = pm_openr(inputFileName); + + pbm_readpbminit(ifP, &cols, &rows, &format); + + writeIcon(ifP, cols, rows, format, stdout); + + pm_close(ifP); + + return 0; +} + diff --git a/converter/pbm/pbmtoxbm.c b/converter/pbm/pbmtoxbm.c index 340642ce..14c6b85e 100644 --- a/converter/pbm/pbmtoxbm.c +++ b/converter/pbm/pbmtoxbm.c @@ -23,6 +23,7 @@ #define _BSD_SOURCE 1 /* Make sure strdup() is in string.h */ #define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */ +#include #include #include "pm_c_util.h" @@ -35,7 +36,7 @@ enum xbmVersion { X10, X11 }; -struct cmdlineInfo { +struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ @@ -46,8 +47,8 @@ struct cmdlineInfo { static void parseCommandLine(int argc, - char ** argv, - struct cmdlineInfo *cmdlineP ) { + const char ** argv, + struct CmdlineInfo *cmdlineP ) { /*---------------------------------------------------------------------------- Parse program command line described in Unix standard form by argc and argv. Return the information in the options as *cmdlineP. @@ -58,8 +59,8 @@ parseCommandLine(int argc, Note that the strings we return are stored in the storage that was passed to us as the argv array. We also trash *argv. -----------------------------------------------------------------------------*/ - optEntry *option_def; - /* Instructions to optParseOptions3 on how to parse our options. */ + optEntry * option_def; + /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; unsigned int option_def_index; @@ -76,14 +77,14 @@ parseCommandLine(int argc, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3( &argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (!nameSpec) cmdlineP->name = NULL; else if (strlen(cmdlineP->name) > 56) pm_error("Image name too long: %d chars. (max 56)", - strlen(cmdlineP->name)); + (unsigned)strlen(cmdlineP->name)); else if (!ISALPHA(cmdlineP->name[0]) && cmdlineP->name[0] !='_') pm_error("Image name '%s' starts with non-alphabet character.", cmdlineP->name); @@ -111,6 +112,7 @@ parseCommandLine(int argc, pm_error("Program takes zero or one argument (filename). You " "specified %u", argc-1); } + free(option_def); } @@ -242,18 +244,22 @@ puttermX10(void) { unsigned int i; + assert(itemCnt % 2 == 0); + for (i = 0; i < itemCnt; i += 2) { int rc; + assert(i + 1 < itemCnt); + rc = printf("%s0x%02x%02x%s", (i == 0) ? " " : "", itemBuff[i+1], itemBuff[i], - (i == itemCnt - 2) ? "" : ","); + (i + 2 >= itemCnt) ? "" : ","); if (rc < 0) - pm_error("Error writing end of X10 bitmap raster. " + pm_error("Error writing Item %u at end of X10 bitmap raster. " "printf() failed with errno %d (%s)", - errno, strerror(errno)); + i, errno, strerror(errno)); } } @@ -270,12 +276,12 @@ puttermX11(void) { rc = printf("%s0x%02x%s", (i == 0) ? " " : "", itemBuff[i], - (i == itemCnt - 1) ? "" : ","); + (i + 1 >= itemCnt) ? "" : ","); if (rc < 0) - pm_error("Error writing end of X11 bitmap raster. " + pm_error("Error writing Item %u at end of X11 bitmap raster. " "printf() failed with errno %d (%s)", - errno, strerror(errno)); + i, errno, strerror(errno)); } } @@ -319,8 +325,8 @@ writeXbmHeader(enum xbmVersion const xbmVersion, unsigned int const height, FILE * const ofP) { - printf("#define %s_width %d\n", name, width); - printf("#define %s_height %d\n", name, height); + printf("#define %s_width %u\n", name, width); + printf("#define %s_height %u\n", name, height); printf("static %s %s_bits[] = {\n", xbmVersion == X10 ? "short" : "char", name); @@ -337,8 +343,7 @@ convertRaster(FILE * const ifP, enum xbmVersion const xbmVersion) { unsigned int const bitsPerUnit = xbmVersion == X10 ? 16 : 8; - unsigned int const padright = - ((cols + bitsPerUnit - 1 ) / bitsPerUnit) * bitsPerUnit - cols; + unsigned int const padright = ROUNDUP(cols, bitsPerUnit) - cols; /* Amount of padding to round cols up to the nearest multiple of 8 (if x11) or 16 (if x10). */ @@ -352,21 +357,15 @@ convertRaster(FILE * const ifP, bitrow = pbm_allocrow_packed(cols + padright); for (row = 0; row < rows; ++row) { - int const bitrowInBytes = pbm_packed_bytes(cols); - int const padrightIn = bitrowInBytes * 8 - cols; - unsigned int i; pbm_readpbmrow_packed(ifP, bitrow, cols, format); + pbm_cleanrowend_packed(bitrow, cols); - if (padrightIn > 0) { - bitrow[bitrowInBytes - 1] >>= padrightIn; - bitrow[bitrowInBytes - 1] <<= padrightIn; - } - - if (padright >= 8) + if (padright >= 8) { + assert(bitrowBytes > 0); bitrow[bitrowBytes-1] = 0x00; - + } for (i = 0; i < bitrowBytes; ++i) putitem(bitrow[i]); } @@ -379,15 +378,15 @@ convertRaster(FILE * const ifP, int -main(int argc, - char * argv[]) { +main(int argc, + const char ** argv) { - struct cmdlineInfo cmdline; + struct CmdlineInfo cmdline; FILE * ifP; int rows, cols, format; const char * name; - pbm_init(&argc, argv); + pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); if (cmdline.name == NULL) @@ -403,9 +402,11 @@ main(int argc, convertRaster(ifP, cols, rows, format, stdout, cmdline.xbmVersion); - strfree(name); + pm_strfree(name); pm_close(ifP); return 0; } + + diff --git a/converter/pbm/pbmtoybm.c b/converter/pbm/pbmtoybm.c index 508e8e92..27ce6cb1 100644 --- a/converter/pbm/pbmtoybm.c +++ b/converter/pbm/pbmtoybm.c @@ -9,100 +9,89 @@ ** copyright notice and this permission notice appear in supporting ** documentation. This software is provided "as is" without express or ** implied warranty. +** +** Feb 2010 afu +** Added dimension check to prevent short int from overflowing +** Changed code style (ANSI-style function definitions, etc.) */ #include + +#include "pm.h" #include "pbm.h" +#include "bitreverse.h" #define YBM_MAGIC ( ( '!' << 8 ) | '!' ) +#define INT16MAX 32767 + +static void +putinit(int const cols, + int const rows) { + + pm_writebigshort(stdout, YBM_MAGIC); + pm_writebigshort(stdout, cols); + pm_writebigshort(stdout, rows); +} + -static void putinit ARGS(( int cols, int rows )); -static void putbit ARGS(( bit b )); -static void putrest ARGS(( void )); -static void putitem ARGS(( void )); int -main( argc, argv ) - int argc; - char* argv[]; - { - FILE* ifp; - bit* bitrow; - register bit* bP; - int rows, cols, format, padright, row, col; - - - pbm_init( &argc, argv ); - - if ( argc > 2 ) - pm_usage( "[pbmfile]" ); - if ( argc == 2 ) - ifp = pm_openr( argv[1] ); - else - ifp = stdin; - - pbm_readpbminit( ifp, &cols, &rows, &format ); - bitrow = pbm_allocrow( cols ); +main(int argc, const char *argv[]) { + + FILE * ifP; + bit * bitrow; + int rows; + int cols; + int format; + unsigned int row; + const char * inputFileName; + + pm_proginit(&argc, argv); + + if (argc-1 < 1) + inputFileName = "-"; + else { + inputFileName = argv[1]; + + if (argc-1 > 1) + pm_error("Too many arguments. The only argument is the optional " + "input file name"); + } + + ifP = pm_openr(inputFileName); + + pbm_readpbminit(ifP, &cols, &rows, &format); + + if (rows > INT16MAX || cols > INT16MAX) + pm_error("Input image is too large."); + + bitrow = pbm_allocrow_packed(cols + 8); - /* Compute padding to round cols up to the nearest multiple of 16. */ - padright = ( ( cols + 15 ) / 16 ) * 16 - cols; + putinit(cols, rows); + + bitrow[pbm_packed_bytes(cols + 8) - 1] = 0x00; + for (row = 0; row < rows; ++row) { + uint16_t * const itemrow = (uint16_t *) bitrow; + unsigned int const itemCt = (cols + 15) / 16; - putinit( cols, rows ); - for ( row = 0; row < rows; ++row ) - { - pbm_readpbmrow( ifp, bitrow, cols, format ); - for ( col = 0, bP = bitrow; col < cols; ++col, ++bP ) - putbit( *bP ); - for ( col = 0; col < padright; ++col ) - putbit( 0 ); - } + unsigned int i; - if ( ifp != stdin ) - fclose( ifp ); + pbm_readpbmrow_packed(ifP, bitrow, cols, format); + pbm_cleanrowend_packed(bitrow, cols); - putrest( ); + for (i = 0; i < pbm_packed_bytes(cols); ++i) + bitrow[i] = bitreverse[bitrow[i]]; - exit( 0 ); + for (i = 0; i < itemCt; ++i) + pm_writebigshort(stdout, itemrow[i]); } -static long item; -static int bitsperitem, bitshift; + pbm_freerow_packed(bitrow); -static void -putinit( cols, rows ) - int cols, rows; - { - pm_writebigshort( stdout, YBM_MAGIC ); - pm_writebigshort( stdout, cols ); - pm_writebigshort( stdout, rows ); - item = 0; - bitsperitem = 0; - bitshift = 0; - } + if (ifP != stdin) + fclose(ifP); -static void -putbit( bit b ) - { - if ( bitsperitem == 16 ) - putitem( ); - ++bitsperitem; - if ( b == PBM_BLACK ) - item += 1 << bitshift; - ++bitshift; - } + return 0; +} -static void -putrest( ) - { - if ( bitsperitem > 0 ) - putitem( ); - } -static void -putitem( ) - { - pm_writebigshort( stdout, item ); - item = 0; - bitsperitem = 0; - bitshift = 0; - } diff --git a/converter/pbm/pbmtozinc.c b/converter/pbm/pbmtozinc.c index 2df39f0d..66ec5582 100644 --- a/converter/pbm/pbmtozinc.c +++ b/converter/pbm/pbmtozinc.c @@ -1,4 +1,4 @@ -/* pbmtozinc.c - read a portable bitmap and produce an bitmap file +/* pbmtozinc.c - read a PBM image and produce a bitmap file ** in the format used by the Zinc Interface Library (v1.0) ** November 1990. ** @@ -21,108 +21,163 @@ #include #include +#include "mallocvar.h" #include "nstring.h" #include "pbm.h" -int -main(int argc, char * argv[]) { - - FILE* ifp; - bit* bitrow; - register bit* bP; - int rows, cols, format, padright, row; - register int col; - char name[100]; - char* cp; - int itemsperline; - register int bitsperitem; - register int item; - int firstitem; - const char * const hexchar = "084c2a6e195d3b7f"; - - pbm_init( &argc, argv ); - - if ( argc > 2 ) - pm_usage( "[pbmfile]" ); - - if ( argc == 2 ) - { - ifp = pm_openr( argv[1] ); - strcpy( name, argv[1] ); - if ( streq( name, "-" ) ) - strcpy( name, "noname" ); - - if ( ( cp = strchr( name, '.' ) ) != 0 ) +static void +parseCommandLine(int const argc, + const char ** const argv, + const char ** const inputFileNameP) { + + if (argc-1 > 0) { + *inputFileNameP = argv[1]; + + if (argc-1 > 1) + pm_error("To many arguments: %u. " + "The only possible argument is the " + "name of the input file", argc-1); + } else + *inputFileNameP = "-"; +} + + + +static const char * +imageName(const char * const inputFileName) { +/*---------------------------------------------------------------------------- + The image name to put in the Zinc file, based on the input file name + 'inputFileName' ("-" to indicate Standard Input). + + Result is newly malloc'ed space that Caller must free. +-----------------------------------------------------------------------------*/ + const char * retval; + + if (streq(inputFileName, "-")) + pm_asprintf(&retval, "noname"); + else { + char * nameBuf; + char * cp; + + MALLOCARRAY_NOFAIL(nameBuf, strlen(inputFileName) + 1); + + strcpy(nameBuf, inputFileName); + + cp = strchr(nameBuf, '.' ); + if (cp) *cp = '\0'; - } - else - { - ifp = stdin; - strcpy( name, "noname" ); - } - - pbm_readpbminit( ifp, &cols, &rows, &format ); - bitrow = pbm_allocrow( cols ); - - /* Compute padding to round cols up to the nearest multiple of 16. */ - padright = ( ( cols + 15 ) / 16 ) * 16 - cols; - - printf( "USHORT %s[] = {\n",name); - printf( " %d\n", cols ); - printf( " %d\n", rows ); - - itemsperline = 0; - bitsperitem = 0; - item = 0; - firstitem = 1; - -#define PUTITEM \ - { \ - if ( firstitem ) \ - firstitem = 0; \ - else \ - putchar( ',' ); \ - if ( itemsperline == 11 ) \ - { \ - putchar( '\n' ); \ - itemsperline = 0; \ - } \ - if ( itemsperline == 0 ) \ - putchar( ' ' ); \ - ++itemsperline; \ - putchar('0'); \ - putchar('x'); \ - putchar(hexchar[item & 15]); \ - putchar(hexchar[(item >> 4) & 15]); \ - putchar(hexchar[(item >> 8) & 15]); \ - putchar(hexchar[item >> 12]); \ - bitsperitem = 0; \ - item = 0; \ + + retval = nameBuf; } + return retval; +} -#define PUTBIT(b) \ - { \ - if ( bitsperitem == 16 ) \ - PUTITEM; \ - if ( (b) == PBM_BLACK ) \ - item += 1 << bitsperitem; \ - ++bitsperitem; \ + + +typedef struct { + unsigned int itemsperline; + uint16_t item; + unsigned int firstitem; +} Packer; + + + +static void +packer_init(Packer * const packerP) { + + packerP->itemsperline = 0; + packerP->firstitem = 1; +} + + + +static void +packer_putitem(Packer * const packerP) { + + if (packerP->firstitem) + packerP->firstitem = 0; + else + putchar(','); + + if (packerP->itemsperline == 11) { + putchar('\n'); + packerP->itemsperline = 0; } + if (packerP->itemsperline == 0) + putchar(' '); + + ++packerP->itemsperline; + printf ("0x%02x%02x", packerP->item & 255, packerP->item >> 8); - for ( row = 0; row < rows; ++row ) - { - pbm_readpbmrow( ifp, bitrow, cols, format ); - for ( col = 0, bP = bitrow; col < cols; ++col, ++bP ) - PUTBIT( *bP ); - for ( col = 0; col < padright; ++col ) - PUTBIT( 0 ); +} + + + +static void +writeRaster(FILE * const ifP, + unsigned int const rows, + unsigned int const cols, + int const format) { + + bit * const bitrow = pbm_allocrow_packed(cols + 8); + + Packer packer; + unsigned int row; + + packer_init(&packer); + + bitrow[pbm_packed_bytes(cols+8) -1 ] = 0x00; + + for (row = 0; row < rows; ++row) { + uint16_t * const itemrow = (uint16_t *) bitrow; + unsigned int const itemCt = (cols + 15 ) / 16; + + unsigned int i; + + pbm_readpbmrow_packed(ifP, bitrow, cols, format); + + pbm_cleanrowend_packed(bitrow, cols); + + for (i = 0; i < itemCt; ++i) { + packer.item = itemrow[i]; + packer_putitem(&packer); + } } + pbm_freerow_packed(bitrow); +} + + + +int +main(int argc, const char * argv[]) { + + const char * inputFileName; + FILE * ifP; + int rows, cols; + int format; + const char * name; + + pm_proginit(&argc, argv); + + parseCommandLine(argc, argv, &inputFileName); + + ifP = pm_openr(inputFileName); + + name = imageName(inputFileName); + + pbm_readpbminit(ifP, &cols, &rows, &format); + + printf("USHORT %s[] = {\n", name); + printf(" %d\n", cols); + printf(" %d\n", rows); + + writeRaster(ifP, rows, cols, format); + + printf("};\n"); + + pm_close(ifP); - pm_close( ifp ); - - if ( bitsperitem > 0 ) - PUTITEM; - printf( "};\n" ); + pm_strfree(name); return 0; } diff --git a/converter/pbm/pi3topbm.c b/converter/pbm/pi3topbm.c index 8b3b21e3..17b07d6f 100644 --- a/converter/pbm/pi3topbm.c +++ b/converter/pbm/pi3topbm.c @@ -22,91 +22,147 @@ */ #include + +#include "pm_c_util.h" +#include "mallocvar.h" +#include "shhopt.h" #include "pbm.h" + + +struct CmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + const char * inputFileName; /* Filename of input file */ + unsigned int debug; +}; + + + +static void +parseCommandLine(int argc, + const char ** argv, + struct CmdlineInfo * const cmdlineP) { +/* -------------------------------------------------------------------------- + Parse program command line described in Unix standard form by argc + and argv. Return the information in the options as *cmdlineP. + + If command line is internally inconsistent (invalid options, etc.), + issue error message to stderr and abort program. + + Note that the strings we return are stored in the storage that + was passed to us as the argv array. We also trash *argv. +--------------------------------------------------------------------------*/ + optEntry * option_def; + optStruct3 opt; + /* Instructions to pm_optParseOptions3 on how to parse our options. */ + unsigned int option_def_index; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENT3 */ + OPTENT3(0, "debug", OPT_FLAG, NULL, &cmdlineP->debug, 0); + + opt.opt_table = option_def; + opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ + opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ + + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + if (argc-1 < 1) + cmdlineP->inputFileName = "-"; + else { + cmdlineP->inputFileName = argv[1]; + + if (argc-1 > 1) + pm_error("Program takes zero or one argument (filename). You " + "specified %u", argc-1); + } +} + + + +static void +readAndValidateHeader(FILE * const ifP, + bool const debug, + bool * const reverseP) { + + short item; + + pm_readbigshort(ifP, &item); + + if (debug) + pm_message("resolution is %d", item); + + /* only handles hi-rez 640x400 */ + if (item != 2) + pm_error("bad resolution %d", item); + + pm_readbigshort(ifP, &item); + + *reverseP = (item == 0); + + { + unsigned int i; + + for (i = 1; i < 16; ++i) + pm_readbigshort (ifP, &item); + } +} + + + int -main(argc, argv) - int argc; - char *argv[]; -{ - int debug = 0; - FILE *f; - int x; - int i, k; - int c; - int rows, cols; - bit *bitrow; - short res; - int black, white; - const char * const usage = "[-debug] [pi3file]"; - int argn = 1; - - pbm_init( &argc, argv ); - - while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') - { - if (pm_keymatch(argv[1], "-debug", 2)) - debug = 1; - else - pm_usage (usage); - ++argn; - } - - if (argn == argc) - f = stdin; - else - { - f = pm_openr (argv[argn]); - ++argn; - } - - if (argn != argc) - pm_usage (usage); - - if (pm_readbigshort (f, &res) == -1) - pm_error ("EOF / read error"); - - if (debug) - pm_message ("resolution is %d", res); - - /* only handles hi-rez 640x400 */ - if (res != 2) - pm_error( "bad resolution" ); - - pm_readbigshort (f, &res); - if (res == 0) - { - black = PBM_WHITE; - white = PBM_BLACK; - } - else - { - black = PBM_BLACK; - white = PBM_WHITE; - } - - for (i = 1; i < 16; i++) - if (pm_readbigshort (f, &res) == -1) - pm_error ("EOF / read error"); - - cols = 640; - rows = 400; - pbm_writepbminit( stdout, cols, rows, 0 ); - bitrow = pbm_allocrow( cols ); - - for (i = 0; i < rows; ++i) { - x = 0; - while (x < cols) { - if ((c = getc(f)) == EOF) - pm_error( "end of file reached" ); - for (k = 0x80; k; k >>= 1) { - bitrow[x] = (k & c) ? black : white; - ++x; - } - } - pbm_writepbmrow( stdout, bitrow, cols, 0 ); - } - pm_close( f ); - pm_close( stdout ); - exit(0); +main(int argc, const char ** argv) { + + unsigned int const rows = 400; + unsigned int const cols = 640; + + struct CmdlineInfo cmdline; + FILE * ifP; + unsigned int row; + bit * bitrow; + bool reverse; + + pm_proginit(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + ifP = pm_openr(cmdline.inputFileName); + + readAndValidateHeader(ifP, cmdline.debug, &reverse); + + pbm_writepbminit(stdout, cols, rows, 0); + + bitrow = pbm_allocrow_packed(cols); + + for (row = 0; row < rows; ++row) { + unsigned int const colChars = cols / 8; + + unsigned int bytesReadCt; + + bytesReadCt = fread(bitrow, cols / 8, 1, ifP); + if (bytesReadCt != 1) { + if (feof(ifP)) + pm_error( "EOF reached while reading image data" ); + else + pm_error("read error while reading image data"); + } + + if (reverse) { + /* flip all pixels */ + unsigned int colChar; + for (colChar = 0; colChar < colChars; ++colChar) + bitrow[colChar] = ~bitrow[colChar]; + } + pbm_writepbmrow_packed(stdout, bitrow, cols, 0); + } + + pbm_freerow_packed(bitrow); + pm_close(ifP); + pm_close(stdout); + + return 0; } diff --git a/converter/pbm/thinkjettopbm.l b/converter/pbm/thinkjettopbm.l index 71501596..5de4f2bb 100644 --- a/converter/pbm/thinkjettopbm.l +++ b/converter/pbm/thinkjettopbm.l @@ -47,8 +47,15 @@ undefined. (Simply leaving them undefined typically works anyway, but it is a problem if you use compiler options that say to fail when someone uses a macro he failed to define). + + We'd like to define YY_NO_UNPUT so as not to generate the unput function, + which we don't use, and avoid a compiler warning about defining and not + using it. Alas, Flex 2.5.35 ignores YY_NO_UNPUT and generates the unput + function anyway. So we have to have a bogus reference to silence the + unused function compiler warning. And that means we have to generate + the function always. Flex 2.5.4 does respect YY_NO_UNPUT. */ -#define YY_NO_UNPUT +#define YY_NO_INPUT 1 #define YY_STACK_USED 0 #define YY_ALWAYS_INTERACTIVE 0 #define YY_NEVER_INTERACTIVE 0 @@ -151,7 +158,7 @@ parseCommandLine(int argc, char ** const argv, was passed to us as the argv array. -----------------------------------------------------------------------------*/ optEntry *option_def = malloc(100*sizeof(optEntry)); - /* Instructions to OptParseOptions3 on how to parse our options. + /* Instructions to pm_OptParseOptions3 on how to parse our options. */ optStruct3 opt; @@ -164,7 +171,7 @@ parseCommandLine(int argc, char ** const argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ @@ -200,6 +207,8 @@ main (int argc, char **argv) } debugFlag = cmdline.debug; yylex (); + if (0) + yyunput(0, NULL); /* defeat compiler warning about unused fn */ return 0; } diff --git a/converter/pbm/xbmtopbm.c b/converter/pbm/xbmtopbm.c index 9505ba67..bbf4e395 100644 --- a/converter/pbm/xbmtopbm.c +++ b/converter/pbm/xbmtopbm.c @@ -170,7 +170,7 @@ getXbmHeader(FILE * const ifP, if (strlen(line) == MAX_LINE - 1) pm_error("A line in the input file is %u characters long. " "%u is the maximum we can handle", - strlen(line), MAX_LINE-1); + (unsigned)strlen(line), MAX_LINE-1); parseWidthHeightLine(line, &gotWidth, widthP, &gotHeight, heightP); @@ -362,12 +362,8 @@ main(int argc, for (i = 0; i < bytesPerRow; ++i) bitrow[i] = bitreverse[*p++]; - - if (cols % 8 > 0) { - bitrow[bytesPerRow-1] >>= 8 - cols % 8; - bitrow[bytesPerRow-1] <<= 8 - cols % 8; - } - + + pbm_cleanrowend_packed(bitrow, cols); pbm_writepbmrow_packed(stdout, bitrow, cols, 0); } diff --git a/converter/pbm/ybmtopbm.c b/converter/pbm/ybmtopbm.c index 739e168a..2a429086 100644 --- a/converter/pbm/ybmtopbm.c +++ b/converter/pbm/ybmtopbm.c @@ -10,104 +10,101 @@ ** implied warranty. */ -#include +#include "pm.h" #include "pbm.h" +#include "bitreverse.h" -static void getinit ARGS(( FILE* file, short* colsP, short* rowsP, short* depthP, short* padrightP )); -static bit getbit ARGS(( FILE* file )); +static short const ybmMagic = ( ( '!' << 8 ) | '!' ); -#define YBM_MAGIC ( ( '!' << 8 ) | '!' ) -int -main( argc, argv ) - int argc; - char* argv[]; - { - FILE* ifp; - bit* bitrow; - register bit* bP; - short rows, cols, padright, row, col; - short depth; - pbm_init( &argc, argv ); +static void +getinit(FILE * const ifP, + short * const colsP, + short * const rowsP, + short * const depthP) { - if ( argc > 2 ) - pm_usage( "[ybmfile]" ); + short magic; + int rc; - if ( argc == 2 ) - ifp = pm_openr( argv[1] ); - else - ifp = stdin; + rc = pm_readbigshort(ifP, &magic); + if (rc == -1) + pm_error("EOF / read error"); - getinit( ifp, &cols, &rows, &depth, &padright ); - if ( depth != 1 ) - pm_error( - "YBM file has depth of %d, must be 1", - (int) depth ); + if (magic != ybmMagic) + pm_error("bad magic number in YBM file"); - pbm_writepbminit( stdout, cols, rows, 0 ); - bitrow = pbm_allocrow( cols ); + rc = pm_readbigshort(ifP, colsP); + if (rc == -1 ) + pm_error("EOF / read error"); - for ( row = 0; row < rows; ++row ) - { - /* Get data. */ - for ( col = 0, bP = bitrow; col < cols; ++col, ++bP ) - *bP = getbit( ifp ); - /* Discard line padding */ - for ( col = 0; col < padright; ++col ) - (void) getbit( ifp ); - pbm_writepbmrow( stdout, bitrow, cols, 0 ); - } + rc = pm_readbigshort(ifP, rowsP); + if (rc == -1) + pm_error("EOF / read error"); - pm_close( ifp ); - pm_close( stdout ); + *depthP = 1; +} - exit( 0 ); - } -static int item; -static int bitsperitem, bitshift; -static void -getinit( file, colsP, rowsP, depthP, padrightP ) - FILE* file; - short* colsP; - short* rowsP; - short* depthP; - short* padrightP; - { - short magic; - if ( pm_readbigshort( file, &magic ) == -1 ) - pm_error( "EOF / read error" ); - if ( magic != YBM_MAGIC ) - pm_error( "bad magic number in YBM file" ); - if ( pm_readbigshort( file, colsP ) == -1 ) - pm_error( "EOF / read error" ); - if ( pm_readbigshort( file, rowsP ) == -1 ) - pm_error( "EOF / read error" ); - *depthP = 1; - *padrightP = ( ( *colsP + 15 ) / 16 ) * 16 - *colsP; - bitsperitem = 0; + +int +main(int argc, const char * argv[]) { + + FILE * ifP; + bit * bitrow; + short rows, cols; + unsigned int row; + short depth; + const char * inputFile; + + pm_proginit(&argc, argv); + + if (argc-1 < 1) + inputFile = "-"; + else { + inputFile = argv[1]; + + if (argc-1 > 1) + pm_error("Too many arguments. The only argument is the optional " + "input file name"); } -static bit -getbit( file ) - FILE* file; - { - bit b; - - if ( bitsperitem == 0 ) - { - item = getc(file) | getc(file)<<8; - if ( item == EOF ) - pm_error( "EOF / read error" ); - bitsperitem = 16; - bitshift = 0; - } - b = ( ( item >> bitshift) & 1 ) ? PBM_BLACK : PBM_WHITE; - --bitsperitem; - ++bitshift; - return b; + ifP = pm_openr(inputFile); + + getinit(ifP, &cols, &rows, &depth); + if (depth != 1) + pm_error("YBM file has depth of %u, must be 1", (unsigned)depth); + + pbm_writepbminit(stdout, cols, rows, 0); + + bitrow = pbm_allocrow_packed(cols + 8); + + for (row = 0; row < rows; ++row) { + uint16_t * const itemrow = (uint16_t *) bitrow; + unsigned int const itemCt = (cols + 15) / 16; + + unsigned int i; + + /* Get raster. */ + for (i = 0; i < itemCt; ++i) { + short int item; + pm_readbigshort(ifP, &item); + itemrow[i] = (uint16_t) item; + } + + for (i = 0; i < pbm_packed_bytes(cols); ++i) + bitrow[i] = bitreverse[bitrow[i]]; + + pbm_cleanrowend_packed(bitrow, cols); + pbm_writepbmrow_packed(stdout, bitrow, cols, 0); } + + pbm_freerow_packed(bitrow); + pm_close(ifP); + pm_close(stdout); + + return 0; +} diff --git a/converter/pgm/Makefile b/converter/pgm/Makefile index b109683b..f7ff341e 100644 --- a/converter/pgm/Makefile +++ b/converter/pgm/Makefile @@ -8,8 +8,8 @@ VPATH=.:$(SRCDIR)/$(SUBDIR) include $(BUILDDIR)/config.mk PORTBINARIES = asciitopgm bioradtopgm fstopgm hipstopgm \ - lispmtopgm pgmtofs pgmtolispm pgmtopgm \ - psidtopgm spottopgm sbigtopgm + lispmtopgm pgmtofs pgmtolispm pgmtopgm pgmtosbig pgmtost4 \ + psidtopgm spottopgm sbigtopgm st4topgm MATHBINARIES = rawtopgm BINARIES = $(PORTBINARIES) $(MATHBINARIES) diff --git a/converter/pgm/asciitopgm.c b/converter/pgm/asciitopgm.c index a3a5bd48..f4179de8 100644 --- a/converter/pgm/asciitopgm.c +++ b/converter/pgm/asciitopgm.c @@ -1,4 +1,4 @@ -/* asciitopgm.c - read an ASCII graphics file and produce a portable graymap +/* asciitopgm.c - read an ASCII graphics file and produce a PGM ** ** Copyright (C) 1989 by Wilson H. Bent, Jr ** @@ -16,11 +16,11 @@ #include #include "pm_c_util.h" -#include "pgm.h" #include "mallocvar.h" #include "nstring.h" +#include "pgm.h" -static char gmap [128] = { +static unsigned int const gmap [128] = { /*00 nul-bel*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*08 bs -si */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*10 dle-etb*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -39,28 +39,160 @@ static char gmap [128] = { /*78 x -del*/ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, }; -static gray maxval = 127; +static gray const maxval = 127; + + + +static void +zeroObuf(unsigned int * const obuf, + unsigned int const cols) { + + unsigned int col; + for (col = 0; col < cols; ++col) + obuf[col] = 0; +} + + + +static void +convertRowToPgm(const unsigned int * const obuf, + unsigned int const cols, + gray const maxval, + gray * const grayrow) { + + unsigned int col; + + for (col = 0; col < cols; ++col) + grayrow[col] = maxval - MIN(maxval, obuf[col]); +} + + + +static bool warnedNonAscii; + +static unsigned int +darknessOfChar(char const c) { + + unsigned char asciifiedC; + + if (c & 0x80) { /* !isascii(c) */ + if (!warnedNonAscii) { + pm_message("Warning: non-ASCII char(s) in input"); + warnedNonAscii = true; + } + asciifiedC = c & 0x7f; /* toascii(c) */ + } else + asciifiedC = c; + + return gmap[asciifiedC]; +} + + + +static void +convertAsciiToPgm(FILE * const ifP, + unsigned int const cols, + unsigned int const rows, + unsigned int const divisor, + gray const maxval, + gray ** const grays, + unsigned int * const obuf) { + + unsigned int outRow; + unsigned int outCursor; + bool beginningOfImage; + bool beginningOfLine; + bool warnedTrunc; + bool eof; + + zeroObuf(obuf, cols); + + warnedNonAscii = false; + warnedTrunc = false; + outRow = 0; + outCursor = 0; + beginningOfImage = true; + beginningOfLine = true; + eof = false; + while (outRow < rows && !eof) { + int c; + + c = getc(ifP); + + if (c == EOF) + eof = true; + else { + if (beginningOfLine) { + if (c == '+') { + /* + at start of line means rest of line + overstrikes previous + */ + c = getc(ifP); + if (c == EOF) + eof = true; + } else { + if (!beginningOfImage) { + /* Output previous line, move to next */ + + convertRowToPgm(obuf, cols, maxval, grays[outRow]); + + zeroObuf(obuf, cols); + + ++outRow; + } + } + outCursor = 0; + beginningOfLine = false; + } + if (!eof) { + if (c == '\n') + beginningOfLine = true; + else { + if (outRow < rows && outCursor < cols) + obuf[outCursor++] += darknessOfChar(c) / divisor; + else { + if (!warnedTrunc) { + pm_message("Warning: " + "truncating image to %u columns " + "x %u rows", cols, rows); + warnedTrunc = true; + } + } + } + } + } + beginningOfImage = false; + } + while (outRow < rows) { + /* Output previous line, move to next */ + + convertRowToPgm(obuf, cols, maxval, grays[outRow]); + + zeroObuf(obuf, cols); + + ++outRow; + } +} + + int -main( argc, argv ) - int argc; - char *argv[]; -{ - FILE *ifd; - register gray **grays; - int argn, row; - register int c, i; - int rows = 0, cols = 0; - int divisor = 1; - bool warned; - int *obuf; +main(int argc, const char ** argv) { + + FILE * ifP; + gray ** grays; + int argn; + unsigned int rows, cols; + unsigned int divisor; + unsigned int * obuf; /* malloced */ const char * const usage = "[-d ] height width [asciifile]"; - char trunc; - - pgm_init( &argc, argv ); - warned = FALSE; + pm_proginit(&argc, argv); + rows = 0; /* initial value */ + cols = 0; /* initial value */ + divisor = 1; /* initial value */ + argn = 1; if ( argc < 3 || argc > 6 ) @@ -72,7 +204,7 @@ main( argc, argv ) { if ( argc == argn + 1 ) pm_usage( usage ); - if ( sscanf( argv[argn+1], "%d", &divisor ) != 1 ) + if ( sscanf( argv[argn+1], "%u", &divisor ) != 1 ) pm_usage( usage ); argn += 2; } @@ -80,9 +212,9 @@ main( argc, argv ) pm_usage( usage ); } - if ( sscanf( argv[argn++], "%d", &rows ) != 1 ) + if ( sscanf( argv[argn++], "%u", &rows ) != 1 ) pm_usage( usage ); - if ( sscanf( argv[argn++], "%d", &cols ) != 1 ) + if ( sscanf( argv[argn++], "%u", &cols ) != 1 ) pm_usage( usage ); if ( rows < 1 ) pm_error( "height is less than 1" ); @@ -93,86 +225,24 @@ main( argc, argv ) pm_usage( usage ); if ( argc == argn + 1 ) - ifd = pm_openr( argv[argn] ); + ifP = pm_openr(argv[argn]); else - ifd = stdin; - - /* Here's where the work is done: - * - Usually, the graymap value of the input char is summed into grays - * - For a 'normal' newline, the current row is adjusted by the divisor - * and the current row is incremented - * - If the first char in the input line is a '+', then the current row - * stays the same to allow 'overstriking' - * NOTE that we assume the user specified a sufficiently large width! - */ - MALLOCARRAY( obuf, cols ); - if ( obuf == NULL ) - pm_error( "Unable to allocate memory for %d columns.", cols); - else { - unsigned int col; - for (col = 0; col < cols; ++col) obuf[col] = 0; - } - grays = pgm_allocarray( cols, rows ); - row = i = trunc = 0; - while ( row < rows ) - { - switch (c = getc (ifd)) - { - case EOF: - goto line_done; - case '\n': - newline: - trunc = 0; - if ((c = getc (ifd)) == EOF) - goto line_done; - if (c == '+') - i = 0; - else - { - line_done: - for (i = 0; i < cols; ++i) - grays[row][i] = maxval - (obuf[i] / divisor); - { - unsigned int col; - for (col = 0; col < cols; ++col) obuf[col] = 0; - } - i = 0; - ++row; - if ( row >= rows ) - break; - if (c == '\n') - goto newline; - else if (c != EOF) - obuf[i++] += gmap[c]; - } - break; - default: - if (i == cols) - { - if (! trunc) - { - pm_message("Warning: row %d being truncated at %d columns", - row+1, cols); - trunc = 1; - } - continue; - } - if (c > 0x7f) /* !isascii(c) */ - { - if (!warned) - { - pm_message("Warning: non-ASCII char(s) in input"); - warned = TRUE; - } - c &= 0x7f; /* toascii(c) */ - } - obuf[i++] += gmap[c]; - break; - } - } - pm_close( ifd ); + ifP = stdin; + + MALLOCARRAY(obuf, cols); + if (obuf == NULL) + pm_error("Unable to allocate memory for %u columns", cols); + + grays = pgm_allocarray(cols, rows); + + convertAsciiToPgm(ifP, cols, rows, divisor, maxval, grays, obuf); + + pm_close(ifP); + + pgm_writepgm(stdout, grays, cols, rows, maxval, 0); - pgm_writepgm( stdout, grays, cols, rows, maxval, 0 ); + free(obuf); + pgm_freearray(grays, rows); return 0; } diff --git a/converter/pgm/fstopgm.c b/converter/pgm/fstopgm.c index 2c636f41..1f574604 100644 --- a/converter/pgm/fstopgm.c +++ b/converter/pgm/fstopgm.c @@ -12,127 +12,144 @@ #include +#include "pm.h" #include "pgm.h" -static int gethexit ARGS(( FILE* ifp )); + + +static int +gethexit(FILE * const ifP) { + + for ( ; ; ) { + unsigned int const i = getc(ifP); + + if (i == EOF) + pm_error("EOF / read error"); + else { + char const c = (char) i; + if (c >= '0' && c <= '9') + return c - '0'; + else if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + else if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + else { + /* Ignore - whitespace. */ + } + } + } +} + + + +static void +warnNonsquarePixels(unsigned int const cols, + unsigned int const xcols, + unsigned int const rows, + unsigned int const xrows) { + + const char * const baseMsg = "warning, non-square pixels"; + + if (pm_have_float_format()) { + float const rowratio = (float) xrows / (float) rows; + float const colratio = (float) xcols / (float) cols; + + pm_message("%s; to fix do a 'pamscale -%cscale %g'", + baseMsg, + rowratio > colratio ? 'y' : 'x', + rowratio > colratio ? + rowratio / colratio : colratio / rowratio); + } else + pm_message("%s", baseMsg); +} + + int -main( argc, argv ) -int argc; -char *argv[]; - { - FILE *ifp; - register gray **grays, *gP; - int argn, row; - register int col; - int maxval; - int rows = 0, cols = 0, depth = 0, xrows = 0, xcols = 0, xdepth = 0; +main(int argc, const char ** argv) { + + FILE * ifP; + gray ** grays; + int argn; + int row; + gray maxval; + int rows, cols, depth; + int xrows, xcols, xdepth; #define STRSIZE 1000 - char buf[STRSIZE], firstname[STRSIZE], lastname[STRSIZE], email[STRSIZE]; + pm_proginit(&argc, argv); - pgm_init( &argc, argv ); + rows = 0; + cols = 0; + depth = 0; + + xrows = 0; + xcols = 0; + xdepth = 0; argn = 1; - if ( argn < argc ) - { - ifp = pm_openr( argv[argn] ); - argn++; - } - else - ifp = stdin; + if (argn < argc) { + ifP = pm_openr(argv[argn]); + argn++; + } else + ifP = stdin; - if ( argn != argc ) - pm_usage( "[fsfile]" ); + if (argn != argc) + pm_error("Too many arguments. The only argument is the file name"); /* Read the FaceSaver(tm) header. */ - for ( ; ; ) - { - if ( fgets( buf, STRSIZE, ifp ) == (char *) 0 ) - pm_error( "error reading header" ); - - /* Blank line ends header. */ - if ( strlen( buf ) == 1 ) - break; - - if ( sscanf( buf, "FirstName: %[^\n]", firstname ) == 1 ) - ; - else if ( sscanf( buf, "LastName: %[^\n]", lastname ) == 1 ) - ; - else if ( sscanf( buf, "E-mail: %[^\n]", email ) == 1 ) - ; - else if ( sscanf( buf, "PicData: %d %d %d\n", - &cols, &rows, &depth ) == 3 ) - { - if ( depth != 8 ) - pm_error( - "can't handle 'PicData' depth other than 8" ); - } - else if ( sscanf( buf, "Image: %d %d %d\n", - &xcols, &xrows, &xdepth ) == 3 ) - { - if ( xdepth != 8 ) - pm_error( - "can't handle 'Image' depth other than 8" ); - } - } - if ( cols <= 0 || rows <= 0 ) - pm_error( "invalid header" ); - maxval = pm_bitstomaxval( depth ); - if ( maxval > PGM_OVERALLMAXVAL ) - pm_error( "depth %d is too large. Our maximum is %d", - maxval, PGM_OVERALLMAXVAL); - if ( xcols != 0 && xrows != 0 && ( xcols != cols || xrows != rows ) ) - { - float rowratio, colratio; - - rowratio = (float) xrows / (float) rows; - colratio = (float) xcols / (float) cols; - pm_message( - "warning, non-square pixels; to fix do a 'pamscale -%cscale %g'", - rowratio > colratio ? 'y' : 'x', - rowratio > colratio ? rowratio / colratio : colratio / rowratio ); - } - - /* Now read the hex bits. */ - grays = pgm_allocarray( cols, rows ); - for ( row = rows - 1; row >= 0; row--) - { - for ( col = 0, gP = grays[row]; col < cols; col++, gP++ ) - { - *gP = gethexit( ifp ) << 4; - *gP += gethexit( ifp ); - } - } - pm_close( ifp ); - - /* And write out the graymap. */ - pgm_writepgm( stdout, grays, cols, rows, (gray) maxval, 0 ); - pm_close( stdout ); - - exit( 0 ); + for ( ; ; ) { + char buf[STRSIZE]; + char firstname[STRSIZE]; + char lastname[STRSIZE]; + char email[STRSIZE]; + + char * const rc = fgets(buf, STRSIZE, ifP); + + if (rc == NULL) + pm_error("error reading header"); + + /* Blank line ends header. */ + if (strlen(buf) == 1) + break; + + if (sscanf(buf, "FirstName: %[^\n]", firstname) == 1); + else if (sscanf(buf, "LastName: %[^\n]", lastname) == 1); + else if (sscanf(buf, "E-mail: %[^\n]", email ) == 1); + else if (sscanf(buf, "PicData: %d %d %d\n", + &cols, &rows, &depth ) == 3) { + if (depth != 8) + pm_error("can't handle 'PicData' depth other than 8"); + } else if (sscanf(buf, "Image: %d %d %d\n", + &xcols, &xrows, &xdepth ) == 3) { + if (xdepth != 8) + pm_error("can't handle 'Image' depth other than 8"); + } } - -static int -gethexit( ifp ) -FILE *ifp; - { - register int i; - register char c; - - for ( ; ; ) - { - i = getc( ifp ); - if ( i == EOF ) - pm_error( "EOF / read error" ); - c = (char) i; - if ( c >= '0' && c <= '9' ) - return c - '0'; - else if ( c >= 'A' && c <= 'F' ) - return c - 'A' + 10; - else if ( c >= 'a' && c <= 'f' ) - return c - 'a' + 10; - /* Else ignore - whitespace. */ - } + if (cols <= 0 || rows <= 0) + pm_error("invalid header"); + maxval = pm_bitstomaxval(depth); + if (maxval > PGM_OVERALLMAXVAL) + pm_error("depth %d is too large. Our maximum is %d", + maxval, PGM_OVERALLMAXVAL); + if (xcols != 0 && xrows != 0 && (xcols != cols || xrows != rows)) + warnNonsquarePixels(cols, xcols, rows, xrows); + + /* Read the hex bits. */ + grays = pgm_allocarray(cols, rows); + for (row = rows - 1; row >= 0; --row) { + unsigned int col; + for (col = 0; col < cols; ++col) { + grays[row][col] = gethexit(ifP) << 4; + grays[row][col] += gethexit(ifP); + } } + pm_close(ifP); + + pgm_writepgm(stdout, grays, cols, rows, maxval, 0); + pm_close(stdout); + + return 0; +} + diff --git a/converter/pgm/pgmtolispm.c b/converter/pgm/pgmtolispm.c index abb85494..7d931fb3 100644 --- a/converter/pgm/pgmtolispm.c +++ b/converter/pgm/pgmtolispm.c @@ -14,129 +14,167 @@ ** usually a color image; but a color map is not written in the file, so we ** treat this as a graymap instead. To convert a color image to Lispm ** format, you must convert it to a pgm, and hand-edit a color map... Ick. +** +** Feb 2010 afu +** Added dimension check to prevent short int from overflowing +** Changed code style (ANSI-style function definitions, etc.) */ -#include +#include "pm.h" #include "pgm.h" #define LISPM_MAGIC "This is a BitMap file" +#define INT16MAX 32767 -static void putinit ARGS(( int cols, int rows, int depth )); -static int depth_to_word_size ARGS(( int depth )); -static void putval ARGS(( gray b )); -static void putrest ARGS(( void )); -static void putitem ARGS(( void )); -int -main( argc, argv ) - int argc; - char* argv[]; - { - FILE* ifp; - gray *grayrow; - register gray* gP; - int rows, cols, depth, format, padright, row, col; - gray maxval; +static unsigned int item; +static unsigned int bitsperitem, maxbitsperitem, bitshift; +static unsigned int +depth_to_word_size(unsigned int const depth) { - pgm_init( &argc, argv ); + /* Lispm architecture specific - if a bitmap is written */ + /* out with a depth of 5, it really has a depth of 8, and */ + /* is stored that way in the file. */ - if ( argc > 2 ) - pm_usage( "[pgmfile]" ); - if ( argc == 2 ) - ifp = pm_openr( argv[1] ); - else - ifp = stdin; + unsigned int const wordSize = + depth == 1 ? 1 : + depth == 2 ? 2 : + depth <= 4 ? 4 : + depth <= 8 ? 8 : + depth <= 16 ? 16 : + depth <= 32 ? 32 : + 0; - pgm_readpgminit( ifp, &cols, &rows, &maxval, &format ); - grayrow = pgm_allocrow( cols ); - depth = pm_maxvaltobits( maxval ); + if (wordSize == 0) + pm_error("depth was %u, which is not in the range 1-32", depth); - /* Compute padding to round cols up to the nearest multiple of 32. */ - padright = ( ( cols + 31 ) / 32 ) * 32 - cols; + return wordSize; +} - putinit( cols, rows, depth ); - for ( row = 0; row < rows; ++row ) - { - pgm_readpgmrow( ifp, grayrow, cols, maxval, format ); - for ( col = 0, gP = grayrow; col < cols; ++col, ++gP ) - putval( *gP ); - for ( col = 0; col < padright; ++col ) - putval( 0 ); - } - pm_close( ifp ); - putrest( ); +static void +putinit(unsigned int const cols, + unsigned int const rows, + unsigned int const depth) { - exit( 0 ); - } + unsigned int const cols32 = ((cols + 31 ) / 32) * 32; -static unsigned int item; -static unsigned int bitsperitem, maxbitsperitem, bitshift; + unsigned int i; -static void -putinit( cols, rows, depth ) - int cols, rows, depth; - { - int i; - int cols32 = ( ( cols + 31 ) / 32 ) * 32; /* Lispms are able to write bit files that are not mod32 wide, but we */ - /* don't. This should be ok, since bit arrays which are not mod32 wide */ - printf(LISPM_MAGIC); /* are pretty useless on a lispm (can't hand them to bitblt). */ - pm_writelittleshort( stdout, cols ); - pm_writelittleshort( stdout, rows ); - pm_writelittleshort( stdout, cols32 ); + /* Lispms are able to write bit files that are not mod32 wide, but we */ + /* don't. This should be ok, since bit arrays which are not mod32 wide */ + /* are pretty useless on a lispm (can't hand them to bitblt). */ + + if (rows > INT16MAX || cols > INT16MAX || cols32 > INT16MAX) + pm_error("Input image is too large."); + + printf(LISPM_MAGIC); + + pm_writelittleshort(stdout, cols); + pm_writelittleshort(stdout, rows); + pm_writelittleshort(stdout, cols32); putchar(depth & 0xFF); - for ( i = 0; i < 9; ++i ) - putchar( 0 ); /* pad bytes */ + for (i = 0; i < 9; ++i) + putchar(0); /* pad bytes */ - item = 0; - bitsperitem = 0; - maxbitsperitem = depth_to_word_size( depth ); - bitshift = 0; - } + item = 0; + bitsperitem = 0; + maxbitsperitem = depth_to_word_size(depth); + bitshift = 0; +} -static int -depth_to_word_size (depth) /* Lispm architecture specific - if a bitmap is written */ - int depth; /* out with a depth of 5, it really has a depth of 8, and */ -{ /* is stored that way in the file. */ - if (depth==0 || depth==1) return ( 1); - else if (depth == 2) return ( 2); - else if (depth <= 4) return ( 4); - else if (depth <= 8) return ( 8); - else if (depth <= 16) return (16); - else if (depth <= 32) return (32); - else { - pm_error( "depth was %d, which is not in the range 1-32", depth ); - return(-1); /* Should never reach here */ - } + + +static void +putitem(void) { + + pm_writelittlelong(stdout, ~item); + + item = 0; + bitsperitem = 0; + bitshift = 0; } static void -putval( gray b ) - { - if ( bitsperitem == 32 ) - putitem( ); - item = item | ( b << bitshift ); +putval(gray const b) { + + if (bitsperitem == 32) + putitem(); + + item = item | (b << bitshift); bitsperitem = bitsperitem + maxbitsperitem; - bitshift = bitshift + maxbitsperitem; - } + bitshift = bitshift + maxbitsperitem; +} + + static void -putrest( ) - { - if ( bitsperitem > 0 ) - putitem( ); +putrest(void) { + + if (bitsperitem > 0) + putitem(); +} + + + +int +main(int argc, const char * argv[]) { + + FILE * ifP; + gray * grayrow; + int rows; + int cols; + unsigned int depth; + int format; + unsigned int padright; + unsigned int row; + gray maxval; + const char * inputFile; + + pm_proginit(&argc, argv); + + if (argc-1 < 1) + inputFile = "-"; + else { + inputFile = argv[1]; + + if (argc-1 > 2) + pm_error("Too many arguments. The only argument is the optional " + "input file name"); } -static void -putitem( ) - { - pm_writelittlelong( stdout, ~item ); - item = 0; - bitsperitem = 0; - bitshift = 0; + ifP = pm_openr(inputFile); + + pgm_readpgminit(ifP, &cols, &rows, &maxval, &format); + + grayrow = pgm_allocrow(cols); + depth = pm_maxvaltobits(maxval); + + /* Compute padding to round cols up to the nearest multiple of 32. */ + padright = ((cols + 31) / 32) * 32 - cols; + + putinit(cols, rows, depth); + + for (row = 0; row < rows; ++row) { + unsigned int col; + + pgm_readpgmrow(ifP, grayrow, cols, maxval, format); + + for (col = 0; col < cols; ++col) + putval(grayrow[col]); + + for (col = 0; col < padright; ++col) + putval(0); } + + pm_close(ifP); + + putrest(); + + return 0; +} diff --git a/converter/pgm/pgmtosbig.c b/converter/pgm/pgmtosbig.c new file mode 100644 index 00000000..0a302dd8 --- /dev/null +++ b/converter/pgm/pgmtosbig.c @@ -0,0 +1,130 @@ +/*============================================================================= + pgmtosbig +=============================================================================== + + This program converts from PGM to a simple subset of SBIG. + + By Bryan Henderson January 19, 2015. + + Contributed to the public domain by its author. +=============================================================================*/ +#include + +#include "pm.h" +#include "nstring.h" +#include "pgm.h" + + + +#define SBIG_HEADER_LENGTH 2048 /* File header length */ + +#define CTLZ "\x1A" + + +struct SbigHeader { +/*---------------------------------------------------------------------------- + The information in an SBIG file header. + + This is only the information this program cares about; the header + may have much more information in it. +-----------------------------------------------------------------------------*/ + unsigned int height; + unsigned int width; + unsigned int saturationLevel; +}; + + + +static void +addUintParm(char * const buffer, + const char * const name, + unsigned int const value) { + + const char * line; + + pm_asprintf(&line, "%s=%u\n\r", name, value); + + strcat(buffer, line); + + pm_strfree(line); +} + + + +static void +writeSbigHeader(FILE * const ofP, + struct SbigHeader const hdr) { + + char buffer[SBIG_HEADER_LENGTH]; + + memset(&buffer[0], 0x00, sizeof(buffer)); + + buffer[0] = '\0'; + + /* N.B. LF-CR instead of CRLF. That's what the spec says. */ + + strcat(buffer, "ST-6 Image\n\r" ); + + addUintParm(buffer, "Height", hdr.height); + + addUintParm(buffer, "Width", hdr.width); + + addUintParm(buffer, "Sat_level", hdr.saturationLevel); + + strcat(buffer, "End\n\r" CTLZ); + + fwrite(buffer, 1, sizeof(buffer), ofP); +} + + + +int +main(int argc, const char * argv[]) { + + FILE * ifP; + gray * grayrow; + int rows; + int cols; + int format; + struct SbigHeader hdr; + unsigned int row; + gray maxval; + const char * inputFile; + + pm_proginit(&argc, argv); + + if (argc-1 < 1) + inputFile = "-"; + else { + inputFile = argv[1]; + + if (argc-1 > 2) + pm_error("Too many arguments. The only argument is the optional " + "input file name"); + } + + ifP = pm_openr(inputFile); + + pgm_readpgminit(ifP, &cols, &rows, &maxval, &format); + + grayrow = pgm_allocrow(cols); + + hdr.height = rows; + hdr.width = cols; + hdr.saturationLevel = maxval; + + writeSbigHeader(stdout, hdr); + + for (row = 0; row < rows; ++row) { + unsigned int col; + + pgm_readpgmrow(ifP, grayrow, cols, maxval, format); + + for (col = 0; col < cols; ++col) + pm_writelittleshort(stdout, grayrow[col]); + } + + pm_close(ifP); + + return 0; +} diff --git a/converter/pgm/pgmtost4.c b/converter/pgm/pgmtost4.c new file mode 100644 index 00000000..fa101ac9 --- /dev/null +++ b/converter/pgm/pgmtost4.c @@ -0,0 +1,104 @@ +/*============================================================================= + pgmtost4 +=============================================================================== + + This program converts from PGM to a simple subset of SBIG ST-4. + + By Bryan Henderson January 19, 2015. + + Contributed to the public domain by its author. +=============================================================================*/ +#include + +#include "pm.h" +#include "nstring.h" +#include "pam.h" + + + +static unsigned int const st4Height = 165; +static unsigned int const st4Width = 192; +static unsigned int const st4Maxval = 255; + + + +static void +writeSt4Footer(FILE * const ofP) { + + const char * const comment = "This was created by Pgmtost4"; + char buffer[192]; + + memset(buffer, ' ', sizeof(buffer)); /* initial value */ + + buffer[0] = 'v'; + + memcpy(&buffer[ 0], "v", 1); + memcpy(&buffer[ 1], comment, strlen(comment)); + memcpy(&buffer[ 79], " 7", 10); + memcpy(&buffer[ 89], " 8", 10); + memcpy(&buffer[ 99], " 9", 10); + memcpy(&buffer[109], " 10", 10); + + fwrite(buffer, 1, sizeof(buffer), ofP); +} + + + +int +main(int argc, const char * argv[]) { + + FILE * ifP; + tuple * tuplerow; + struct pam inpam; + unsigned int row; + const char * inputFile; + + pm_proginit(&argc, argv); + + if (argc-1 < 1) + inputFile = "-"; + else { + inputFile = argv[1]; + + if (argc-1 > 2) + pm_error("Too many arguments. The only argument is the optional " + "input file name"); + } + + ifP = pm_openr(inputFile); + + pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type)); + + if (inpam.height != st4Height) + pm_error("Image is wrong height for ST-4 SBIG: %u pixels. " + "Must be %u", inpam.height, st4Height); + + if (inpam.width != st4Width) + pm_error("Image is wrong width for ST-4 SBIG: %u pixels. " + "Must be %u", inpam.width, st4Width); + + /* Really, we should just scale to maxval 255. There are library routines + for that, but we're too lazy even for that, since nobody is really + going to use this program. + */ + if (inpam.maxval != st4Maxval) + pm_error("Image is wrong maxval for ST-4 SBIG: %u. " + "Must be %u", (unsigned)inpam.maxval, st4Maxval); + + tuplerow = pnm_allocpamrow(&inpam); + + for (row = 0; row < inpam.height; ++row) { + unsigned int col; + + pnm_readpamrow(&inpam, tuplerow); + + for (col = 0; col < inpam.width; ++col) + pm_writechar(stdout, (char)tuplerow[col][0]); + } + + writeSt4Footer(stdout); + + pm_close(ifP); + + return 0; +} diff --git a/converter/pgm/rawtopgm.c b/converter/pgm/rawtopgm.c index 0180a02c..2e5fbb7d 100644 --- a/converter/pgm/rawtopgm.c +++ b/converter/pgm/rawtopgm.c @@ -13,8 +13,9 @@ #include #include "pm_c_util.h" -#include "pgm.h" +#include "mallocvar.h" #include "shhopt.h" +#include "pgm.h" struct cmdline_info { /* All the information the user supplied in the command line, @@ -37,82 +38,93 @@ struct cmdline_info { static void parse_command_line(int argc, char ** argv, - struct cmdline_info *cmdline_p) { + struct cmdline_info *cmdlineP) { /*---------------------------------------------------------------------------- Note that the file spec array we return is stored in the storage that was passed to us as the argv array. -----------------------------------------------------------------------------*/ - optStruct *option_def = malloc(100*sizeof(optStruct)); - /* Instructions to OptParseOptions2 on how to parse our options. + optEntry * option_def; + /* Instructions to OptParseOptions3 on how to parse our options. */ - optStruct2 opt; + optStruct3 opt; unsigned int option_def_index; - option_def_index = 0; /* incremented by OPTENTRY */ - OPTENTRY(0, "bottomfirst", OPT_FLAG, &cmdline_p->bottomfirst, 0); - OPTENTRY(0, "bt", OPT_FLAG, &cmdline_p->bottomfirst, 0); - OPTENTRY(0, "topbottom", OPT_FLAG, &cmdline_p->bottomfirst, 0); - OPTENTRY(0, "tb", OPT_FLAG, &cmdline_p->bottomfirst, 0); - OPTENTRY(0, "headerskip", OPT_UINT, &cmdline_p->headerskip, 0); - OPTENTRY(0, "rowskip", OPT_FLOAT, &cmdline_p->rowskip, 0); - OPTENTRY(0, "bpp", OPT_INT, &cmdline_p->bpp, 0); - OPTENTRY(0, "littleendian", OPT_FLAG, &cmdline_p->littleendian, 0); - OPTENTRY(0, "maxval", OPT_UINT, &cmdline_p->maxval, 0); + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENT3 */ + OPTENT3(0, "bottomfirst", OPT_FLAG, &cmdlineP->bottomfirst, + NULL, 0); + OPTENT3(0, "bt", OPT_FLAG, &cmdlineP->bottomfirst, + NULL, 0); + OPTENT3(0, "topbottom", OPT_FLAG, &cmdlineP->bottomfirst, + NULL, 0); + OPTENT3(0, "tb", OPT_FLAG, &cmdlineP->bottomfirst, + NULL, 0); + OPTENT3(0, "headerskip", OPT_UINT, &cmdlineP->headerskip, + NULL, 0); + OPTENT3(0, "rowskip", OPT_FLOAT, &cmdlineP->rowskip, + NULL, 0); + OPTENT3(0, "bpp", OPT_INT, &cmdlineP->bpp, + NULL, 0); + OPTENT3(0, "littleendian", OPT_FLAG, &cmdlineP->littleendian, + NULL, 0); + OPTENT3(0, "maxval", OPT_UINT, &cmdlineP->maxval, + NULL, 0); /* Set the defaults */ - cmdline_p->bottomfirst = FALSE; - cmdline_p->headerskip = 0; - cmdline_p->rowskip = 0.0; - cmdline_p->bpp = 1; - cmdline_p->littleendian = 0; - cmdline_p->maxval = -1; + cmdlineP->bottomfirst = FALSE; + cmdlineP->headerskip = 0; + cmdlineP->rowskip = 0.0; + cmdlineP->bpp = 1; + cmdlineP->littleendian = 0; + cmdlineP->maxval = -1; opt.opt_table = option_def; opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We may have parms that are negative numbers */ - optParseOptions2(&argc, argv, opt, 0); - /* Uses and sets argc, argv, and some of *cmdline_p and others. */ + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (argc-1 == 0) { - cmdline_p->inputFileName = "-"; - cmdline_p->autosize = TRUE; + cmdlineP->inputFileName = "-"; + cmdlineP->autosize = TRUE; } else if (argc-1 == 1) { - cmdline_p->inputFileName = argv[1]; - cmdline_p->autosize = TRUE; + cmdlineP->inputFileName = argv[1]; + cmdlineP->autosize = TRUE; } else if (argc-1 == 2) { - cmdline_p->inputFileName = "-"; - cmdline_p->autosize = FALSE; - cmdline_p->width = pm_parse_width(argv[1]); - cmdline_p->height = pm_parse_height(argv[2]); + cmdlineP->inputFileName = "-"; + cmdlineP->autosize = FALSE; + cmdlineP->width = pm_parse_width(argv[1]); + cmdlineP->height = pm_parse_height(argv[2]); } else if (argc-1 == 3) { - cmdline_p->inputFileName = argv[3]; - cmdline_p->autosize = FALSE; - cmdline_p->width = pm_parse_width(argv[1]); - cmdline_p->height = pm_parse_height(argv[2]); + cmdlineP->inputFileName = argv[3]; + cmdlineP->autosize = FALSE; + cmdlineP->width = pm_parse_width(argv[1]); + cmdlineP->height = pm_parse_height(argv[2]); } else pm_error("Program takes zero, one, two, or three arguments. You " "specified %d", argc-1); - if (cmdline_p->bpp != 1 && cmdline_p->bpp != 2) + if (cmdlineP->bpp != 1 && cmdlineP->bpp != 2) pm_error("Bytes per pixel (-bpp) must be 1 or 2. You specified %d.", - cmdline_p->bpp); + cmdlineP->bpp); - if (cmdline_p->maxval == 0) + if (cmdlineP->maxval == 0) pm_error("Maxval (-maxval) may not be zero."); - if (cmdline_p->maxval > 255 && cmdline_p->bpp == 1) + if (cmdlineP->maxval > 255 && cmdlineP->bpp == 1) pm_error("You have specified one byte per pixel, but a maxval " - "too large to fit in one byte: %d", cmdline_p->maxval); - if (cmdline_p->maxval > 65535) + "too large to fit in one byte: %d", cmdlineP->maxval); + if (cmdlineP->maxval > 65535) pm_error("Maxval must be less than 65536. You specified %d.", - cmdline_p->maxval); + cmdlineP->maxval); - if (cmdline_p->rowskip && cmdline_p->autosize) + if (cmdlineP->rowskip && cmdlineP->autosize) pm_error("If you specify -rowskip, you must also give the image " "dimensions."); - if (cmdline_p->rowskip && cmdline_p->bottomfirst) + if (cmdlineP->rowskip && cmdlineP->bottomfirst) pm_error("You canot specify both -rowskip and -bottomfirst. This is " "a limitation of this program."); diff --git a/converter/pgm/sbigtopgm.c b/converter/pgm/sbigtopgm.c index dd4e921a..3c223c47 100644 --- a/converter/pgm/sbigtopgm.c +++ b/converter/pgm/sbigtopgm.c @@ -1,210 +1,353 @@ /* - sbigtopgm.c - read a Santa Barbara Instruments Group CCDOPS file - Note: All SBIG CCD astronomical cameras produce 14 bits or - (the ST-4 and ST-5) or 16 bits (ST-6 and later) per pixel. - - Copyright (C) 1998 by John Walker - http://www.fourmilab.ch/ + Note: All SBIG CCD astronomical cameras produce 14 bits + (the ST-4 and ST-5) or 16 bits (ST-6 and later) per pixel. If you find yourself having to add functionality included subsequent to the implementation of this program, you can probably find documentation of any changes to the SBIG file format on their Web site: http://www.sbig.com/ + Copyright (C) 1998 by John Walker + http://www.fourmilab.ch/ + Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission - notice appear in supporting documentation. This software is + notice appear in supporting documentation. This software is provided "as is" without express or implied warranty. - */ #include -#include "pgm.h" +#include "pm_c_util.h" +#include "mallocvar.h" #include "nstring.h" +#include "shhopt.h" +#include "pm.h" +#include "pgm.h" + +struct CmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + const char * inputFileName; +}; + + + +static void +parseCommandLine(int argc, const char ** argv, + struct CmdlineInfo * const cmdlineP) { +/*---------------------------------------------------------------------------- + Note that the file spec array we return is stored in the storage that + was passed to as as the argv array. +-----------------------------------------------------------------------------*/ + optEntry * option_def; + /* Instructions to pm_optParseOptions3 on how to parse our options. + */ + optStruct3 opt; + + unsigned int option_def_index; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENT3 */ + OPTENTINIT; + + opt.opt_table = option_def; + opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ + opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ + + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others */ + + if (argc-1 < 1) + cmdlineP->inputFileName = "-"; + else { + cmdlineP->inputFileName = argv[1]; + + if (argc-1 > 1) + pm_error("Too many arguments. The only possible argument is the " + "optional input file name"); + } +} + + #define SBIG_HEADER_LENGTH 2048 /* File header length */ -/* looseCanon -- Canonicalize a line from the file header so - items more sloppily formatted than those - written by CCDOPS are still accepted. */ -static void looseCanon(cp) - char *cp; -{ - char *op = cp; + +static void +looseCanon(char * const cpArg) { +/*---------------------------------------------------------------------------- + Canonicalize a line from the file header so items more sloppily formatted + than those written by CCDOPS are still accepted. + + Remove all whitespace and make all letters lowercase. + + Note that the SBIG Type 3 format specification at www.sbig.com in January + 2015 says header parameter names are capitalized like 'Height'; we change + that to "height". + + The spec also says the line ends with LF, then CR (yes, really). Assuming + Caller separates lines at LF, that means we see CR at the beginning of all + lines but the first. We remove that. +-----------------------------------------------------------------------------*/ + char * cp; + char * op; char c; - + + cp = cpArg; /* initial value */ + op = cpArg; /* initial value */ + while ((c = *cp++) != 0) { - if (!ISSPACE(c)) { - if (ISUPPER(c)) { - c = tolower(c); - } - *op++ = c; - } + if (!ISSPACE(c)) { + if (ISUPPER(c)) + c = tolower(c); + *op++ = c; + } } - *op++ = 0; + *op++ = '\0'; } -int main(argc, argv) - int argc; - char* argv[]; -{ - FILE *ifp; - gray *grayrow; - register gray *gP; - int argn, row; - register int col; - int maxval; - int comp, rows, cols; - char header[SBIG_HEADER_LENGTH+1]; - char *hdr; - static char camera[80] = "ST-?"; - - pgm_init(&argc, argv); - - argn = 1; - - if (argn < argc) { - ifp = pm_openr(argv[argn]); - argn++; - } else { - ifp = stdin; - } - if (argn != argc) - pm_usage( "[sbigfile]" ); - if (fread(header, SBIG_HEADER_LENGTH, 1, ifp) < 1) { - pm_error("error reading SBIG file header"); - } - header[SBIG_HEADER_LENGTH] = '\0'; +struct SbigHeader { +/*---------------------------------------------------------------------------- + The information in an SBIG file header. + + This is only the information this program cares about; the header + may have much more information in it. +-----------------------------------------------------------------------------*/ + unsigned int rows; + unsigned int cols; + unsigned int maxval; + bool isCompressed; + const char * cameraType; + /* Null means information not in header */ +}; + - /* Walk through the header and parse relevant parameters. */ - comp = -1; - cols = -1; - rows = -1; +static void +readSbigHeader(FILE * const ifP, + struct SbigHeader * const sbigHeaderP) { - /* The SBIG header specification equivalent to maxval is + size_t rc; + bool gotCompression; + bool gotWidth; + bool gotHeight; + char * buffer; /* malloced */ + char * cursor; + bool endOfHeader; + + MALLOCARRAY_NOFAIL(buffer, SBIG_HEADER_LENGTH + 1); + + rc = fread(buffer, SBIG_HEADER_LENGTH, 1, ifP); + + if (rc < 1) + pm_error("error reading SBIG file header"); + + buffer[SBIG_HEADER_LENGTH] = '\0'; + + /* The SBIG header specification equivalent to maxval is "Sat_level", the saturation level of the image. This - specification is optional, and was not included in files - written by early versions of CCDOPS. It was introduced when it - became necessary to distinguish 14-bit images with a Sat_level - of 16383 from 16-bit images which saturate at 65535. In - addition, co-adding images or capturing with Track and - Accumulate can increase the saturation level. Since files + specification is optional, and was not included in files + written by early versions of CCDOPS. It was introduced when it + became necessary to distinguish 14-bit images with a Sat_level + of 16383 from 16-bit images which saturate at 65535. In + addition, co-adding images or capturing with Track and + Accumulate can increase the saturation level. Since files which don't have a Sat_level line in the header were most - probably written by early drivers for the ST-4 or ST-5, it - might seem reasonable to make the default for maxval 16383, - the correct value for those cameras. I chose instead to use - 65535 as the default because the overwhelming majority of + probably written by early drivers for the ST-4 or ST-5, it + might seem reasonable to make the default for maxval 16383, + the correct value for those cameras. I chose instead to use + 65535 as the default because the overwhelming majority of cameras in use today are 16 bit, and it's possible some non-SBIG software may omit the "optional" Sat_level - specification. Also, no harm is done if a larger maxval is - specified than appears in the image--a simple contrast stretch - will adjust pixels to use the full 0 to maxval range. The - converse, pixels having values greater than maxval, results in - an invalid file which may cause problems in programs which - attempt to process it. */ - - maxval = 65535; - - hdr = header; - - for (;;) { - char *cp = strchr(hdr, '\n'); - - if (cp == NULL) { - pm_error("malformed SBIG file header at character %d", hdr - header); - } - *cp = 0; - if (strncmp(hdr, "ST-", 3) == 0 || - (hdr == &header[0] && strstr(hdr,"Image") != NULL)) { - char *ep = strchr(hdr + 3, ' '); - - if (ep != NULL) { - *ep = 0; - STRSCPY(camera, hdr); + specification. Also, no harm is done if a larger maxval is + specified than appears in the image--a simple contrast stretch + will adjust pixels to use the full 0 to maxval range. The + converse, pixels having values greater than maxval, results in + an invalid file which may cause problems in programs which + attempt to process it. + + According to the official specification, the camera type name is the + first item in the header, and may or may not start with "ST-". But + this program has historically had an odd method of detecting camera + type, which allows any string starting with "ST-" anywhere in the + header, and for now we leave that undisturbed. 2015.05.27. + */ + + gotCompression = false; /* initial value */ + gotWidth = false; /* initial value */ + gotHeight = false; /* initial value */ + + sbigHeaderP->maxval = 65535; /* initial assumption */ + sbigHeaderP->cameraType = NULL; /* initial assumption */ + + for (cursor = &buffer[0], endOfHeader = false; !endOfHeader;) { + char * const cp = strchr(cursor, '\n'); + + if (cp == NULL) { + pm_error("malformed SBIG file header at character %u", + (unsigned)(cursor - &buffer[0])); + } + *cp = '\0'; + if (strneq(cursor, "ST-", 3) || + (cursor == &buffer[0] && strstr(cursor,"Image") != NULL)) { + + char * const ep = strchr(cursor + 3, ' '); + + if (ep != NULL) { + *ep = '\0'; + sbigHeaderP->cameraType = pm_strdup(cursor); *ep = ' '; - } - } - looseCanon(hdr); - if (strncmp(hdr, "st-", 3) == 0) { - comp = strstr(hdr, "compressed") != NULL; - } else if (strncmp(hdr, "height=", 7) == 0) { - rows = atoi(hdr + 7); - } else if (strncmp(hdr, "width=", 6) == 0) { - cols = atoi(hdr + 6); - } else if (strncmp(hdr, "sat_level=", 10) == 0) { - maxval = atoi(hdr + 10); - } else if (streq(hdr, "end")) { - break; - } - hdr = cp + 1; + } + } + + looseCanon(cursor); + /* Convert from standard SBIG to an internal format */ + + if (strneq(cursor, "st-", 3) || cursor == &buffer[0]) { + sbigHeaderP->isCompressed = + (strstr(cursor, "compressedimage") != NULL); + gotCompression = true; + } else if (strneq(cursor, "height=", 7)) { + sbigHeaderP->rows = atoi(cursor + 7); + gotHeight = true; + } else if (strneq(cursor, "width=", 6)) { + sbigHeaderP->cols = atoi(cursor + 6); + gotWidth = true; + } else if (strneq(cursor, "sat_level=", 10)) { + sbigHeaderP->maxval = atoi(cursor + 10); + } else if (streq("end", cursor)) { + endOfHeader = true; + } + cursor = cp + 1; } - if ((comp == -1) || (rows == -1) || (cols == -1)) { - pm_error("required specification missing from SBIG file header"); - } + if (!gotCompression) + pm_error("Required 'ST-*' specification missing " + "from SBIG file header"); + if (!gotHeight) + pm_error("required 'height=' specification missing" + "from SBIG file header"); + if (!gotWidth) + pm_error("required 'width=' specification missing " + "from SBIG file header"); +} - fprintf(stderr, "SBIG %s %dx%d %s image, saturation level = %d.\n", - camera, cols, rows, comp ? "compressed" : "uncompressed", maxval); - if (maxval > PGM_OVERALLMAXVAL) { - pm_error("Saturation level (%d levels) is too large.\n" - "This program's limit is %d.", maxval, PGM_OVERALLMAXVAL); + +static void +termSbigHeader(struct SbigHeader const sbigHeader) { + + if (sbigHeader.cameraType) + pm_strfree(sbigHeader.cameraType); +} + + + +static void +writeRaster(FILE * const ifP, + struct SbigHeader const hdr, + FILE * const ofP) { + + gray * grayrow; + unsigned int row; + + grayrow = pgm_allocrow(hdr.cols); + + for (row = 0; row < hdr.rows; ++row) { + bool compthis; + unsigned int col; + + if (hdr.isCompressed) { + unsigned short rowlen; /* Compressed row length */ + + pm_readlittleshortu(ifP, &rowlen); + + /* If compression results in a row length >= the uncompressed + row length, that row is output uncompressed. We detect this + by observing that the compressed row length is equal to + that of an uncompressed row. + */ + + if (rowlen == hdr.cols * 2) + compthis = false; + else + compthis = hdr.isCompressed; + } else + compthis = hdr.isCompressed; + + for (col = 0; col < hdr.cols; ++col) { + unsigned short g; + + if (compthis) { + if (col == 0) { + pm_readlittleshortu(ifP, &g); + } else { + int const delta = getc(ifP); + + if (delta == 0x80) + pm_readlittleshortu(ifP, &g); + else + g += ((signed char) delta); + } + } else + pm_readlittleshortu(ifP, &g); + grayrow[col] = g; + } + pgm_writepgmrow(ofP, grayrow, hdr.cols, hdr.maxval, 0); } - pgm_writepgminit(stdout, cols, rows, (gray) maxval, 0); - grayrow = pgm_allocrow(cols); - -#define DOSINT(fp) ((getc(fp) & 0xFF) | (getc(fp) << 8)) - - for (row = 0; row < rows; row++) { - int compthis = comp; - - if (comp) { - int rowlen = DOSINT(ifp); /* Compressed row length */ - - /* If compression results in a row length >= the uncompressed - row length, that row is output uncompressed. We detect this - by observing that the compressed row length is equal to - that of an uncompressed row. */ - - if (rowlen == cols * 2) { - compthis = 0; - } - } - for (col = 0, gP = grayrow; col < cols; col++, gP++) { - gray g; - - if (compthis) { - - if (col == 0) { - g = DOSINT(ifp); - } else { - int delta = getc(ifp); - - if (delta == 0x80) { - g = DOSINT(ifp); - } else { - g += ((signed char) delta); - } - } - } else { - g = DOSINT(ifp); - } - *gP = g; - } - pgm_writepgmrow(stdout, grayrow, cols, (gray) maxval, 0); + pgm_freerow(grayrow); +} + + + +int +main(int argc, const char ** argv) { + + FILE * ifP; + struct CmdlineInfo cmdline; + struct SbigHeader hdr; + + pm_proginit(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + ifP = pm_openr(cmdline.inputFileName); + + readSbigHeader(ifP, &hdr); + + pm_message("SBIG '%s' %ux%u %s image, saturation level = %u", + (hdr.cameraType ? hdr.cameraType : "ST-?"), + hdr.cols, hdr.rows, + hdr.isCompressed ? "compressed" : "uncompressed", + hdr.maxval); + + if (hdr.maxval > PGM_OVERALLMAXVAL) { + pm_error("Saturation level (%u levels) is too large" + "This program's limit is %u.", hdr.maxval, PGM_OVERALLMAXVAL); } - pm_close(ifp); + + pgm_writepgminit(stdout, hdr.cols, hdr.rows, hdr.maxval, 0); + + writeRaster(ifP, hdr, stdout); + + termSbigHeader(hdr); + + pm_close(ifP); pm_close(stdout); return 0; } + + + diff --git a/converter/pgm/st4topgm.c b/converter/pgm/st4topgm.c new file mode 100644 index 00000000..8e4660a3 --- /dev/null +++ b/converter/pgm/st4topgm.c @@ -0,0 +1,260 @@ +/*============================================================================= + st4topgm +=============================================================================== + + Convert an SBIG ST-4 image (not to be confused with the more sophisticated + SBIG format that every other SBIG camera produces) to PGM. + + By Bryan Henderson January 2015. + + Contributed to the public domain by its author. + + This program was intended to substitute for the program of the same name in + the Debian version of Netpbm, by Justin Pryzby + in December 2003. + +=============================================================================*/ +#include + +#include "pm_config.h" +#include "pm_c_util.h" +#include "pm.h" +#include "pam.h" + + + +static unsigned int const st4Height = 165; +static unsigned int const st4Width = 192; +static unsigned int const st4Maxval = 255; + + + +static void +validateFileSize(FILE * const ifP) { +/*---------------------------------------------------------------------------- + Abort program if *ifP is not the proper size for an ST-4 SBIG file. + + Don't change file position. +-----------------------------------------------------------------------------*/ + pm_filepos const st4FileSize = (st4Height+1) * st4Width; + + pm_filepos oldFilePos; + pm_filepos endFilePos; + + pm_tell2(ifP, &oldFilePos, sizeof(endFilePos)); + + fseek(ifP, 0, SEEK_END); + + pm_tell2(ifP, &endFilePos, sizeof(endFilePos)); + + pm_seek2(ifP, &oldFilePos, sizeof(oldFilePos)); + + if (endFilePos != st4FileSize) + pm_error("File is the wrong size for an ST-4 SBIG file. " + "It is %u bytes; it should be %u bytes", + (unsigned)endFilePos, (unsigned)st4FileSize); +} + + +static void +writeRaster(FILE * const ifP, + struct pam * const pamP) { + + tuple * tuplerow; + unsigned int row; + + tuplerow = pnm_allocpamrow(pamP); + + for (row = 0; row < st4Height; ++row) { + unsigned int col; + + for (col = 0; col < st4Width; ++col) { + char c; + + pm_readchar(ifP, &c); + + tuplerow[col][0] = (unsigned char)c; + } + pnm_writepamrow(pamP, tuplerow); + } + + pnm_freepamrow(tuplerow); +} + + + +struct St4Footer { +/*---------------------------------------------------------------------------- + The information in an ST-4 SBIG footer. +-----------------------------------------------------------------------------*/ + /* Note that numerical information is in decimal text, because we're lazy. + */ + + char comment[78+1]; + char exposureTime[10+1]; + char focalLength[10+1]; + char apertureArea[10+1]; + char calibrationFactor[10+1]; +}; + + + +static void +stripTrailing(char * const arg) { + + if (strlen(arg) > 0) { + char * p; + for (p = arg + strlen(arg); p > arg && *(p-1) == ' '; --p); + + *p = '\0'; + } +} + + + +static void +stripLeading(char * const arg) { + + const char * p; + + for (p = &arg[0]; *p == ' '; ++p); + + if (p > arg) + memmove(arg, p, strlen(p) + 1); +} + + + +static void +readFooter(FILE * const ifP, + struct St4Footer * const footerP) { +/*---------------------------------------------------------------------------- + Read the footer of the ST-4 image from *ifP, assuming *ifP is positioned + to the footer. + + Return its contents as *footerP. +-----------------------------------------------------------------------------*/ + char buffer[192]; + size_t bytesReadCt; + + /* The footer is laid out as follows. + + off len description + --- --- ----------- + 000 1 Signature: 'v' + 001 78 Freeform comment + 079 10 Exposure time in 1/100s of a second + 089 10 Focal length in inches + 099 10 Aperture area in square inches + 109 10 Calibration factor + 119 73 Reserved + + Note tha the footer is the same length as a raster row. + */ + + bytesReadCt = fread(buffer, 1, sizeof(buffer), ifP); + + if (bytesReadCt != 192) + pm_error("Failed to read footer of image"); + + if (buffer[0] != 'v') + pm_error("Input is not an ST-4 file. We know because the " + "signature byte (first byte of the footer) is not 'v'"); + + buffer[191] = '\0'; + memmove(footerP->comment, &buffer[1], 78); + footerP->comment[78] = '\0'; + stripTrailing(footerP->comment); + + memmove(footerP->exposureTime, &buffer[79], 10); + footerP->exposureTime[10] = '\0'; + stripLeading(footerP->exposureTime); + + memmove(footerP->focalLength, &buffer[89], 10); + footerP->focalLength[10] = '\0'; + stripLeading(footerP->focalLength); + + memmove(footerP->apertureArea, &buffer[99], 10); + footerP->apertureArea[10] = '\0'; + stripLeading(footerP->apertureArea); + + memmove(footerP->calibrationFactor, &buffer[109], 10); + footerP->calibrationFactor[10] = '\0'; + stripLeading(footerP->calibrationFactor); +} + + + +static void +reportFooter(struct St4Footer const footer) { + + pm_message("Comment: %s", footer.comment); + + pm_message("Exposure time (1/100 s): %s", footer.exposureTime); + + pm_message("Focal length (in): %s", footer.focalLength); + + pm_message("Aperture area (sq in): %s", footer.apertureArea); + + pm_message("Calibration factor: %s", footer.calibrationFactor); +} + + + +int +main(int argc, const char **argv) { + + FILE * ifP; + const char * inputFileName; + struct pam outpam; + struct St4Footer footer; + + pm_proginit(&argc, argv); + + if (argc-1 < 1) + inputFileName = "-"; + else { + inputFileName = argv[1]; + if (argc-1 > 1) + pm_error("Too many arguments: %u. " + "The only possible argument is the " + "optional input file name", argc-1); + } + + /* We check the file size to catch the common problem of the input not + being valid ST-4 SBIG input. Unlike most formats, this one does not + have any signature at the head of the file. + + More checks on the validity of the format happens when we process + the image footer. + */ + + ifP = pm_openr_seekable(inputFileName); + + validateFileSize(ifP); + + outpam.size = sizeof(outpam); + outpam.len = PAM_STRUCT_SIZE(maxval); + outpam.file = stdout; + outpam.format = PGM_FORMAT; + outpam.plainformat = false; + outpam.height = st4Height; + outpam.width = st4Width; + outpam.depth = 1; + outpam.maxval = st4Maxval; + + pnm_writepaminit(&outpam); + + writeRaster(ifP, &outpam); + + readFooter(ifP, &footer); + + reportFooter(footer); + + pm_close(ifP); + pm_close(stdout); + + return 0; +} + + diff --git a/converter/ppm/411toppm.c b/converter/ppm/411toppm.c index 6ece4c4b..eb2372a5 100644 --- a/converter/ppm/411toppm.c +++ b/converter/ppm/411toppm.c @@ -30,7 +30,7 @@ Bryan Henderson reworked the program to use the Netpbm libraries to create the PPM output and follow some other Netpbm conventions. - 2001-03-03. Bryan's contribution is public domain. + 2001-03-03. Bryan's contribution is public domain. */ /* * Copyright (c) 1995 The Regents of the University of California. @@ -56,22 +56,21 @@ * HEADER FILES * *==============*/ #include -#include #include "pm_c_util.h" -#include "ppm.h" -#include "shhopt.h" #include "mallocvar.h" +#include "shhopt.h" +#include "ppm.h" typedef unsigned char uint8; #define CHOP(x) ((x < 0) ? 0 : ((x > 255) ? 255 : x)) -struct cmdline_info { +struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ - const char *input_filespec; /* Filespec of input file */ + const char * inputFileName; int width; int height; }; @@ -79,38 +78,42 @@ struct cmdline_info { static void -parse_command_line(int argc, char ** argv, - struct cmdline_info *cmdline_p) { +parseCommandLine(int argc, const char ** argv, + struct CmdlineInfo *cmdlineP) { /*---------------------------------------------------------------------------- Note that the file spec array we return is stored in the storage that was passed to us as the argv array. -----------------------------------------------------------------------------*/ - optStruct *option_def = malloc(100*sizeof(optStruct)); + optEntry * option_def; /* Instructions to OptParseOptions2 on how to parse our options. */ - optStruct2 opt; + optStruct3 opt; unsigned int option_def_index; - option_def_index = 0; /* incremented by OPTENTRY */ - OPTENTRY(0, "width", OPT_INT, &cmdline_p->width, 0); - OPTENTRY(0, "height", OPT_INT, &cmdline_p->height, 0); + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENT3 */ + OPTENT3(0, "width", OPT_INT, &cmdlineP->width, NULL, 0); + OPTENT3(0, "height", OPT_INT, &cmdlineP->height, NULL, 0); /* Set the defaults */ - cmdline_p->width = 64; - cmdline_p->height = 48; + cmdlineP->width = 64; + cmdlineP->height = 48; opt.opt_table = option_def; opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions2(&argc, argv, opt, 0); - /* Uses and sets argc, argv, and some of *cmdline_p and others. */ + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ - if (cmdline_p->width <= 0) + if (cmdlineP->width <= 0) pm_error("-width must be positive."); - if (cmdline_p->height <= 0) + if (cmdlineP->width %4 != 0) + pm_error("-width must be a multiple of 4."); + if (cmdlineP->height <= 0) pm_error("-height must be positive."); if (argc > 2) @@ -118,145 +121,111 @@ parse_command_line(int argc, char ** argv, "You supplied %d", argc-1); else { if (argc > 1) - cmdline_p->input_filespec = argv[1]; + cmdlineP->inputFileName = argv[1]; else - cmdline_p->input_filespec = "-"; + cmdlineP->inputFileName = "-"; } + free(option_def); } -static void -ReadYUV(FILE *fpointer, const int width, const int height, - uint8 ** const orig_y, uint8 ** const orig_cb, - uint8 ** const orig_cr) { +static void +ReadYUV(FILE * const ifP, + uint8 * const inbuff) { + + size_t bytesRead; - int y, x, i; + bytesRead = fread(inbuff, 1, 6, ifP); - for (y = 0; y < height; y++) { - for (x = 0, i = 0; x < width; x+=4, i++) { - fread(orig_y[y]+x , 1, 4, fpointer); - fread(orig_cb[y]+i, 1, 1, fpointer); - fread(orig_cr[y]+i, 1, 1, fpointer); - } - } + if (bytesRead != 6 ) { + if (feof(ifP)) + pm_error("Premature end of input."); + else + pm_error("Error reading input."); + } } static void -AllocYCC(const int width, const int height, - uint8 *** const orig_yP, uint8 *** const orig_crP, - uint8 *** const orig_cbP) { - int y; - - MALLOCARRAY_NOFAIL(*orig_yP, height); - for (y = 0; y < height; y++) - MALLOCARRAY_NOFAIL((*orig_yP)[y], width); - - MALLOCARRAY_NOFAIL(*orig_crP, height); - for (y = 0; y < height; y++) - MALLOCARRAY_NOFAIL((*orig_crP)[y], width/4); - - MALLOCARRAY_NOFAIL(*orig_cbP, height); - for (y = 0; y < height; y++) - MALLOCARRAY_NOFAIL((*orig_cbP)[y], width/4); -} +YUVtoPPM(FILE * const ifP, + int const width, + int const height, + pixel * const pixrow ) { + unsigned int col; + for (col = 0; col < width; ++col) { -static void -YUVtoPPM(const int width, const int height, - uint8 ** const orig_y, - uint8 ** const orig_cb, - uint8 ** const orig_cr, - pixel ** const ppm_image - ) { - int **Y, **U, **V; - int y; + uint8 inbuff[6]; - /* first, allocate tons of memory */ + uint8 * const origY = &inbuff[0]; + uint8 * const origCb = &inbuff[4]; + uint8 * const origCr = &inbuff[5]; + int y, u, v; + int32_t tempR, tempG, tempB; + pixval r, g, b; - MALLOCARRAY_NOFAIL(Y, height); - for (y = 0; y < height; y++) - MALLOCARRAY_NOFAIL(Y[y], width); - - MALLOCARRAY_NOFAIL(U, height); - for (y = 0; y < height; y++) - MALLOCARRAY_NOFAIL(U[y], width / 4); - - MALLOCARRAY_NOFAIL(V, height); - for (y = 0; y < height; y++) - MALLOCARRAY_NOFAIL(V[y], width/4); - - for ( y = 0; y < height; y ++ ) { - int x; - for ( x = 0; x < width/4; x ++ ) { - U[y][x] = orig_cb[y][x] - 128; - V[y][x] = orig_cr[y][x] - 128; - } - } - for ( y = 0; y < height; y ++ ) { - int x; - for ( x = 0; x < width; x ++ ) - { - Y[y][x] = orig_y[y][x] - 16; - } - } - for ( y = 0; y < height; y++ ) { - int x; - for ( x = 0; x < width; x++ ) { - pixval r, g, b; - long tempR, tempG, tempB; - /* look at yuvtoppm source for explanation */ - - tempR = 104635*V[y][x/4]; - tempG = -25690*U[y][x/4] + -53294 * V[y][x/4]; - tempB = 132278*U[y][x/4]; - - tempR += (Y[y][x]*76310); - tempG += (Y[y][x]*76310); - tempB += (Y[y][x]*76310); - - r = CHOP((int)(tempR >> 16)); - g = CHOP((int)(tempG >> 16)); - b = CHOP((int)(tempB >> 16)); - - PPM_ASSIGN(ppm_image[y][x], r, g, b); + if (col % 4 == 0) { + ReadYUV(ifP, inbuff); + u = origCb[0] - 128; + v = origCr[0] - 128; } + + y = origY[col % 4] - 16; + + tempR = 104635 * v + y * 76310; + tempG = -25690 * u + -53294 * v + y * 76310; + tempB = 132278 * u + y * 76310; + + r = CHOP((int)(tempR >> 16)); + g = CHOP((int)(tempG >> 16)); + b = CHOP((int)(tempB >> 16)); + + PPM_ASSIGN(pixrow[col], r, g, b); } - /* We really should free the Y, U, and V arrays now */ } int -main(int argc, char **argv) { - FILE *infile; - struct cmdline_info cmdline; - uint8 **orig_y, **orig_cb, **orig_cr; - pixel **ppm_image; +main(int argc, const char **argv) { - ppm_init(&argc, argv); + pixval const maxval = 255; + struct CmdlineInfo cmdline; + FILE * ifP; + pixel * pixrow; + unsigned int row; - parse_command_line(argc, argv, &cmdline); + pm_proginit(&argc, argv); - AllocYCC(cmdline.width, cmdline.height, &orig_y, &orig_cr, &orig_cb); - ppm_image = ppm_allocarray(cmdline.width, cmdline.height); + parseCommandLine(argc, argv, &cmdline); - pm_message("Reading (%dx%d): %s\n", cmdline.width, cmdline.height, - cmdline.input_filespec); - infile = pm_openr(cmdline.input_filespec); - ReadYUV(infile, cmdline.width, cmdline.height, orig_y, orig_cb, orig_cr); - pm_close(infile); + pixrow = ppm_allocrow(cmdline.width); - YUVtoPPM(cmdline.width, cmdline.height, orig_y, orig_cb, orig_cr, - ppm_image); + pm_message("Reading (%ux%u): '%s'", cmdline.width, cmdline.height, + cmdline.inputFileName); - ppm_writeppm(stdout, ppm_image, cmdline.width, cmdline.height, 255, 0); + ifP = pm_openr(cmdline.inputFileName); - ppm_freearray(ppm_image, cmdline.height); + ppm_writeppminit(stdout, cmdline.width, cmdline.height, maxval, 0); + + for (row = 0; row < cmdline.height; ++row) { + YUVtoPPM(ifP, cmdline.width, cmdline.height, pixrow); + ppm_writeppmrow(stdout, pixrow, cmdline.width, maxval, 0); + } + + if (fgetc(ifP) != EOF) + pm_message("Extraneous data at end of image."); + + pm_close(ifP); + ppm_freerow(pixrow); return 0; } +/* + By default a .411 file is width=64, height=48, 4608 bytes. + There is no header. +*/ diff --git a/converter/ppm/Makefile b/converter/ppm/Makefile index adc3a400..003ef8d3 100644 --- a/converter/ppm/Makefile +++ b/converter/ppm/Makefile @@ -12,15 +12,16 @@ SUBDIRS = hpcdtoppm ppmtompeg PORTBINARIES = 411toppm eyuvtoppm gouldtoppm ilbmtoppm imgtoppm \ leaftoppm mtvtoppm neotoppm \ pcxtoppm pc1toppm pi1toppm picttoppm pjtoppm \ - ppmtoacad ppmtoarbtxt \ + ppmtoacad ppmtoapplevol ppmtoarbtxt ppmtoascii \ ppmtobmp ppmtoeyuv ppmtogif ppmtoicr ppmtoilbm \ ppmtoleaf ppmtolj ppmtomitsu ppmtoneo \ ppmtopcx ppmtopi1 ppmtopict ppmtopj \ - ppmtopjxl ppmtoppm ppmtopuzz ppmtorgb3 ppmtosixel ppmtoterm \ + ppmtopjxl ppmtoppm ppmtopuzz ppmtorgb3 \ + ppmtosixel ppmtospu ppmtoterm \ ppmtowinicon ppmtoxpm ppmtoyuv ppmtoyuvsplit \ qrttoppm rawtoppm rgb3toppm spctoppm \ sputoppm tgatoppm winicontoppm ximtoppm xpmtoppm xvminitoppm \ - yuvtoppm yuvsplittoppm + yuvsplittoppm yuvtoppm MATHBINARIES = sldtoppm diff --git a/converter/ppm/eyuvtoppm.c b/converter/ppm/eyuvtoppm.c index 33d57409..910a125b 100644 --- a/converter/ppm/eyuvtoppm.c +++ b/converter/ppm/eyuvtoppm.c @@ -36,9 +36,9 @@ #include #include "pm_c_util.h" -#include "ppm.h" #include "shhopt.h" #include "mallocvar.h" +#include "ppm.h" typedef unsigned char uint8; @@ -46,11 +46,11 @@ typedef unsigned char uint8; -struct cmdline_info { +struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ - const char *input_filespec; /* Filespecs of input file */ + const char * inputFileName; /* Name of input file */ unsigned int width; unsigned int height; }; @@ -59,11 +59,13 @@ struct cmdline_info { static void parseCommandLine(int argc, char ** argv, - struct cmdline_info *cmdlineP) { + struct CmdlineInfo * const cmdlineP) { optStruct3 opt; /* Set by OPTENT3 */ unsigned int option_def_index; - optEntry *option_def = malloc(100*sizeof(optEntry)); + optEntry * option_def; + + MALLOCARRAY_NOFAIL(option_def, 100); option_def_index = 0; /* incremented by OPTENT3 */ OPTENT3('w', "width", OPT_UINT, &cmdlineP->width, NULL, 0); @@ -77,7 +79,7 @@ parseCommandLine(int argc, char ** argv, opt.short_allowed = TRUE; opt.allowNegNum = FALSE; - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); if (cmdlineP->width == 0) pm_error("The width cannot be zero."); @@ -92,32 +94,34 @@ parseCommandLine(int argc, char ** argv, if (argc-1 == 0) - cmdlineP->input_filespec = "-"; + cmdlineP->inputFileName = "-"; else if (argc-1 != 1) pm_error("Program takes zero or one argument (filename). You " - "specified %d", argc-1); + "specified %u", argc-1); else - cmdlineP->input_filespec = argv[1]; + cmdlineP->inputFileName = argv[1]; + free(option_def); } static uint8 ** -AllocUint8Array(unsigned int const cols, unsigned int const rows) { +allocUint8Array(unsigned int const cols, + unsigned int const rows) { - uint8 **retval; - unsigned int y; + uint8 ** retval; + unsigned int row; MALLOCARRAY(retval, rows); if (retval == NULL) - pm_error("Unable to allocate storage for %d x %d byte array.", + pm_error("Unable to allocate storage for %u x %u byte array.", cols, rows); - for (y = 0; y < rows; y++) { - MALLOCARRAY(retval[y], cols); - if (retval[y] == NULL) - pm_error("Unable to allocate storage for %d x %d byte array.", + for (row = 0; row < rows; ++row) { + MALLOCARRAY(retval[row], cols); + if (retval[row] == NULL) + pm_error("Unable to allocate storage for %u x %u byte array.", cols, rows); } return retval; @@ -125,216 +129,191 @@ AllocUint8Array(unsigned int const cols, unsigned int const rows) { -static int ** -AllocIntArray(unsigned int const cols, unsigned int const rows) { +static void +freeUint8Array(uint8 ** const array, + unsigned int const rows) { - int **retval; - unsigned int y; + unsigned int row; - MALLOCARRAY(retval, rows); - if (retval == NULL) - pm_error("Unable to allocate storage for %d x %d byte array.", - cols, rows); + for (row = 0; row < rows; ++row) + free(array[row]); - for (y = 0; y < rows; y++) { - MALLOCARRAY(retval[y], cols); - if (retval[y] == NULL) - pm_error("Unable to allocate storage for %d x %d byte array.", - cols, rows); - } - return retval; + free(array); } static void -allocateStorage(int const cols, int const rows, - int *** const YP, int *** const UP, int *** const VP, - pixel *** const pixelsP, - uint8 *** const orig_yP, uint8 *** const orig_cbP, - uint8 *** const orig_crP) { - - *YP = AllocIntArray(cols, rows); - *UP = AllocIntArray(cols, rows); - *VP = AllocIntArray(cols, rows); - - *pixelsP = ppm_allocarray(cols, rows); - - *orig_yP = AllocUint8Array(cols, rows); - *orig_cbP = AllocUint8Array(cols, rows); - *orig_crP = AllocUint8Array(cols, rows); -} - - - -static void -FreeArray(void ** const array, unsigned int const rows) { - - unsigned int y; - - for (y = 0; y < rows; y++) - free(array[y]); - free(array); +allocateStorage(unsigned int const cols, + unsigned int const rows, + uint8 *** const orig_yP, + uint8 *** const orig_cbP, + uint8 *** const orig_crP) { + + *orig_yP = allocUint8Array(cols, rows); + *orig_cbP = allocUint8Array(cols, rows); + *orig_crP = allocUint8Array(cols, rows); } static void -freeStorage(int const rows, - int ** const Y, int ** const U, int ** const V, - pixel ** const pixels, - uint8 ** const orig_y, uint8 ** const orig_cb, - uint8 ** const orig_cr) { +freeStorage(unsigned int const rows, + uint8 ** const orig_y, + uint8 ** const orig_cb, + uint8 ** const orig_cr) { - FreeArray((void**) orig_y, rows); - FreeArray((void**) orig_cb, rows); - FreeArray((void**) orig_cr, rows); - - ppm_freearray(pixels, rows); + freeUint8Array(orig_y, rows); + freeUint8Array(orig_cb, rows); + freeUint8Array(orig_cr, rows); - FreeArray((void**) Y, rows); - FreeArray((void**) U, rows); - FreeArray((void**) V, rows); } static void -YUVtoPPM(unsigned int const cols, unsigned int const rows, - uint8 ** const orig_y, uint8 ** const orig_cb, uint8 ** const orig_cr, - pixel ** const pixels, - int ** const Y, int ** const U, int ** const V) { +YUVtoPPM(FILE * const ofP, + unsigned int const cols, + unsigned int const rows, + uint8 ** const orig_y, + uint8 ** const orig_cb, + uint8 ** const orig_cr) { /*---------------------------------------------------------------------------- Convert the YUV image in arrays orig_y[][], orig_cb[][], and orig_cr[][] - to a PPM image in the array (already allocated) pixels[][]. - - Use the preallocated areas Y[][], U[][], and V[][] for working space. + to a PPM image and write it to file *ofP. -----------------------------------------------------------------------------*/ + pixel * const pixrow = ppm_allocrow(cols); - int y; + unsigned int row; - for ( y = 0; y < rows/2; y ++ ) { - int x; - for ( x = 0; x < cols/2; x ++ ) { - U[y][x] = orig_cb[y][x] - 128; - V[y][x] = orig_cr[y][x] - 128; - } - } + ppm_writeppminit(ofP, cols, rows, 255, FALSE); - for ( y = 0; y < rows; y ++ ) { - int x; - for ( x = 0; x < cols; x ++ ) - Y[y][x] = orig_y[y][x] - 16; - } + for (row = 0; row < rows; ++row) { + unsigned int col; - for ( y = 0; y < rows; y++ ) { - int x; - for ( x = 0; x < cols; x++ ) { + for (col = 0; col < cols; ++col) { + int const y = orig_y[row][col] - 16; + int const u = orig_cb[row/2][col/2] - 128; + int const v = orig_cr[row/2][col/2] - 128; long tempR, tempG, tempB; - int r, g, b; + int r, g, b; /* look at yuvtoppm source for explanation */ - tempR = 104635*V[y/2][x/2]; - tempG = -25690*U[y/2][x/2] + -53294 * V[y/2][x/2]; - tempB = 132278*U[y/2][x/2]; - - tempR += (Y[y][x]*76310); - tempG += (Y[y][x]*76310); - tempB += (Y[y][x]*76310); + tempR = 104635*v + 76310*y; + tempG = -25690*u + -53294*v + 76310*y; + tempB = 132278*u + 76310*y; r = CHOP((int)(tempR >> 16)); g = CHOP((int)(tempG >> 16)); b = CHOP((int)(tempB >> 16)); - PPM_ASSIGN(pixels[y][x], r, g, b); + PPM_ASSIGN(pixrow[col], r, g, b); } + ppm_writeppmrow(stdout, pixrow, cols, 255, FALSE); } + ppm_freerow(pixrow); } static void -ReadYUV(FILE * const yuvfile, - unsigned int const cols, unsigned int const rows, - uint8 ** const orig_y, - uint8 ** const orig_cb, - uint8 ** const orig_cr, - bool * const eofP) { - - unsigned int y; - int c; - - c = fgetc(yuvfile); - if (c < 0) - *eofP = TRUE; - else { - *eofP = FALSE; - ungetc(c, yuvfile); +ReadYUV(FILE * const ifP, + unsigned int const cols, + unsigned int const rows, + uint8 ** const orig_y, + uint8 ** const orig_cb, + uint8 ** const orig_cr, + bool * const eofP) { + + unsigned int row; + unsigned int totalRead; + bool eof; + + eof = false; /* initial value */ + totalRead = 0; /* initial value */ + + for (row = 0; row < rows && !eof; ++row) { /* Y */ + size_t bytesRead; + + bytesRead = fread(orig_y[row], 1, cols, ifP); + totalRead += bytesRead; + if (bytesRead != cols) + eof = true; } - if (!*eofP) { - for (y = 0; y < rows; y++) /* Y */ - fread(orig_y[y], 1, cols, yuvfile); - for (y = 0; y < rows / 2; y++) /* U */ - fread(orig_cb[y], 1, cols / 2, yuvfile); + for (row = 0; row < rows / 2 && !eof; ++row) { /* U */ + size_t bytesRead; + + bytesRead = fread(orig_cb[row], 1, cols / 2, ifP); + totalRead += bytesRead; + if (bytesRead != cols / 2) + eof = true; + } - for (y = 0; y < rows / 2; y++) /* V */ - fread(orig_cr[y], 1, cols / 2, yuvfile); - if (feof(yuvfile)) - pm_error("Premature end of file reading EYUV input file"); + for (row = 0; row < rows / 2 && !eof; ++row) { /* V */ + size_t bytesRead; + + bytesRead = fread(orig_cr[row], 1, cols / 2, ifP); + totalRead += bytesRead; + if (bytesRead != cols / 2) + eof = true; } + + if (eof) { + if (totalRead == 0) + *eofP = TRUE; + else + pm_error("Premature end of file reading EYUV input file"); + } else + *eofP = FALSE; } int -main(int argc, char **argv) { +main(int argc, const char **argv) { - FILE *ifp; - struct cmdline_info cmdline; + FILE * ifP; + struct CmdlineInfo cmdline; unsigned int frameSeq; /* The following are addresses of malloc'ed storage areas for use by subroutines. */ - int ** Y; - int ** U; - int ** V; - uint8 **orig_y, **orig_cb, **orig_cr; - pixel ** pixels; + uint8 ** orig_y; + uint8 ** orig_cb; + uint8 ** orig_cr; + bool eof; - ppm_init(&argc, argv); + pm_proginit(&argc, argv); - parseCommandLine(argc, argv, &cmdline); + parseCommandLine(argc, (char **)argv, &cmdline); - /* Allocate all the storage once, to save time. */ + /* Allocate all the storage at once, to save time. */ allocateStorage(cmdline.width, cmdline.height, - &Y, &U, &V, &pixels, &orig_y, &orig_cb, &orig_cr); + &orig_y, &orig_cb, &orig_cr); - ifp = pm_openr(cmdline.input_filespec); + ifP = pm_openr(cmdline.inputFileName); - for (frameSeq = 0; !feof(ifp); frameSeq++) { - bool eof; + for (frameSeq = 0, eof = false; !eof; ++frameSeq) { - ReadYUV(ifp, cmdline.width, cmdline.height, + ReadYUV(ifP, cmdline.width, cmdline.height, orig_y, orig_cb, orig_cr, &eof); + if (!eof) { pm_message("Converting Frame %u", frameSeq); - YUVtoPPM(cmdline.width, cmdline.height, orig_y, orig_cb, orig_cr, - pixels, Y, U, V); - ppm_writeppm(stdout, pixels, cmdline.width, cmdline.height, - 255, FALSE); - } + YUVtoPPM(stdout, cmdline.width, cmdline.height, + orig_y, orig_cb, orig_cr); + } else if (frameSeq == 0) + pm_error("Empty EYUV input file"); } - freeStorage(cmdline.height, Y, U, V, pixels, orig_y, orig_cb, orig_cr); - - pm_close(ifp); - exit(0); -} - + freeStorage(cmdline.height, orig_y, orig_cb, orig_cr); + pm_close(ifP); + return 0; +} diff --git a/converter/ppm/hpcdtoppm/pcdovtoppm b/converter/ppm/hpcdtoppm/pcdovtoppm index 1f8b3006..dbf6f53d 100755 --- a/converter/ppm/hpcdtoppm/pcdovtoppm +++ b/converter/ppm/hpcdtoppm/pcdovtoppm @@ -195,7 +195,7 @@ if [ ${#imagefiles[*]} -gt 0 ] ; then rowfiles="$rowfiles $rowfile" fi -if [ ${#rowfiles[*]} == 1 ]; then +if [ ${#rowfiles[*]} = 1 ]; then cat $rowfiles else if [ "$colors" = "n" ] ; then diff --git a/converter/ppm/ilbm.h b/converter/ppm/ilbm.h index 68657956..dbe47758 100644 --- a/converter/ppm/ilbm.h +++ b/converter/ppm/ilbm.h @@ -23,7 +23,7 @@ typedef struct { #define mskNone 0 #define mskHasMask 1 #define mskHasTransparentColor 2 -#define mskLasso 3 /* not supported */ +#define mskLasso 3 /* can't handle this */ #define mskMAXKNOWN mskLasso static const char * mskNAME[] = { "none", "mask plane", "transparent color", "lasso" @@ -127,8 +127,8 @@ typedef struct { #define CLUT_RED 1 #define CLUT_GREEN 2 #define CLUT_BLUE 3 -#define CLUT_HUE 4 /* not supported */ -#define CLUT_SAT 5 /* not supported */ +#define CLUT_HUE 4 /* can't handle this */ +#define CLUT_SAT 5 /* can't handle this */ /* unofficial DCOL chunk for direct-color */ diff --git a/converter/ppm/ilbmtoppm.c b/converter/ppm/ilbmtoppm.c index 5ceb70b6..662be0b5 100644 --- a/converter/ppm/ilbmtoppm.c +++ b/converter/ppm/ilbmtoppm.c @@ -9,7 +9,7 @@ ** documentation. This software is provided "as is" without express or ** implied warranty. ** -** Modified by Mark Thompson on 10/4/90 to accomodate 24-bit IFF files +** Modified by Mark Thompson on 10/4/90 to accommodate 24-bit IFF files ** as used by ASDG, NewTek, etc. ** ** Modified by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de) @@ -89,11 +89,10 @@ static unsigned char *ilbmrow; static pixel *pixelrow; static FILE *maskfile = NULL; static bit *maskrow = NULL; -static short wrotemask = 0; +static bool wrotemask; static IFF_ID typeid; /* ID_ILBM, ID_RGBN, ID_RGB8 */ -static pixel *transpColor = NULL; /* transparent color */ -static char *transpName = NULL; +static char *transpName = NULL; /* -transparent option value */ static bool debug = FALSE; @@ -192,8 +191,8 @@ read_bytes(FILE * const ifP, static unsigned char -get_byte(ifp, iffid, counter) - FILE* ifp; +get_byte(ifP, iffid, counter) + FILE* ifP; IFF_ID iffid; long *counter; { @@ -204,9 +203,9 @@ get_byte(ifp, iffid, counter) pm_error("insufficient data in %s chunk", ID2string(iffid)); --(*counter); } - i = getc(ifp); + i = getc(ifP); if( i == EOF ) - readerr(ifp, iffid); + readerr(ifP, iffid); return (unsigned char) i; } @@ -311,7 +310,7 @@ display_chunk(FILE * const ifP, static void -read_cmap(FILE * const ifp, +read_cmap(FILE * const ifP, IFF_ID const iffid, long const chunksize, ColorMap * const cmap) { @@ -321,7 +320,7 @@ read_cmap(FILE * const ifp, colors = chunksize / 3; if( colors == 0 ) { pm_error("warning - empty %s colormap", ID2string(iffid)); - skip_chunk(ifp, iffid, chunksize); + skip_chunk(ifP, iffid, chunksize); } else { unsigned int i; if( cmap->color ) /* prefer CMAP-chunk over CMYK-chunk */ @@ -331,30 +330,30 @@ read_cmap(FILE * const ifp, for( i = 0; i < colors; ++i ) { int r, g, b; - r = get_byte(ifp, iffid, &chunksize); - g = get_byte(ifp, iffid, &chunksize); - b = get_byte(ifp, iffid, &chunksize); + r = get_byte(ifP, iffid, &chunksize); + g = get_byte(ifP, iffid, &chunksize); + b = get_byte(ifP, iffid, &chunksize); PPM_ASSIGN(cmap->color[i], r, g, b); } - chunk_end(ifp, iffid, chunksize); + chunk_end(ifP, iffid, chunksize); } } static void -read_cmyk(FILE * const ifp, +read_cmyk(FILE * const ifP, IFF_ID const iffid, long const chunksize, ColorMap * const cmap) { if( HAS_COLORMAP(cmap) ) { /* prefer RGB color map */ - skip_chunk(ifp, iffid, chunksize); + skip_chunk(ifP, iffid, chunksize); } else { long const colors = chunksize/4; if( colors == 0 ) { pm_error("warning - empty %s colormap", ID2string(iffid)); - skip_chunk(ifp, iffid, chunksize); + skip_chunk(ifP, iffid, chunksize); } else { unsigned int i; cmap->color = ppm_allocrow(colors); @@ -362,10 +361,10 @@ read_cmyk(FILE * const ifp, for( i = 0; i < colors; ++i ) { int c, m, y, k; - c = get_byte(ifp, iffid, &chunksize); - m = get_byte(ifp, iffid, &chunksize); - y = get_byte(ifp, iffid, &chunksize); - k = get_byte(ifp, iffid, &chunksize); + c = get_byte(ifP, iffid, &chunksize); + m = get_byte(ifP, iffid, &chunksize); + y = get_byte(ifP, iffid, &chunksize); + k = get_byte(ifP, iffid, &chunksize); { pixval const red = @@ -381,7 +380,7 @@ read_cmyk(FILE * const ifp, PPM_ASSIGN(cmap->color[i], red, green, blue); } } - chunk_end(ifp, iffid, chunksize); + chunk_end(ifP, iffid, chunksize); } } } @@ -389,7 +388,7 @@ read_cmyk(FILE * const ifp, static void -read_clut(FILE * const ifp, +read_clut(FILE * const ifP, IFF_ID const iffid, unsigned long const chunksize, ColorMap * const cmap) { @@ -397,19 +396,19 @@ read_clut(FILE * const ifp, if (chunksize != CLUTSize) { pm_message("invalid size for %s chunk - skipping it", ID2string(iffid)); - skip_chunk(ifp, iffid, chunksize); + skip_chunk(ifP, iffid, chunksize); } else { long type; unsigned char * lut; unsigned long remainingChunksize; unsigned int i; - type = get_big_long(ifp, iffid, &remainingChunksize); - get_big_long(ifp, iffid, &remainingChunksize); /* skip reserved fld */ + type = get_big_long(ifP, iffid, &remainingChunksize); + get_big_long(ifP, iffid, &remainingChunksize); /* skip reserved fld */ MALLOCARRAY_NOFAIL(lut, 256); for( i = 0; i < 256; ++i ) - lut[i] = get_byte(ifp, iffid, &remainingChunksize); + lut[i] = get_byte(ifP, iffid, &remainingChunksize); switch( type ) { case CLUT_MONO: @@ -434,6 +433,27 @@ read_clut(FILE * const ifp, +static void +warnNonsquarePixels(uint8_t const xAspect, + uint8_t const yAspect) { + + if (xAspect != yAspect) { + const char * const baseMsg = "warning - non-square pixels"; + + if (pm_have_float_format()) + pm_message("%s; to fix do a 'pamscale -%cscale %g'", + baseMsg, + xAspect > yAspect ? 'x' : 'y', + xAspect > yAspect ? + (float)xAspect/yAspect : + (float)yAspect/xAspect); + else + pm_message("%s", baseMsg); + } +} + + + static BitMapHeader * read_bmhd(FILE * const ifP, IFF_ID const iffid, @@ -441,7 +461,7 @@ read_bmhd(FILE * const ifP, BitMapHeader * bmhdP; - if( chunksize != BitMapHeaderSize ) { + if (chunksize != BitMapHeaderSize) { pm_message("invalid size for %s chunk - skipping it", ID2string(iffid)); skip_chunk(ifP, iffid, chunksize); @@ -468,24 +488,24 @@ read_bmhd(FILE * const ifP, bmhdP->pageWidth = get_big_short(ifP, iffid, &remainingChunksize); bmhdP->pageHeight = get_big_short(ifP, iffid, &remainingChunksize); - if( verbose ) { - if( typeid == ID_ILBM ) + if (verbose) { + if (typeid == ID_ILBM) pm_message("dimensions: %dx%d, %d planes", bmhdP->w, bmhdP->h, bmhdP->nPlanes); else pm_message("dimensions: %dx%d", bmhdP->w, bmhdP->h); - if( typeid == ID_ILBM || typeid == ID_PBM ) { + if (typeid == ID_ILBM || typeid == ID_PBM) { pm_message("compression: %s", bmhdP->compression <= cmpMAXKNOWN ? cmpNAME[bmhdP->compression] : "unknown"); - switch( bmhdP->masking ) { + switch(bmhdP->masking) { case mskNone: break; case mskHasMask: case mskHasTransparentColor: - if( !maskfile ) + if (!maskfile) pm_message("use '-maskfile ' " "to generate a PBM mask file from %s", mskNAME[bmhdP->masking]); @@ -499,27 +519,20 @@ read_bmhd(FILE * const ifP, } } else /* RGBN/RGB8 */ - if( !maskfile ) + if (!maskfile) pm_message("use '-maskfile ' " "to generate a PBM mask file " "from genlock bits"); } /* fix aspect ratio */ - if( bmhdP->xAspect == 0 || bmhdP->yAspect == 0 ) { + if (bmhdP->xAspect == 0 || bmhdP->yAspect == 0) { pm_message("warning - illegal aspect ratio %d:%d, using 1:1", bmhdP->xAspect, bmhdP->yAspect); bmhdP->xAspect = bmhdP->yAspect = 1; } - if( bmhdP->xAspect != bmhdP->yAspect ) { - pm_message("warning - non-square pixels; " - "to fix do a 'pnmscale -%cscale %g'", - bmhdP->xAspect > bmhdP->yAspect ? 'x' : 'y', - bmhdP->xAspect > bmhdP->yAspect ? - (float)(bmhdP->xAspect)/bmhdP->yAspect : - (float)(bmhdP->yAspect)/bmhdP->xAspect); - } + warnNonsquarePixels(bmhdP->xAspect, bmhdP->yAspect); } return bmhdP; } @@ -628,42 +641,42 @@ decode_mask(FILE * const ifP, unsigned char *ilp; cols = bmhdP->w; - switch( bmhdP->masking ) { + switch (bmhdP->masking) { case mskNone: break; case mskHasMask: /* mask plane */ read_ilbm_plane(ifP, remainingChunksizeP, RowBytes(cols), bmhdP->compression); - if( maskfile ) { + if (maskfile) { ilp = ilbmrow; cbit = 7; - for( col = 0; col < cols; col++, cbit-- ) { - if( cbit < 0 ) { + for (col = 0; col < cols; ++col, --cbit) { + if (cbit < 0) { cbit = 7; - ilp++; + ++ilp; } - if( *ilp & bit_mask[cbit] ) + if (*ilp & bit_mask[cbit]) maskrow[col] = PBM_BLACK; else maskrow[col] = PBM_WHITE; } pbm_writepbmrow(maskfile, maskrow, cols, 0); - wrotemask = 1; + wrotemask = true; } break; case mskHasTransparentColor: - if( !chunkyrow ) + if (!chunkyrow) pm_error("decode_mask(): chunkyrow == NULL - can't happen"); - if( maskfile ) { - for( col = 0; col < cols; col++ ) { - if( chunkyrow[col] == bmhdP->transparentColor ) + if (maskfile) { + for (col = 0; col < cols; ++col) { + if (chunkyrow[col] == bmhdP->transparentColor) maskrow[col] = PBM_WHITE; else maskrow[col] = PBM_BLACK; } pbm_writepbmrow(maskfile, maskrow, cols, 0); - wrotemask = 1; + wrotemask = true; } break; case mskLasso: @@ -758,83 +771,66 @@ multi_free(cmap) } + /**************************************************************************** Colormap handling ****************************************************************************/ + + static void -prepareCmap(const BitMapHeader * const bmhd, - ColorMap * const cmap) { -/*---------------------------------------------------------------------------- - This is a really ugly subroutine that 1) analyzes a colormap and its - context (returning the analysis in global variables); and 2) modifies that - color map, because it's really one type of data structure as input and - another as output. +analyzeCmapSamples(const ColorMap * const cmapP, + pixval * const maxSampleP, + bool * const shiftedP) { ------------------------------------------------------------------------------*/ - pixval colmaxval = 0; - int shifted = 1; - int i, r, g, b; - - if( bmhd ) { - if( bmhd->masking == mskHasTransparentColor || - bmhd->masking == mskLasso ) { - unsigned short const transpIdx = bmhd->transparentColor; - if( !transpName ) { - MALLOCVAR_NOFAIL(transpColor); - if (HAS_COLORMAP(cmap)) { - if( transpIdx >= cmap->ncolors ) { - pm_message("using default transparent color (black)"); - PPM_ASSIGN(*transpColor, 0, 0, 0); - } else - *transpColor = cmap->color[transpIdx]; - } else { - /* The color index is just a direct gray level */ - PPM_ASSIGN(*transpColor, transpIdx, transpIdx, transpIdx); - } - } - } + pixval maxSample; + bool shifted; + unsigned int i; + + for (i = 0, maxSample = 0, shifted = true; i < cmapP->ncolors; ++i) { + pixval const r = PPM_GETR(cmapP->color[i]); + pixval const g = PPM_GETG(cmapP->color[i]); + pixval const b = PPM_GETB(cmapP->color[i]); - if( bmhd->flags & BMHD_FLAGS_CMAPOK ) - return; + maxSample = MAX(maxSample, MAX(r, MAX(g, b))); + + if (r & 0x0f || g & 0x0f || b & 0x0f) + shifted = false; } + *shiftedP = shifted; + *maxSampleP = maxSample; +} - if( !HAS_COLORMAP(cmap) ) - return; - for( i = 0; i < cmap->ncolors; i++ ) { - r = PPM_GETR(cmap->color[i]); - if( r > colmaxval ) colmaxval = r; - if( r & 0x0f ) shifted = 0; - g = PPM_GETG(cmap->color[i]); - if( g > colmaxval ) colmaxval = g; - if( g & 0x0f ) shifted = 0; +static void +transformCmap(ColorMap * const cmapP) { - b = PPM_GETB(cmap->color[i]); - if( b > colmaxval ) colmaxval = b; - if( b & 0x0f ) shifted = 0; - } + pixval maxSample; + /* The maximum sample value in *cmapP input */ + bool shifted; + /* Samples in the *cmapP input appear to be 4 bit (maxval 15) original + values shifted left 4 places to make 8 bit (maxval 255) samples. + */ -#ifdef DEBUG - pm_message("colormap maxval is %d", colmaxval); -#endif - if( colmaxval == 0 ) + analyzeCmapSamples(cmapP, &maxSample, &shifted); + + if (maxSample == 0) pm_message("warning - black colormap"); - else - if( shifted || colmaxval <= 15 ) { - if( !adjustcolors ) { + else if (shifted || maxSample <= 15) { + if (!adjustcolors) { pm_message("warning - probably %s4-bit colormap", - shifted ? "shifted " : ""); - pm_message(" use '-adjustcolors' to scale colormap to 8 bits"); - } - else { + shifted ? "shifted " : ""); + pm_message("Use '-adjustcolors' to scale colormap to 8 bits"); + } else { + unsigned int i; pm_message("scaling colormap to 8 bits"); - for( i = 0; i < cmap->ncolors; i++ ) { - r = PPM_GETR(cmap->color[i]); - g = PPM_GETG(cmap->color[i]); - b = PPM_GETB(cmap->color[i]); - if( shifted ) { + for (i = 0; i < cmapP->ncolors; ++i) { + pixval r, g, b; + r = PPM_GETR(cmapP->color[i]); + g = PPM_GETG(cmapP->color[i]); + b = PPM_GETB(cmapP->color[i]); + if (shifted) { r >>= 4; g >>= 4; b >>= 4; @@ -842,13 +838,74 @@ prepareCmap(const BitMapHeader * const bmhd, r *= FACTOR_4BIT; g *= FACTOR_4BIT; b *= FACTOR_4BIT; - PPM_ASSIGN(cmap->color[i], r, g, b); + PPM_ASSIGN(cmapP->color[i], r, g, b); } } } } + +static pixel * +transpColor(const BitMapHeader * const bmhdP, + ColorMap * const cmapP, + const char * const transpName, + pixval const maxval) { + + pixel * transpColorP; + + if (bmhdP) { + if (bmhdP->masking == mskHasTransparentColor || + bmhdP->masking == mskLasso) { + MALLOCVAR_NOFAIL(transpColorP); + + if (transpName) + *transpColorP = ppm_parsecolor(transpName, maxval); + else { + unsigned short const transpIdx = bmhdP->transparentColor; + if (HAS_COLORMAP(cmapP)) { + if (transpIdx >= cmapP->ncolors) { + pm_message("using default transparent color (black)"); + PPM_ASSIGN(*transpColorP, 0, 0, 0); + } else + *transpColorP = cmapP->color[transpIdx]; + } else { + /* The color index is just a direct gray level */ + PPM_ASSIGN(*transpColorP, transpIdx, transpIdx, transpIdx); + } + } + } else + transpColorP = NULL; + } else + transpColorP = NULL; + + return transpColorP; +} + + + +static void +prepareCmap(const BitMapHeader * const bmhdP, + ColorMap * const cmapP) { +/*---------------------------------------------------------------------------- + This is a really ugly subroutine that 1) analyzes a colormap and its + context (returning the analysis in global variables); and 2) modifies that + color map, because it's really one type of data structure as input and + another as output. +-----------------------------------------------------------------------------*/ + bool bmhdCmapOk; + + if (bmhdP) + bmhdCmapOk = (bmhdP->flags & BMHD_FLAGS_CMAPOK); + else + bmhdCmapOk = false; + + if (HAS_COLORMAP(cmapP) && !bmhdCmapOk) + transformCmap(cmapP); +} + + + static pixval lookup_red(cmap, oldval) ColorMap *cmap; @@ -988,18 +1045,18 @@ get_color(cmap, idx, red, green, blue) ****************************************************************************/ static void -std_to_ppm(FILE * const ifp, +std_to_ppm(FILE * const ifP, long const chunksize, - BitMapHeader * const bmhd, + BitMapHeader * const bmhdP, ColorMap * const cmap, long const viewportmodes); static void -ham_to_ppm(FILE * const ifp, +ham_to_ppm(FILE * const ifP, long const chunksize, - BitMapHeader * const bmhd, + BitMapHeader * const bmhdP, ColorMap * const cmap, long const viewportmodes) { @@ -1008,9 +1065,9 @@ ham_to_ppm(FILE * const ifp, rawtype *rawrow; unsigned char hamlut[256]; - cols = bmhd->w; - rows = bmhd->h; - hambits = bmhd->nPlanes - 2; + cols = bmhdP->w; + rows = bmhdP->h; + hambits = bmhdP->nPlanes - 2; hammask = (1 << hambits) - 1; hamshift = 8 - hambits; hammask2 = (1 << hamshift) - 1; @@ -1019,15 +1076,16 @@ ham_to_ppm(FILE * const ifp, int const assumed_viewportmodes = viewportmodes & ~(vmHAM); pm_message("%d-plane HAM?? - interpreting image as a normal ILBM", - bmhd->nPlanes); - std_to_ppm(ifp, chunksize, bmhd, cmap, assumed_viewportmodes); + bmhdP->nPlanes); + std_to_ppm(ifP, chunksize, bmhdP, cmap, assumed_viewportmodes); return; } else { unsigned long remainingChunksize; + pixel * transpColorP; pm_message("input is a %sHAM%d file", HAS_MULTIPALETTE(cmap) ? "multipalette " : "", - bmhd->nPlanes); + bmhdP->nPlanes); if( HAS_COLORLUT(cmap) || HAS_MONOLUT(cmap) ) { pm_message("warning - color lookup tables ignored in HAM"); @@ -1046,10 +1104,7 @@ ham_to_ppm(FILE * const ifp, cmap->monolut = hamlut; } - if( transpName ) { - MALLOCVAR_NOFAIL(transpColor); - *transpColor = ppm_parsecolor(transpName, MAXCOLVAL); - } + transpColorP = transpColor(bmhdP, cmap, transpName, MAXCOLVAL); if( HAS_MULTIPALETTE(cmap) ) multi_init(cmap, viewportmodes); @@ -1066,15 +1121,15 @@ ham_to_ppm(FILE * const ifp, if( HAS_MULTIPALETTE(cmap) ) multi_update(cmap, row); - decode_row(ifp, &remainingChunksize, rawrow, bmhd->nPlanes, bmhd); - decode_mask(ifp, &remainingChunksize, rawrow, bmhd); + decode_row(ifP, &remainingChunksize, rawrow, bmhdP->nPlanes, bmhdP); + decode_mask(ifP, &remainingChunksize, rawrow, bmhdP); r = g = b = 0; for( col = 0; col < cols; col++ ) { int idx = rawrow[col] & hammask; - if( transpColor && maskrow && maskrow[col] == PBM_WHITE ) - pixelrow[col] = *transpColor; + if( transpColorP && maskrow && maskrow[col] == PBM_WHITE ) + pixelrow[col] = *transpColorP; else { switch((rawrow[col] >> hambits) & 0x03) { case HAMCODE_CMAP: @@ -1101,7 +1156,7 @@ ham_to_ppm(FILE * const ifp, } ppm_writeppmrow(stdout, pixelrow, cols, MAXCOLVAL, 0); } - chunk_end(ifp, ID_BODY, remainingChunksize); + chunk_end(ifP, ID_BODY, remainingChunksize); } } @@ -1110,27 +1165,28 @@ ham_to_ppm(FILE * const ifp, static void std_to_ppm(FILE * const ifP, long const chunksize, - BitMapHeader * const bmhd, + BitMapHeader * const bmhdP, ColorMap * const cmap, long const viewportmodes) { if (viewportmodes & vmHAM) { - ham_to_ppm(ifP, chunksize, bmhd, cmap, viewportmodes); + ham_to_ppm(ifP, chunksize, bmhdP, cmap, viewportmodes); } else { - unsigned int const cols = bmhd->w; - unsigned int const rows = bmhd->h; + unsigned int const cols = bmhdP->w; + unsigned int const rows = bmhdP->h; rawtype *rawrow; unsigned int row, col; pixval maxval; unsigned long remainingChunksize; + pixel * transpColorP; - pm_message("input is a %d-plane %s%sILBM", bmhd->nPlanes, + pm_message("input is a %d-plane %s%sILBM", bmhdP->nPlanes, HAS_MULTIPALETTE(cmap) ? "multipalette " : "", viewportmodes & vmEXTRA_HALFBRITE ? "EHB " : "" ); - if( bmhd->nPlanes > MAXPLANES ) + if( bmhdP->nPlanes > MAXPLANES ) pm_error("too many planes (max %d)", MAXPLANES); if( HAS_COLORMAP(cmap) ) { @@ -1140,15 +1196,12 @@ std_to_ppm(FILE * const ifP, } else { pm_message("no colormap - interpreting values as grayscale"); - maxval = lut_maxval(cmap, pm_bitstomaxval(bmhd->nPlanes)); + maxval = lut_maxval(cmap, pm_bitstomaxval(bmhdP->nPlanes)); if( maxval > PPM_OVERALLMAXVAL ) pm_error("nPlanes is too large"); } - if( transpName ) { - MALLOCVAR_NOFAIL(transpColor); - *transpColor = ppm_parsecolor(transpName, maxval); - } + transpColorP = transpColor(bmhdP, cmap, transpName, maxval); rawrow = alloc_rawrow(cols); @@ -1164,13 +1217,13 @@ std_to_ppm(FILE * const ifP, if( HAS_MULTIPALETTE(cmap) ) multi_update(cmap, row); - decode_row(ifP, &remainingChunksize, rawrow, bmhd->nPlanes, bmhd); - decode_mask(ifP, &remainingChunksize, rawrow, bmhd); + decode_row(ifP, &remainingChunksize, rawrow, bmhdP->nPlanes, bmhdP); + decode_mask(ifP, &remainingChunksize, rawrow, bmhdP); for( col = 0; col < cols; col++ ) { pixval r, g, b; - if( transpColor && maskrow && maskrow[col] == PBM_WHITE ) - pixelrow[col] = *transpColor; + if( transpColorP && maskrow && maskrow[col] == PBM_WHITE ) + pixelrow[col] = *transpColorP; else { get_color(cmap, rawrow[col], &r, &g, &b); PPM_ASSIGN(pixelrow[col], r, g, b); @@ -1198,6 +1251,7 @@ deep_to_ppm(FILE * const ifP, rawtype *Rrow, *Grow, *Brow; pixval maxval; unsigned long remainingChunksize; + pixel * transpColorP; pm_message("input is a deep (%d-bit) ILBM", bmhdP->nPlanes); if( planespercolor > MAXPLANES ) @@ -1214,11 +1268,8 @@ deep_to_ppm(FILE * const ifP, if( maxval > PPM_OVERALLMAXVAL ) pm_error("nPlanes is too large"); - if( transpName ) { - MALLOCVAR_NOFAIL(transpColor); - *transpColor = ppm_parsecolor(transpName, maxval); - } - + transpColorP = transpColor(bmhdP, cmap, transpName, maxval); + Rrow = alloc_rawrow(cols); Grow = alloc_rawrow(cols); Brow = alloc_rawrow(cols); @@ -1234,8 +1285,8 @@ deep_to_ppm(FILE * const ifP, decode_mask(ifP, &remainingChunksize, NULL, bmhdP); for( col = 0; col < cols; col++ ) { - if( transpColor && maskrow && maskrow[col] == PBM_WHITE ) - pixelrow[col] = *transpColor; + if( transpColorP && maskrow && maskrow[col] == PBM_WHITE ) + pixelrow[col] = *transpColorP; else PPM_ASSIGN(pixelrow[col], lookup_red(cmap, Rrow[col]), lookup_green(cmap, Grow[col]), @@ -1266,6 +1317,7 @@ dcol_to_ppm(FILE * const ifP, pixval maxval, redmaxval, greenmaxval, bluemaxval; pixval *redtable, *greentable, *bluetable; unsigned long remainingChunksize; + pixel * transpColorP; pm_message("input is a %d:%d:%d direct color ILBM", redplanes, greenplanes, blueplanes); @@ -1316,10 +1368,7 @@ dcol_to_ppm(FILE * const ifP, for (i = 0; i <= bluemaxval; ++i) bluetable[i] = ROUNDDIV(i * maxval, bluemaxval); } - if( transpName ) { - MALLOCVAR_NOFAIL(transpColor); - *transpColor = ppm_parsecolor(transpName, maxval); - } + transpColorP = transpColor(bmhdP, cmap, transpName, maxval); Rrow = alloc_rawrow(cols); Grow = alloc_rawrow(cols); @@ -1336,8 +1385,8 @@ dcol_to_ppm(FILE * const ifP, decode_mask(ifP, &remainingChunksize, NULL, bmhdP); for( col = 0; col < cols; col++ ) { - if( transpColor && maskrow && maskrow[col] == PBM_WHITE ) - pixelrow[col] = *transpColor; + if( transpColorP && maskrow && maskrow[col] == PBM_WHITE ) + pixelrow[col] = *transpColorP; else PPM_ASSIGN( pixelrow[col], redtable[Rrow[col]], greentable[Grow[col]], @@ -1372,6 +1421,7 @@ ipbm_to_ppm(FILE * const ifP, int col, row; pixval maxval; unsigned long remainingChunksize; + pixel * transpColorP; pm_message("input is a %sPBM ", HAS_MULTIPALETTE(cmap) ? "multipalette " : ""); @@ -1390,10 +1440,7 @@ ipbm_to_ppm(FILE * const ifP, maxval = lut_maxval(cmap, pm_bitstomaxval(bmhdP->nPlanes)); } - if( transpName ) { - MALLOCVAR_NOFAIL(transpColor); - *transpColor = ppm_parsecolor(transpName, maxval); - } + transpColorP = transpColor(bmhdP, cmap, transpName, maxval); if( HAS_MULTIPALETTE(cmap) ) multi_init(cmap, viewportmodes); @@ -1412,8 +1459,8 @@ ipbm_to_ppm(FILE * const ifP, for( col = 0; col < cols; col++ ) { pixval r, g, b; - if( transpColor && maskrow && maskrow[col] == PBM_WHITE ) - pixelrow[col] = *transpColor; + if( transpColorP && maskrow && maskrow[col] == PBM_WHITE ) + pixelrow[col] = *transpColorP; else { get_color(cmap, ilbmrow[col], &r, &g, &b); PPM_ASSIGN(pixelrow[col], r, g, b); @@ -1436,48 +1483,54 @@ rgbn_to_ppm(FILE * const ifP, unsigned int const rows = bmhdP->h; unsigned int const cols = bmhdP->w; - int row, col, count, genlock, tries; - pixval r, g, b, maxval; + unsigned int row; + unsigned int count; + pixval maxval; unsigned long remainingChunksize; + pixel * transpColorP; pm_message("input is a %d-bit RGB image", (typeid == ID_RGB8 ? 8 : 4)); - if( bmhdP->compression != 4 ) + if (bmhdP->compression != 4) pm_error("invalid compression mode for %s: %d (must be 4)", ID2string(typeid), bmhdP->compression); - - switch( typeid ) { - case ID_RGBN: - if( bmhdP->nPlanes != 13 ) - pm_error("invalid number of planes for %s: %d (must be 13)", - ID2string(typeid), bmhdP->nPlanes); - maxval = lut_maxval(cmap, 15); - break; - case ID_RGB8: - if( bmhdP->nPlanes != 25 ) - pm_error("invalid number of planes for %s: %d (must be 25)", - ID2string(typeid), bmhdP->nPlanes); - maxval = 255; - break; - default: - pm_error("rgbn_to_ppm(): invalid IFF ID %s - can't happen", - ID2string(typeid)); + + switch (typeid) { + case ID_RGBN: + if (bmhdP->nPlanes != 13) + pm_error("invalid number of planes for %s: %d (must be 13)", + ID2string(typeid), bmhdP->nPlanes); + maxval = lut_maxval(cmap, 15); + break; + case ID_RGB8: + if (bmhdP->nPlanes != 25) + pm_error("invalid number of planes for %s: %d (must be 25)", + ID2string(typeid), bmhdP->nPlanes); + maxval = 255; + break; + default: + pm_error("rgbn_to_ppm(): invalid IFF ID %s - can't happen", + ID2string(typeid)); } - if( transpName ) { - MALLOCVAR_NOFAIL(transpColor); - *transpColor = ppm_parsecolor(transpName, maxval); - } + transpColorP = transpColor(bmhdP, cmap, transpName, maxval); ppm_writeppminit(stdout, cols, rows, maxval, 0); - remainingChunksize = chunksize; /* initial value */ - count = 0; - for( row = 0; row < rows; row++ ) { - for( col = 0; col < cols; col++ ) { + for (row = 0, count = 0, remainingChunksize = chunksize; + row < rows; + ++row) { + + unsigned int col; + + for (col = 0; col < cols; ++col) { + unsigned int tries; + unsigned int genlock; + pixval r, g, b; + tries = 0; - while( !count ) { - if( typeid == ID_RGB8 ) { + while (count == 0) { + if (typeid == ID_RGB8) { r = lookup_red(cmap, get_byte(ifP, ID_BODY, &remainingChunksize)); g = lookup_green(cmap, get_byte(ifP, ID_BODY, @@ -1487,47 +1540,46 @@ rgbn_to_ppm(FILE * const ifP, count = get_byte(ifP, ID_BODY, &remainingChunksize); genlock = count & 0x80; count &= 0x7f; - } - else { - int word; - word = get_big_short(ifP, ID_BODY, &remainingChunksize); + } else { + unsigned int const word = + get_big_short(ifP, ID_BODY, &remainingChunksize); r = lookup_red(cmap, (word & 0xf000) >> 12); g = lookup_green(cmap, (word & 0x0f00) >> 8); b = lookup_blue(cmap, (word & 0x00f0) >> 4); genlock = word & 0x0008; count = word & 0x0007; } - if( !count ) { + if (!count) { count = get_byte(ifP, ID_BODY, &remainingChunksize); - if( !count ) + if (count == 0) count = get_big_short(ifP, ID_BODY, &remainingChunksize); - if( !count ) - ++tries; + if (count == 0) + ++tries; } } - if( tries ) { - pm_message("warning - repeat count 0 at col %d row %d: " - "skipped %d RGB entr%s", + if (tries > 0) { + pm_message("warning - repeat count 0 at col %u row %u: " + "skipped %u RGB entr%s", col, row, tries, (tries == 1 ? "y" : "ies")); } - if( maskfile ) { + if (maskfile) { /* genlock bit set -> transparent */ - if( genlock ) + if (genlock) maskrow[col] = PBM_WHITE; else maskrow[col] = PBM_BLACK; } - if( transpColor && maskrow && maskrow[col] == PBM_WHITE ) - pixelrow[col] = *transpColor; + if (transpColorP && maskrow && maskrow[col] == PBM_WHITE) + pixelrow[col] = *transpColorP; else PPM_ASSIGN(pixelrow[col], r, g, b); --count; } ppm_writeppmrow(stdout, pixelrow, cols, maxval, 0); - if( maskfile ) { + if (maskfile) { pbm_writepbmrow(maskfile, maskrow, cols, 0); - wrotemask = 1; + wrotemask = true; } } chunk_end(ifP, ID_BODY, remainingChunksize); @@ -1916,13 +1968,13 @@ PCHG_ConvertBig(PCHGHeader * const PCHG, static void -read_pchg(FILE * const ifp, +read_pchg(FILE * const ifP, IFF_ID const iffid, long const chunksize, ColorMap * const cmap) { if( cmap->mp_type >= MP_TYPE_PCHG ) { - skip_chunk(ifp, iffid, chunksize); + skip_chunk(ifP, iffid, chunksize); } else { PCHGHeader PCHG; unsigned char *data; @@ -1936,15 +1988,15 @@ read_pchg(FILE * const ifp, remainingChunksize = chunksize; /* initial value */ - PCHG.Compression = get_big_short(ifp, iffid, &remainingChunksize); - PCHG.Flags = get_big_short(ifp, iffid, &remainingChunksize); - PCHG.StartLine = get_big_short(ifp, iffid, &remainingChunksize); - PCHG.LineCount = get_big_short(ifp, iffid, &remainingChunksize); - PCHG.ChangedLines= get_big_short(ifp, iffid, &remainingChunksize); - PCHG.MinReg = get_big_short(ifp, iffid, &remainingChunksize); - PCHG.MaxReg = get_big_short(ifp, iffid, &remainingChunksize); - PCHG.MaxChanges = get_big_short(ifp, iffid, &remainingChunksize); - PCHG.TotalChanges= get_big_long(ifp, iffid, &remainingChunksize); + PCHG.Compression = get_big_short(ifP, iffid, &remainingChunksize); + PCHG.Flags = get_big_short(ifP, iffid, &remainingChunksize); + PCHG.StartLine = get_big_short(ifP, iffid, &remainingChunksize); + PCHG.LineCount = get_big_short(ifP, iffid, &remainingChunksize); + PCHG.ChangedLines= get_big_short(ifP, iffid, &remainingChunksize); + PCHG.MinReg = get_big_short(ifP, iffid, &remainingChunksize); + PCHG.MaxReg = get_big_short(ifP, iffid, &remainingChunksize); + PCHG.MaxChanges = get_big_short(ifP, iffid, &remainingChunksize); + PCHG.TotalChanges= get_big_long(ifP, iffid, &remainingChunksize); #ifdef DEBUG pm_message("PCHG StartLine : %d", PCHG.StartLine); @@ -1959,17 +2011,17 @@ read_pchg(FILE * const ifp, long treesize, compsize; CompHdr.CompInfoSize = - get_big_long(ifp, iffid, &remainingChunksize); + get_big_long(ifP, iffid, &remainingChunksize); CompHdr.OriginalDataSize = - get_big_long(ifp, iffid, &remainingChunksize); + get_big_long(ifP, iffid, &remainingChunksize); treesize = CompHdr.CompInfoSize; MALLOCARRAY_NOFAIL(comptree, treesize); - read_bytes(ifp, treesize, comptree, iffid, &remainingChunksize); + read_bytes(ifP, treesize, comptree, iffid, &remainingChunksize); compsize = remainingChunksize; MALLOCARRAY_NOFAIL(compdata, compsize); - read_bytes(ifp, compsize, compdata, iffid, &remainingChunksize); + read_bytes(ifP, compsize, compdata, iffid, &remainingChunksize); datasize = CompHdr.OriginalDataSize; MALLOCARRAY_NOFAIL(data, datasize); @@ -1984,7 +2036,7 @@ read_pchg(FILE * const ifp, #endif datasize = remainingChunksize; MALLOCARRAY_NOFAIL(data, datasize); - read_bytes(ifp, datasize, data, iffid, &remainingChunksize); + read_bytes(ifP, datasize, data, iffid, &remainingChunksize); } if( PCHG.Flags & PCHGF_USE_ALPHA ) @@ -2023,7 +2075,7 @@ read_pchg(FILE * const ifp, ID2string(iffid)); } free(data); - chunk_end(ifp, iffid, remainingChunksize); + chunk_end(ifP, iffid, remainingChunksize); } } @@ -2048,7 +2100,7 @@ ignored_iffid(IFF_ID const iffid, static void -process_body( FILE * const ifp, +process_body( FILE * const ifP, long const chunksize, BitMapHeader * const bmhdP, ColorMap * const cmap, @@ -2058,19 +2110,19 @@ process_body( FILE * const ifp, DirectColor * const dcol, int * const viewportmodesP) { - if( bmhdP == NULL ) + if (bmhdP == NULL) pm_error("%s chunk without %s chunk", ID2string(ID_BODY), ID2string(ID_BMHD)); prepareCmap(bmhdP, cmap); pixelrow = ppm_allocrow(bmhdP->w); - if( maskfile ) { + if (maskfile) { maskrow = pbm_allocrow(bmhdP->w); pbm_writepbminit(maskfile, bmhdP->w, bmhdP->h, 0); } - if( typeid == ID_ILBM ) { + if (typeid == ID_ILBM) { int isdeep; MALLOCARRAY_NOFAIL(ilbmrow, RowBytes(bmhdP->w)); @@ -2084,27 +2136,27 @@ process_body( FILE * const ifp, } else isdeep = isdeepopt; - if( isdeep > 0 ) - deep_to_ppm(ifp, chunksize, bmhdP, cmap); - else if( dcol ) - dcol_to_ppm(ifp, chunksize, bmhdP, cmap, dcol); - else if( bmhdP->nPlanes > 8 ) { - if( bmhdP->nPlanes <= 16 && HAS_COLORMAP(cmap) ) - std_to_ppm(ifp, chunksize, bmhdP, cmap, *viewportmodesP); - else if( isdeep >= 0 && (bmhdP->nPlanes % 3 == 0) ) - deep_to_ppm(ifp, chunksize, bmhdP, cmap); - else if( bmhdP->nPlanes <= 16 ) + if (isdeep > 0) + deep_to_ppm(ifP, chunksize, bmhdP, cmap); + else if (dcol) + dcol_to_ppm(ifP, chunksize, bmhdP, cmap, dcol); + else if (bmhdP->nPlanes > 8) { + if (bmhdP->nPlanes <= 16 && HAS_COLORMAP(cmap)) + std_to_ppm(ifP, chunksize, bmhdP, cmap, *viewportmodesP); + else if (isdeep >= 0 && (bmhdP->nPlanes % 3 == 0)) + deep_to_ppm(ifP, chunksize, bmhdP, cmap); + else if (bmhdP->nPlanes <= 16) /* will be interpreted as grayscale */ - std_to_ppm(ifp, chunksize, bmhdP, cmap, *viewportmodesP); + std_to_ppm(ifP, chunksize, bmhdP, cmap, *viewportmodesP); else pm_error("don't know how to interpret %d-plane image", bmhdP->nPlanes); } else - std_to_ppm(ifp, chunksize, bmhdP, cmap, *viewportmodesP); + std_to_ppm(ifP, chunksize, bmhdP, cmap, *viewportmodesP); } else if( typeid == ID_PBM ) - ipbm_to_ppm(ifp, chunksize, bmhdP, cmap, *viewportmodesP); + ipbm_to_ppm(ifP, chunksize, bmhdP, cmap, *viewportmodesP); else /* RGBN or RGB8 */ - rgbn_to_ppm(ifp, chunksize, bmhdP, cmap); + rgbn_to_ppm(ifP, chunksize, bmhdP, cmap); } @@ -2376,6 +2428,8 @@ main(int argc, char *argv[]) { if( argn != argc ) pm_usage(usage); + wrotemask = false; /* initial value */ + /* Read in the ILBM file. */ firstIffid = get_big_long(ifP, ID_FORM, NULL); diff --git a/converter/ppm/pc1toppm.c b/converter/ppm/pc1toppm.c index 5ba247e9..ec6678a4 100644 --- a/converter/ppm/pc1toppm.c +++ b/converter/ppm/pc1toppm.c @@ -170,7 +170,7 @@ writePpm(FILE * const ofP, is represented by 4 shorts (16 bit integers). The first is for Plane 0, the second for Plane 1, etc. Each short contains the bits for that plane for each of the 16 columns, - arranged from most signficant bit to least in increasing column + arranged from most significant bit to least in increasing column number. */ unsigned int col0ScreenIndex = cols/16*planes * row; diff --git a/converter/ppm/pcxtoppm.c b/converter/ppm/pcxtoppm.c index 25a81531..e252ba22 100644 --- a/converter/ppm/pcxtoppm.c +++ b/converter/ppm/pcxtoppm.c @@ -84,7 +84,7 @@ parseCommandLine ( int argc, char ** argv, was passed to us as the argv array. We also trash *argv. -----------------------------------------------------------------------------*/ optEntry *option_def = malloc( 100*sizeof( optEntry ) ); - /* Instructions to optParseOptions3 on how to parse our options. + /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; @@ -100,7 +100,7 @@ parseCommandLine ( int argc, char ** argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3( &argc, argv, opt, sizeof(opt), 0 ); + pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0 ); /* Uses and sets argc, argv, and some of *cmdline_p and others. */ if (argc-1 < 1) @@ -129,9 +129,9 @@ struct pcxHeader { short Planes; short BitsPerPixel; short BytesPerLine; - /* Number of decompressed bytes each plane of each row of the image - takes. Due to padding (this is always an even number), there may - be garbage on the right end that isn't part of the image. + /* Number of decompressed bytes each plane of each row of the image + takes. Because of padding (this is always an even number), there + may be garbage on the right end that isn't part of the image. */ short PaletteInfo; short HorizontalResolution; @@ -532,14 +532,14 @@ pcx_256col_to_ppm(FILE * const ifP, } else cols = headerCols; - image = (unsigned char **)pm_allocarray(BytesPerLine, rows, - sizeof(unsigned char)); + MALLOCARRAY2(image, rows, BytesPerLine); + for (row = 0; row < rows; ++row) GetPCXRow(ifP, image[row], BytesPerLine); /* * 256 color images have their color map at the end of the file - * preceeded by a magic byte + * preceded by a magic byte */ colormapSignature = GetByte(ifP); if (colormapSignature != PCX_256_COLORS) diff --git a/converter/ppm/picttoppm.c b/converter/ppm/picttoppm.c index 9a7d8e7c..828d5270 100644 --- a/converter/ppm/picttoppm.c +++ b/converter/ppm/picttoppm.c @@ -40,10 +40,10 @@ /* * Typical byte, 2 byte and 4 byte integers. */ -typedef unsigned char byte; -typedef char signed_byte; -typedef unsigned short word; -typedef unsigned long longword; +typedef unsigned char Byte; +typedef char SignedByte; +typedef unsigned short Word; +typedef unsigned long Longword; /* @@ -51,47 +51,47 @@ typedef unsigned long longword; */ struct Rect { - word top; - word left; - word bottom; - word right; + Word top; + Word left; + Word bottom; + Word right; }; struct pixMap { struct Rect Bounds; - word version; - word packType; - longword packSize; - longword hRes; - longword vRes; - word pixelType; - word pixelSize; - word cmpCount; - word cmpSize; - longword planeBytes; - longword pmTable; - longword pmReserved; + Word version; + Word packType; + Longword packSize; + Longword hRes; + Longword vRes; + Word pixelType; + Word pixelSize; + Word cmpCount; + Word cmpSize; + Longword planeBytes; + Longword pmTable; + Longword pmReserved; }; struct RGBColor { - word red; - word grn; - word blu; + Word red; + Word grn; + Word blu; }; struct Point { - word x; - word y; + Word x; + Word y; }; struct Pattern { - byte pix[64]; + Byte pix[64]; }; struct rgbPlanes { - word * red; - word * grn; - word * blu; + Word * red; + Word * grn; + Word * blu; }; struct canvas { @@ -102,8 +102,8 @@ typedef void (*transfer_func) (struct RGBColor* src, struct RGBColor* dst); static const char * stage; static struct Rect picFrame; -static word rowlen; -static word collen; +static Word rowlen; +static Word collen; static int verbose; static int fullres; static int recognize_comment; @@ -121,23 +121,23 @@ static struct Rect clip_rect; static struct Rect cur_rect; static struct Point current; static struct Pattern pen_pat; -static word pen_width; -static word pen_height; -static word pen_mode; +static Word pen_width; +static Word pen_height; +static Word pen_mode; static transfer_func pen_trf; -static word text_font; -static byte text_face; -static word text_mode; +static Word text_font; +static Byte text_face; +static Word text_mode; static transfer_func text_trf; -static word text_size; +static Word text_size; static struct font* tfont; /* state for magic printer comments */ static int ps_text; -static byte ps_just; -static byte ps_flip; -static word ps_rotation; -static byte ps_linespace; +static Byte ps_just; +static Byte ps_flip; +static Word ps_rotation; +static Byte ps_linespace; static int ps_cent_x; static int ps_cent_y; static int ps_cent_set; @@ -277,6 +277,10 @@ typedef void (drawFn)(struct canvas *, blitList *, int); struct opdef { const char* name; int len; + /* If non-negative, this is the length of the argument of the + instruction. If negative, it has special meaning; WORD_LEN + is the only value negative value. + */ drawFn * impl; const char* description; }; @@ -291,11 +295,11 @@ struct opdef { */ /* for reserved opcodes of known length */ -#define res(length) \ +#define RESERVED_OP(length) \ { "reserved", (length), NULL, "reserved for Apple use" } /* for reserved opcodes of length determined by a function */ -#define resf(skipfunction) \ +#define RESERVED_OP_F(skipfunction) \ { "reserved", NA, (skipfunction), "reserved for Apple use" } /* seems like RGB colors are 6 bytes, but Apple says they're variable */ @@ -308,8 +312,8 @@ static int align = 0; -static byte -read_byte(void) { +static Byte +readByte(void) { int c; if ((c = fgetc(ifp)) == EOF) @@ -321,52 +325,52 @@ read_byte(void) { -static word -read_word(void) { - byte b; +static Word +readWord(void) { - b = read_byte(); + Byte const hi = readByte(); + Byte const lo = readByte(); - return (b << 8) | read_byte(); + return (hi << 8) | (lo << 0); } -static void read_point(struct Point * const p) { - p->y = read_word(); - p->x = read_word(); +static void readPoint(struct Point * const p) { + p->y = readWord(); + p->x = readWord(); } -static longword -read_long(void) { - word i; +static Longword +readLong(void) { + Word const hi = readWord(); + Word const lo = readWord(); - i = read_word(); - return (i << 16) | read_word(); + return (hi << 16) | (lo << 0); } -static signed_byte -read_signed_byte(void) { - return (signed_byte)read_byte(); +static SignedByte +readSignedByte(void) { + return (SignedByte)readByte(); } static void -read_short_point(struct Point * const p) { - p->x = read_signed_byte(); - p->y = read_signed_byte(); +readShortPoint(struct Point * const p) { + p->x = readSignedByte(); + p->y = readSignedByte(); } static void skip(int const byteCount) { - static byte buf[1024]; + static Byte buf[1024]; int n; align += byteCount; @@ -461,7 +465,7 @@ const_name(const struct const_name * const table, static void -picComment(word const type, +picComment(Word const type, int const length) { unsigned int remainingLength; @@ -470,10 +474,10 @@ picComment(word const type, case 150: if (verbose) pm_message("TextBegin"); if (length >= 6) { - ps_just = read_byte(); - ps_flip = read_byte(); - ps_rotation = read_word(); - ps_linespace = read_byte(); + ps_just = readByte(); + ps_flip = readByte(); + ps_rotation = readWord(); + ps_linespace = readByte(); remainingLength = length - 5; if (recognize_comment) ps_text = 1; @@ -506,11 +510,11 @@ picComment(word const type, if (length < 8) remainingLength = length; else { - ps_cent_y = read_word(); + ps_cent_y = readWord(); if (ps_cent_y > 32767) ps_cent_y -= 65536; skip(2); /* ignore fractional part */ - ps_cent_x = read_word(); + ps_cent_x = readWord(); if (ps_cent_x > 32767) ps_cent_x -= 65536; skip(2); /* ignore fractional part */ @@ -621,7 +625,7 @@ ShortComment(struct canvas * const canvasP, blitList * const blitListP, int const version) { - picComment(read_word(), 0); + picComment(readWord(), 0); } @@ -633,10 +637,10 @@ LongComment(struct canvas * const canvasP, blitList * const blitListP, int const version) { - word type; + Word type; - type = read_word(); - picComment(type, read_word()); + type = readWord(); + picComment(type, readWord()); } @@ -649,7 +653,7 @@ skip_poly_or_region(struct canvas * const canvasP, int const version) { stage = "skipping polygon or region"; - skip(read_word() - 2); + skip(readWord() - 2); } @@ -788,12 +792,12 @@ dumpRect(const char * const label, static void -read_rect(struct Rect * const r) { +readRect(struct Rect * const r) { - r->top = read_word(); - r->left = read_word(); - r->bottom = read_word(); - r->right = read_word(); + r->top = readWord(); + r->left = readWord(); + r->bottom = readWord(); + r->right = readWord(); if (r->top > r->bottom || r->right < r->left) dumpRect("Invalid rectangle", *r); @@ -1196,7 +1200,7 @@ doDiffSize(struct Rect const clipsrc, unsigned int const dstadd = dstwid - xsize; - FILE * pnmscalePipeP; + FILE * pamscalePipeP; const char * command; FILE * scaled; int cols, rows, format; @@ -1205,9 +1209,9 @@ doDiffSize(struct Rect const clipsrc, pixel * rowp; FILE * tempFileP; const char * tempFilename; - word * reddst; - word * grndst; - word * bludst; + Word * reddst; + Word * grndst; + Word * bludst; reddst = dst.red; /* initial value */ grndst = dst.grn; /* initial value */ @@ -1217,19 +1221,19 @@ doDiffSize(struct Rect const clipsrc, pm_close(tempFileP); - asprintfN(&command, "pnmscale -xsize %d -ysize %d > %s", - rectwidth(&clipdst), rectheight(&clipdst), tempFilename); + pm_asprintf(&command, "pamscale -xsize %d -ysize %d > %s", + rectwidth(&clipdst), rectheight(&clipdst), tempFilename); pm_message("running command '%s'", command); - pnmscalePipeP = popen(command, "w"); - if (pnmscalePipeP == NULL) + pamscalePipeP = popen(command, "w"); + if (pamscalePipeP == NULL) pm_error("cannot execute command '%s' popen() errno = %s (%d)", command, strerror(errno), errno); - strfree(command); + pm_strfree(command); - fprintf(pnmscalePipeP, "P6\n%d %d\n%d\n", + fprintf(pamscalePipeP, "P6\n%d %d\n%d\n", rectwidth(&clipsrc), rectheight(&clipsrc), PPM_MAXMAXVAL); switch (pixSize) { @@ -1241,9 +1245,9 @@ doDiffSize(struct Rect const clipsrc, for (colNumber = 0; colNumber < xsize; ++colNumber) { unsigned int const colorIndex = row[colNumber]; struct RGBColor * const ct = &color_map[colorIndex]; - fputc(redepth(ct->red, 65535L), pnmscalePipeP); - fputc(redepth(ct->grn, 65535L), pnmscalePipeP); - fputc(redepth(ct->blu, 65535L), pnmscalePipeP); + fputc(redepth(ct->red, 65535L), pamscalePipeP); + fputc(redepth(ct->grn, 65535L), pamscalePipeP); + fputc(redepth(ct->blu, 65535L), pamscalePipeP); } } } @@ -1255,9 +1259,9 @@ doDiffSize(struct Rect const clipsrc, unsigned int colNumber; for (colNumber = 0; colNumber < xsize; ++colNumber) { struct RGBColor const color = decode16(&row[colNumber * 2]); - fputc(redepth(color.red, 32), pnmscalePipeP); - fputc(redepth(color.grn, 32), pnmscalePipeP); - fputc(redepth(color.blu, 32), pnmscalePipeP); + fputc(redepth(color.red, 32), pamscalePipeP); + fputc(redepth(color.grn, 32), pamscalePipeP); + fputc(redepth(color.blu, 32), pamscalePipeP); } } } @@ -1274,17 +1278,17 @@ doDiffSize(struct Rect const clipsrc, unsigned int colNumber; for (colNumber = 0; colNumber < xsize; ++colNumber) { - fputc(redepth(redPlane[colNumber], 256), pnmscalePipeP); - fputc(redepth(grnPlane[colNumber], 256), pnmscalePipeP); - fputc(redepth(bluPlane[colNumber], 256), pnmscalePipeP); + fputc(redepth(redPlane[colNumber], 256), pamscalePipeP); + fputc(redepth(grnPlane[colNumber], 256), pamscalePipeP); + fputc(redepth(bluPlane[colNumber], 256), pamscalePipeP); } } } break; } - if (pclose(pnmscalePipeP)) - pm_error("pnmscale failed. pclose() returned Errno %s (%d)", + if (pclose(pamscalePipeP)) + pm_error("pamscale failed. pclose() returned Errno %s (%d)", strerror(errno), errno); ppm_readppminit(scaled = pm_openr(tempFilename), &cols, &rows, @@ -1331,7 +1335,7 @@ doDiffSize(struct Rect const clipsrc, pm_close(scaled); ppm_freerow(row); - strfree(tempFilename); + pm_strfree(tempFilename); unlink(tempFilename); } @@ -1707,9 +1711,9 @@ allocPlanes(unsigned int const width, pm_error("not enough memory to hold picture"); /* initialize background to white */ - memset(planes.red, 255, planelen * sizeof(word)); - memset(planes.grn, 255, planelen * sizeof(word)); - memset(planes.blu, 255, planelen * sizeof(word)); + memset(planes.red, 255, planelen * sizeof(Word)); + memset(planes.grn, 255, planelen * sizeof(Word)); + memset(planes.blu, 255, planelen * sizeof(Word)); *planesP = planes; } @@ -1727,7 +1731,7 @@ freePlanes(struct rgbPlanes const planes) { static unsigned char -compact(word const input) { +compact(Word const input) { return (input >> 8) & 0xff; } @@ -1913,41 +1917,49 @@ outputPpm(FILE * const ofP, * All data in version 2 is 2-byte word aligned. Odd size data * is padded with a null. */ -static word +static Word get_op(int const version) { if ((align & 1) && version == 2) { stage = "aligning for opcode"; - read_byte(); + readByte(); } stage = "reading opcode"; if (version == 1) - return read_byte(); + return readByte(); else - return read_word(); + return readWord(); } -static drawFn Clip; +static drawFn ClipRgn; static void -Clip(struct canvas * const canvasP, - blitList * const blitListP, - int const version) { +ClipRgn(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { + + Word const len = readWord(); + /* Length in bytes of the parameter (including this word) */ - word len; + if (len == 10) { /* null rgn */ + /* Parameter is 2 bytes of length, 8 bytes of rectangle corners */ - len = read_word(); + /* In March 2011, I saw a supposed PICT file (reported to work with + Apple pictureViewer) with what looked like signed numbers for the + rectangle: (-32767,-32767), (32767, 32767). This code has always + assumed all words in a PICT are unsigned. But even when I changed + it to accept this clip rectangle, this program found the image to + have an invalid raster. + */ - if (len == 0x000a) { /* null rgn */ - read_rect(&clip_rect); + readRect(&clip_rect); /* XXX should clip this by picFrame */ if (verbose) dumpRect("clipping to", clip_rect); - } - else + } else skip(len - 2); } @@ -1960,31 +1972,31 @@ OpColor(struct canvas * const canvasP, blitList * const blitListP, int const version) { - op_color.red = read_word(); - op_color.grn = read_word(); - op_color.blu = read_word(); + op_color.red = readWord(); + op_color.grn = readWord(); + op_color.blu = readWord(); } static void -read_pixmap(struct pixMap * const p) { +readPixmap(struct pixMap * const p) { stage = "getting pixMap header"; - read_rect(&p->Bounds); - p->version = read_word(); - p->packType = read_word(); - p->packSize = read_long(); - p->hRes = read_long(); - p->vRes = read_long(); - p->pixelType = read_word(); - p->pixelSize = read_word(); - p->cmpCount = read_word(); - p->cmpSize = read_word(); - p->planeBytes = read_long(); - p->pmTable = read_long(); - p->pmReserved = read_long(); + readRect(&p->Bounds); + p->version = readWord(); + p->packType = readWord(); + p->packSize = readLong(); + p->hRes = readLong(); + p->vRes = readLong(); + p->pixelType = readWord(); + p->pixelSize = readWord(); + p->cmpCount = readWord(); + p->cmpSize = readWord(); + p->planeBytes = readLong(); + p->pmTable = readLong(); + p->pmReserved = readLong(); if (verbose) { pm_message("pixelType: %d", p->pixelType); @@ -2007,19 +2019,19 @@ read_pixmap(struct pixMap * const p) { static struct RGBColor* -read_color_table(void) { - longword ctSeed; - word ctFlags; - word ctSize; - word val; +readColorTable(void) { + Longword ctSeed; + Word ctFlags; + Word ctSize; + Word val; int i; struct RGBColor* color_table; stage = "getting color table info"; - ctSeed = read_long(); - ctFlags = read_word(); - ctSize = read_word(); + ctSeed = readLong(); + ctFlags = readWord(); + ctSize = readWord(); if (verbose) { pm_message("ctSeed: %ld", ctSeed); @@ -2034,7 +2046,7 @@ read_color_table(void) { pm_error("no memory for color table"); for (i = 0; i <= ctSize; i++) { - val = read_word(); + val = readWord(); /* The indices in a device color table are bogus and usually == 0. * so I assume we allocate up the list of colors in order. */ @@ -2042,9 +2054,9 @@ read_color_table(void) { val = i; if (val > ctSize) pm_error("pixel value greater than color table size"); - color_table[val].red = read_word(); - color_table[val].grn = read_word(); - color_table[val].blu = read_word(); + color_table[val].red = readWord(); + color_table[val].grn = readWord(); + color_table[val].blu = readWord(); if (verbose > 1) pm_message("Color %3u: [%u,%u,%u]", val, @@ -2531,7 +2543,7 @@ interpretCompressedLine(unsigned char * const linebuf, So with 200 being the cutoff, it's actually impossible to represent some 16 bpp images with 200 pixels per row. - We have not been able to find an offical spec for PICT. + We have not been able to find an official spec for PICT. Some day, we may have to make a user option for this. */ @@ -2573,9 +2585,9 @@ unpackCompressedBits(FILE * const ifP, unsigned int linelen; if (llsize == 2) - linelen = read_word(); + linelen = readWord(); else - linelen = read_byte(); + linelen = readByte(); reportValidateCompressedLineLen(row, linelen, raster.rowSize); @@ -2598,7 +2610,7 @@ unpackCompressedBits(FILE * const ifP, static void unpackbits(FILE * const ifP, struct Rect * const boundsP, - word const rowBytesArg, + Word const rowBytesArg, int const bitsPerPixel, struct raster * const rasterP) { @@ -2633,7 +2645,7 @@ unpackbits(FILE * const ifP, static void -interpretRowBytesWord(word const rowBytesWord, +interpretRowBytesWord(Word const rowBytesWord, bool * const pixMapP, unsigned int * const rowBytesP) { @@ -2651,13 +2663,13 @@ interpretRowBytesWord(word const rowBytesWord, * a pattern in the fabled complete version. */ static void -read_pattern(void) { +readPattern(void) { - word PatType; + Word PatType; stage = "Reading a pattern"; - PatType = read_word(); + PatType = readWord(); switch (PatType) { case 2: @@ -2665,7 +2677,7 @@ read_pattern(void) { skip(5); /* RGB for pattern */ break; case 1: { - word rowBytesWord; + Word rowBytesWord; bool pixMap; unsigned int rowBytes; struct pixMap p; @@ -2673,16 +2685,16 @@ read_pattern(void) { struct RGBColor * ct; skip(8); /* old pattern data */ - rowBytesWord = read_word(); + rowBytesWord = readWord(); interpretRowBytesWord(rowBytesWord, &pixMap, &rowBytes); - read_pixmap(&p); - ct = read_color_table(); + readPixmap(&p); + ct = readColorTable(); unpackbits(ifp, &p.Bounds, rowBytes, p.pixelSize, &raster); freeRaster(raster); free(ct); } break; default: - pm_error("unknown pattern type in read_pattern"); + pm_error("unknown pattern type in readPattern"); } } @@ -2697,7 +2709,7 @@ BkPixPat(struct canvas * const canvasP, blitList * const blitListP, int const version) { - read_pattern(); + readPattern(); } @@ -2709,7 +2721,7 @@ PnPixPat(struct canvas * const canvasP, blitList * const blitListP, int const version) { - read_pattern(); + readPattern(); } @@ -2721,13 +2733,13 @@ FillPixPat(struct canvas * const canvasP, blitList * const blitListP, int const version) { - read_pattern(); + readPattern(); } static void -read_8x8_pattern(struct Pattern * const pat) { +read8x8Pattern(struct Pattern * const pat) { unsigned char buf[8]; unsigned char * exp; unsigned int len; @@ -2756,7 +2768,7 @@ BkPat(struct canvas * const canvasP, blitList * const blitListP, int const version) { - read_8x8_pattern(&bkpat); + read8x8Pattern(&bkpat); } @@ -2768,7 +2780,7 @@ PnPat(struct canvas * const canvasP, blitList * const blitListP, int const version) { - read_8x8_pattern(&pen_pat); + read8x8Pattern(&pen_pat); } @@ -2780,7 +2792,7 @@ FillPat(struct canvas * const canvasP, blitList * const blitListP, int const version) { - read_8x8_pattern(&fillpat); + read8x8Pattern(&fillpat); } @@ -2792,8 +2804,8 @@ PnSize(struct canvas * const canvasP, blitList * const blitListP, int const version) { - pen_height = read_word(); - pen_width = read_word(); + pen_height = readWord(); + pen_width = readWord(); if (verbose) pm_message("pen size %d x %d", pen_width, pen_height); } @@ -2807,7 +2819,7 @@ PnMode(struct canvas * const canvasP, blitList * const blitListP, int const version) { - pen_mode = read_word(); + pen_mode = readWord(); if (pen_mode >= 8 && pen_mode < 15) pen_mode -= 8; @@ -2821,10 +2833,10 @@ PnMode(struct canvas * const canvasP, static void -read_rgb(struct RGBColor * const rgb) { - rgb->red = read_word(); - rgb->grn = read_word(); - rgb->blu = read_word(); +readRgb(struct RGBColor * const rgb) { + rgb->red = readWord(); + rgb->grn = readWord(); + rgb->blu = readWord(); } @@ -2836,7 +2848,7 @@ RGBFgCol(struct canvas * const canvasP, blitList * const blitListP, int const version) { - read_rgb(&foreground); + readRgb(&foreground); if (verbose) pm_message("foreground now [%d,%d,%d]", foreground.red, foreground.grn, foreground.blu); @@ -2851,7 +2863,7 @@ RGBBkCol(struct canvas * const canvasP, blitList * const blitListP, int const version) { - read_rgb(&background); + readRgb(&background); if (verbose) pm_message("background now [%d,%d,%d]", background.red, background.grn, background.blu); @@ -2869,7 +2881,7 @@ draw_pixel(struct canvas * const canvasP, transfer_func trf) { if (x < clip_rect.left || x >= clip_rect.right || - y < clip_rect.top || y >= clip_rect.bottom) { + y < clip_rect.top || y >= clip_rect.bottom) { } else { unsigned int const i = PIXEL_INDEX(x, y); @@ -3011,8 +3023,8 @@ Line(struct canvas * const canvasP, int const version) { struct Point p1; - read_point(&p1); - read_point(¤t); + readPoint(&p1); + readPoint(¤t); if (verbose) pm_message("(%d,%d) to (%d, %d)", p1.x,p1.y,current.x,current.y); @@ -3029,7 +3041,7 @@ LineFrom(struct canvas * const canvasP, int const version) { struct Point p1; - read_point(&p1); + readPoint(&p1); if (verbose) pm_message("(%d,%d) to (%d, %d)", current.x, current.y, p1.x, p1.y); @@ -3050,8 +3062,8 @@ ShortLine(struct canvas * const canvasP, int const version) { struct Point p1; - read_point(&p1); - read_short_point(¤t); + readPoint(&p1); + readShortPoint(¤t); if (verbose) pm_message("(%d,%d) delta (%d, %d)", p1.x, p1.y, current.x, current.y); current.x += p1.x; @@ -3071,7 +3083,7 @@ ShortLineFrom(struct canvas * const canvasP, int const version) { struct Point p1; - read_short_point(&p1); + readShortPoint(&p1); if (verbose) pm_message("(%d,%d) delta (%d, %d)", current.x,current.y,p1.x,p1.y); @@ -3108,7 +3120,7 @@ paintRect(struct canvas * const canvasP, blitList * const blitListP, int const version) { - read_rect(&cur_rect); + readRect(&cur_rect); if (!blitListP) do_paintRect(canvasP, cur_rect); } @@ -3159,7 +3171,7 @@ frameRect(struct canvas * const canvasP, blitList * const blitListP, int const version) { - read_rect(&cur_rect); + readRect(&cur_rect); if (!blitListP) do_frameRect(canvasP, cur_rect); } @@ -3179,7 +3191,7 @@ frameSameRect(struct canvas * const canvasP, -/* a stupid shell sort - I'm so embarassed */ +/* a stupid shell sort - I'm so embarrassed */ static void poly_sort(int const sort_index, struct Point points[]) { @@ -3326,11 +3338,11 @@ paintPoly(struct canvas * const canvasP, struct Rect bb; struct Point pts[100]; - int i, np = (read_word() - 10) >> 2; + int i, np = (readWord() - 10) >> 2; - read_rect(&bb); + readRect(&bb); for (i=0; i= 8 && text_mode < 15) text_mode -= 8; @@ -3382,7 +3394,7 @@ TxFont(struct canvas * const canvasP, blitList * const blitListP, int const version) { - text_font = read_word(); + text_font = readWord(); if (verbose) pm_message("text font %s", const_name(font_name, text_font)); } @@ -3396,7 +3408,7 @@ TxFace(struct canvas * const canvasP, blitList * const blitListP, int const version) { - text_face = read_byte(); + text_face = readByte(); if (verbose) pm_message("text face %d", text_face); } @@ -3410,7 +3422,7 @@ TxSize(struct canvas * const canvasP, blitList * const blitListP, int const version) { - text_size = read_word(); + text_size = readWord(); if (verbose) pm_message("text size %d", text_size); } @@ -3420,7 +3432,7 @@ TxSize(struct canvas * const canvasP, static void skip_text(blitList * const blitListP) { - skip(read_byte()); + skip(readByte()); blitListP->unblittableText = true; } @@ -3504,11 +3516,11 @@ rotate(int * const x, static void do_ps_text(struct canvas * const canvasP, - word const tx, - word const ty) { + Word const tx, + Word const ty) { int len, width, i, w, h, x, y, rx, ry, o; - byte str[256], ch; + Byte str[256], ch; struct glyph* glyph; current.x = tx; @@ -3520,12 +3532,12 @@ do_ps_text(struct canvas * const canvasP, ps_cent_set = 1; } - len = read_byte(); + len = readByte(); /* XXX this width calculation is not completely correct */ width = 0; for (i = 0; i < len; i++) { - ch = str[i] = read_byte(); + ch = str[i] = readByte(); if (tfont->glyph[ch]) width += tfont->glyph[ch]->xadd; } @@ -3574,8 +3586,8 @@ do_ps_text(struct canvas * const canvasP, static void do_text(struct canvas * const canvasP, blitList * const blitListP, - word const startx, - word const starty) { + Word const startx, + Word const starty) { if (blitListP) skip_text(blitListP); @@ -3587,12 +3599,12 @@ do_text(struct canvas * const canvasP, do_ps_text(canvasP, startx, starty); else { int len; - word x, y; + Word x, y; x = startx; y = starty; - for (len = read_byte(); len > 0; --len) { - struct glyph* const glyph = tfont->glyph[read_byte()]; + for (len = readByte(); len > 0; --len) { + struct glyph* const glyph = tfont->glyph[readByte()]; if (glyph) { int dy; int h; @@ -3628,7 +3640,7 @@ LongText(struct canvas * const canvasP, struct Point p; - read_point(&p); + readPoint(&p); do_text(canvasP, blitListP, p.x, p.y); } @@ -3642,7 +3654,7 @@ DHText(struct canvas * const canvasP, blitList * const blitListP, int const version) { - current.x += read_byte(); + current.x += readByte(); do_text(canvasP, blitListP, current.x, current.y); } @@ -3656,7 +3668,7 @@ DVText(struct canvas * const canvasP, blitList * const blitListP, int const version) { - current.y += read_byte(); + current.y += readByte(); do_text(canvasP, blitListP, current.x, current.y); } @@ -3669,10 +3681,10 @@ static void DHDVText(struct canvas * const canvasP, blitList * const blitListP, int const version) { - byte dh, dv; + Byte dh, dv; - dh = read_byte(); - dv = read_byte(); + dh = readByte(); + dv = readByte(); if (verbose) pm_message("dh, dv = %d, %d", dh, dv); @@ -3686,7 +3698,7 @@ DHDVText(struct canvas * const canvasP, /* - * This could use read_pixmap, but I'm too lazy to hack read_pixmap. + * This could use readPixmap, but I'm too lazy to hack readPixmap. */ static void @@ -3699,36 +3711,36 @@ directBits(struct canvas * const canvasP, struct Rect srcRect; struct Rect dstRect; struct raster raster; - word mode; + Word mode; unsigned int rectWidth; /* skip fake len, and fake EOF */ skip(4); /* Ptr baseAddr == 0x000000ff */ - read_word(); /* version */ - read_rect(&p.Bounds); + readWord(); /* version */ + readRect(&p.Bounds); rectWidth = p.Bounds.right - p.Bounds.left; - p.packType = read_word(); - p.packSize = read_long(); - p.hRes = read_long(); - p.vRes = read_long(); - p.pixelType = read_word(); - p.pixelSize = read_word(); - p.pixelSize = read_word(); /* XXX twice??? */ - p.cmpCount = read_word(); - p.cmpSize = read_word(); - p.planeBytes = read_long(); - p.pmTable = read_long(); - p.pmReserved = read_long(); - - read_rect(&srcRect); + p.packType = readWord(); + p.packSize = readLong(); + p.hRes = readLong(); + p.vRes = readLong(); + p.pixelType = readWord(); + p.pixelSize = readWord(); + p.pixelSize = readWord(); /* XXX twice??? */ + p.cmpCount = readWord(); + p.cmpSize = readWord(); + p.planeBytes = readLong(); + p.pmTable = readLong(); + p.pmReserved = readLong(); + + readRect(&srcRect); if (verbose) dumpRect("source rectangle:", srcRect); - read_rect(&dstRect); + readRect(&dstRect); if (verbose) dumpRect("destination rectangle:", dstRect); - mode = read_word(); + mode = readWord(); if (verbose) pm_message("transfer mode = %s", const_name(transfer_name, mode)); @@ -3776,38 +3788,38 @@ static void do_pixmap(struct canvas * const canvasP, blitList * const blitListP, int const version, - word const rowBytes, + Word const rowBytes, int const is_region) { /*---------------------------------------------------------------------------- Do a paletted image. -----------------------------------------------------------------------------*/ - word mode; + Word mode; struct pixMap p; struct raster raster; struct RGBColor * color_table; struct Rect srcRect; struct Rect dstRect; - read_pixmap(&p); + readPixmap(&p); if (verbose) pm_message("%u x %u paletted image", p.Bounds.right - p.Bounds.left, p.Bounds.bottom - p.Bounds.top); - color_table = read_color_table(); + color_table = readColorTable(); - read_rect(&srcRect); + readRect(&srcRect); if (verbose) dumpRect("source rectangle:", srcRect); - read_rect(&dstRect); + readRect(&dstRect); if (verbose) dumpRect("destination rectangle:", dstRect); - mode = read_word(); + mode = readWord(); if (verbose) pm_message("transfer mode = %s", const_name(transfer_name, mode)); @@ -3843,7 +3855,7 @@ do_bitmap(FILE * const ifP, struct Rect Bounds; struct Rect srcRect; struct Rect dstRect; - word mode; + Word mode; struct raster raster; /* This raster contains padding on the right to make a multiple of 16 pixels per row. @@ -3851,10 +3863,10 @@ do_bitmap(FILE * const ifP, static struct RGBColor color_table[] = { {65535L, 65535L, 65535L}, {0, 0, 0} }; - read_rect(&Bounds); - read_rect(&srcRect); - read_rect(&dstRect); - mode = read_word(); + readRect(&Bounds); + readRect(&srcRect); + readRect(&dstRect); + mode = readWord(); if (verbose) pm_message("transfer mode = %s", const_name(transfer_name, mode)); @@ -3880,12 +3892,12 @@ BitsRect(struct canvas * const canvasP, blitList * const blitListP, int const version) { - word rowBytesWord; + Word rowBytesWord; bool pixMap; unsigned int rowBytes; stage = "Reading rowBytes word for bitsrect"; - rowBytesWord = read_word(); + rowBytesWord = readWord(); interpretRowBytesWord(rowBytesWord, &pixMap, &rowBytes); @@ -3904,12 +3916,12 @@ BitsRegion(struct canvas * const canvasP, blitList * const blitListP, int const version) { - word rowBytesWord; + Word rowBytesWord; bool pixMap; unsigned int rowBytes; stage = "Reading rowBytes for bitsregion"; - rowBytesWord = read_word(); + rowBytesWord = readWord(); interpretRowBytesWord(rowBytesWord, &pixMap, &rowBytes); @@ -3927,7 +3939,7 @@ BitsRegion(struct canvas * const canvasP, */ static struct opdef const optable[] = { /* 0x00 */ { "NOP", 0, NULL, "nop" }, -/* 0x01 */ { "Clip", NA, Clip, "clip" }, +/* 0x01 */ { "ClipRgn", NA, ClipRgn, "clip region" }, /* 0x02 */ { "BkPat", 8, BkPat, "background pattern" }, /* 0x03 */ { "TxFont", 2, TxFont, "text font (word)" }, /* 0x04 */ { "TxFace", 1, TxFace, "text face (byte)" }, @@ -3949,9 +3961,9 @@ static struct opdef const optable[] = { /* 0x14 */ { "FillPixPat", NA, FillPixPat, "color fill pattern" }, /* 0x15 */ { "PnLocHFrac", 2, PnLocHFrac, "fractional pen position" }, /* 0x16 */ { "ChExtra", 2, NULL, "extra for each character" }, -/* 0x17 */ res(0), -/* 0x18 */ res(0), -/* 0x19 */ res(0), +/* 0x17 */ RESERVED_OP(0), +/* 0x18 */ RESERVED_OP(0), +/* 0x19 */ RESERVED_OP(0), /* 0x1a */ { "RGBFgCol", RGB_LEN, RGBFgCol, "RGB foreColor" }, /* 0x1b */ { "RGBBkCol", RGB_LEN, RGBBkCol, "RGB backColor" }, /* 0x1c */ { "HiliteMode", 0, NULL, "hilite mode flag" }, @@ -3963,134 +3975,134 @@ static struct opdef const optable[] = { /* 0x22 */ { "ShortLine", 6, ShortLine, "pnLoc (point, dh, dv (-128 .. 127))" }, /* 0x23 */ { "ShortLineFrom", 2, ShortLineFrom, "dh, dv (-128 .. 127)" }, -/* 0x24 */ res(WORD_LEN), -/* 0x25 */ res(WORD_LEN), -/* 0x26 */ res(WORD_LEN), -/* 0x27 */ res(WORD_LEN), +/* 0x24 */ RESERVED_OP(WORD_LEN), +/* 0x25 */ RESERVED_OP(WORD_LEN), +/* 0x26 */ RESERVED_OP(WORD_LEN), +/* 0x27 */ RESERVED_OP(WORD_LEN), /* 0x28 */ { "LongText", NA, LongText, "txLoc (point), count (0..255), text" }, /* 0x29 */ { "DHText", NA, DHText, "dh (0..255), count (0..255), text" }, /* 0x2a */ { "DVText", NA, DVText, "dv (0..255), count (0..255), text" }, /* 0x2b */ { "DHDVText", NA, DHDVText, "dh, dv (0..255), count (0..255), text" }, -/* 0x2c */ res(WORD_LEN), -/* 0x2d */ res(WORD_LEN), -/* 0x2e */ res(WORD_LEN), -/* 0x2f */ res(WORD_LEN), +/* 0x2c */ RESERVED_OP(WORD_LEN), +/* 0x2d */ RESERVED_OP(WORD_LEN), +/* 0x2e */ RESERVED_OP(WORD_LEN), +/* 0x2f */ RESERVED_OP(WORD_LEN), /* 0x30 */ { "frameRect", 8, frameRect, "rect" }, /* 0x31 */ { "paintRect", 8, paintRect, "rect" }, /* 0x32 */ { "eraseRect", 8, NULL, "rect" }, /* 0x33 */ { "invertRect", 8, NULL, "rect" }, /* 0x34 */ { "fillRect", 8, NULL, "rect" }, -/* 0x35 */ res(8), -/* 0x36 */ res(8), -/* 0x37 */ res(8), +/* 0x35 */ RESERVED_OP(8), +/* 0x36 */ RESERVED_OP(8), +/* 0x37 */ RESERVED_OP(8), /* 0x38 */ { "frameSameRect", 0, frameSameRect, "rect" }, /* 0x39 */ { "paintSameRect", 0, paintSameRect, "rect" }, /* 0x3a */ { "eraseSameRect", 0, NULL, "rect" }, /* 0x3b */ { "invertSameRect", 0, NULL, "rect" }, /* 0x3c */ { "fillSameRect", 0, NULL, "rect" }, -/* 0x3d */ res(0), -/* 0x3e */ res(0), -/* 0x3f */ res(0), +/* 0x3d */ RESERVED_OP(0), +/* 0x3e */ RESERVED_OP(0), +/* 0x3f */ RESERVED_OP(0), /* 0x40 */ { "frameRRect", 8, NULL, "rect" }, /* 0x41 */ { "paintRRect", 8, NULL, "rect" }, /* 0x42 */ { "eraseRRect", 8, NULL, "rect" }, /* 0x43 */ { "invertRRect", 8, NULL, "rect" }, /* 0x44 */ { "fillRRrect", 8, NULL, "rect" }, -/* 0x45 */ res(8), -/* 0x46 */ res(8), -/* 0x47 */ res(8), +/* 0x45 */ RESERVED_OP(8), +/* 0x46 */ RESERVED_OP(8), +/* 0x47 */ RESERVED_OP(8), /* 0x48 */ { "frameSameRRect", 0, NULL, "rect" }, /* 0x49 */ { "paintSameRRect", 0, NULL, "rect" }, /* 0x4a */ { "eraseSameRRect", 0, NULL, "rect" }, /* 0x4b */ { "invertSameRRect", 0, NULL, "rect" }, /* 0x4c */ { "fillSameRRect", 0, NULL, "rect" }, -/* 0x4d */ res(0), -/* 0x4e */ res(0), -/* 0x4f */ res(0), +/* 0x4d */ RESERVED_OP(0), +/* 0x4e */ RESERVED_OP(0), +/* 0x4f */ RESERVED_OP(0), /* 0x50 */ { "frameOval", 8, NULL, "rect" }, /* 0x51 */ { "paintOval", 8, NULL, "rect" }, /* 0x52 */ { "eraseOval", 8, NULL, "rect" }, /* 0x53 */ { "invertOval", 8, NULL, "rect" }, /* 0x54 */ { "fillOval", 8, NULL, "rect" }, -/* 0x55 */ res(8), -/* 0x56 */ res(8), -/* 0x57 */ res(8), +/* 0x55 */ RESERVED_OP(8), +/* 0x56 */ RESERVED_OP(8), +/* 0x57 */ RESERVED_OP(8), /* 0x58 */ { "frameSameOval", 0, NULL, "rect" }, /* 0x59 */ { "paintSameOval", 0, NULL, "rect" }, /* 0x5a */ { "eraseSameOval", 0, NULL, "rect" }, /* 0x5b */ { "invertSameOval", 0, NULL, "rect" }, /* 0x5c */ { "fillSameOval", 0, NULL, "rect" }, -/* 0x5d */ res(0), -/* 0x5e */ res(0), -/* 0x5f */ res(0), +/* 0x5d */ RESERVED_OP(0), +/* 0x5e */ RESERVED_OP(0), +/* 0x5f */ RESERVED_OP(0), /* 0x60 */ { "frameArc", 12, NULL, "rect, startAngle, arcAngle" }, /* 0x61 */ { "paintArc", 12, NULL, "rect, startAngle, arcAngle" }, /* 0x62 */ { "eraseArc", 12, NULL, "rect, startAngle, arcAngle" }, /* 0x63 */ { "invertArc", 12, NULL, "rect, startAngle, arcAngle" }, /* 0x64 */ { "fillArc", 12, NULL, "rect, startAngle, arcAngle" }, -/* 0x65 */ res(12), -/* 0x66 */ res(12), -/* 0x67 */ res(12), +/* 0x65 */ RESERVED_OP(12), +/* 0x66 */ RESERVED_OP(12), +/* 0x67 */ RESERVED_OP(12), /* 0x68 */ { "frameSameArc", 4, NULL, "rect, startAngle, arcAngle" }, /* 0x69 */ { "paintSameArc", 4, NULL, "rect, startAngle, arcAngle" }, /* 0x6a */ { "eraseSameArc", 4, NULL, "rect, startAngle, arcAngle" }, /* 0x6b */ { "invertSameArc", 4, NULL, "rect, startAngle, arcAngle" }, /* 0x6c */ { "fillSameArc", 4, NULL, "rect, startAngle, arcAngle" }, -/* 0x6d */ res(4), -/* 0x6e */ res(4), -/* 0x6f */ res(4), +/* 0x6d */ RESERVED_OP(4), +/* 0x6e */ RESERVED_OP(4), +/* 0x6f */ RESERVED_OP(4), /* 0x70 */ { "framePoly", NA, skip_poly_or_region, "poly" }, /* 0x71 */ { "paintPoly", NA, paintPoly, "poly" }, /* 0x72 */ { "erasePoly", NA, skip_poly_or_region, "poly" }, /* 0x73 */ { "invertPoly", NA, skip_poly_or_region, "poly" }, /* 0x74 */ { "fillPoly", NA, skip_poly_or_region, "poly" }, -/* 0x75 */ resf(skip_poly_or_region), -/* 0x76 */ resf(skip_poly_or_region), -/* 0x77 */ resf(skip_poly_or_region), +/* 0x75 */ RESERVED_OP_F(skip_poly_or_region), +/* 0x76 */ RESERVED_OP_F(skip_poly_or_region), +/* 0x77 */ RESERVED_OP_F(skip_poly_or_region), /* 0x78 */ { "frameSamePoly", 0, NULL, "poly (NYI)" }, /* 0x79 */ { "paintSamePoly", 0, NULL, "poly (NYI)" }, /* 0x7a */ { "eraseSamePoly", 0, NULL, "poly (NYI)" }, /* 0x7b */ { "invertSamePoly", 0, NULL, "poly (NYI)" }, /* 0x7c */ { "fillSamePoly", 0, NULL, "poly (NYI)" }, -/* 0x7d */ res(0), -/* 0x7e */ res(0), -/* 0x7f */ res(0), +/* 0x7d */ RESERVED_OP(0), +/* 0x7e */ RESERVED_OP(0), +/* 0x7f */ RESERVED_OP(0), /* 0x80 */ { "frameRgn", NA, skip_poly_or_region, "region" }, /* 0x81 */ { "paintRgn", NA, skip_poly_or_region, "region" }, /* 0x82 */ { "eraseRgn", NA, skip_poly_or_region, "region" }, /* 0x83 */ { "invertRgn", NA, skip_poly_or_region, "region" }, /* 0x84 */ { "fillRgn", NA, skip_poly_or_region, "region" }, -/* 0x85 */ resf(skip_poly_or_region), -/* 0x86 */ resf(skip_poly_or_region), -/* 0x87 */ resf(skip_poly_or_region), +/* 0x85 */ RESERVED_OP_F(skip_poly_or_region), +/* 0x86 */ RESERVED_OP_F(skip_poly_or_region), +/* 0x87 */ RESERVED_OP_F(skip_poly_or_region), /* 0x88 */ { "frameSameRgn", 0, NULL, "region (NYI)" }, /* 0x89 */ { "paintSameRgn", 0, NULL, "region (NYI)" }, /* 0x8a */ { "eraseSameRgn", 0, NULL, "region (NYI)" }, /* 0x8b */ { "invertSameRgn", 0, NULL, "region (NYI)" }, /* 0x8c */ { "fillSameRgn", 0, NULL, "region (NYI)" }, -/* 0x8d */ res(0), -/* 0x8e */ res(0), -/* 0x8f */ res(0), +/* 0x8d */ RESERVED_OP(0), +/* 0x8e */ RESERVED_OP(0), +/* 0x8f */ RESERVED_OP(0), /* 0x90 */ { "BitsRect", NA, BitsRect, "copybits, rect clipped" }, /* 0x91 */ { "BitsRgn", NA, BitsRegion, "copybits, rgn clipped" }, -/* 0x92 */ res(WORD_LEN), -/* 0x93 */ res(WORD_LEN), -/* 0x94 */ res(WORD_LEN), -/* 0x95 */ res(WORD_LEN), -/* 0x96 */ res(WORD_LEN), -/* 0x97 */ res(WORD_LEN), +/* 0x92 */ RESERVED_OP(WORD_LEN), +/* 0x93 */ RESERVED_OP(WORD_LEN), +/* 0x94 */ RESERVED_OP(WORD_LEN), +/* 0x95 */ RESERVED_OP(WORD_LEN), +/* 0x96 */ RESERVED_OP(WORD_LEN), +/* 0x97 */ RESERVED_OP(WORD_LEN), /* 0x98 */ { "PackBitsRect", NA, BitsRect, "packed copybits, rect clipped" }, /* 0x99 */ { "PackBitsRgn", NA, BitsRegion, "packed copybits, rgn clipped" }, /* 0x9a */ { "DirectBitsRect", NA, DirectBitsRect, "PixMap, srcRect, dstRect, int copymode, PixData" }, /* 0x9b */ { "DirectBitsRgn", NA, DirectBitsRgn, "PixMap, srcRect, dstRect, int copymode, maskRgn, PixData" }, -/* 0x9c */ res(WORD_LEN), -/* 0x9d */ res(WORD_LEN), -/* 0x9e */ res(WORD_LEN), -/* 0x9f */ res(WORD_LEN), +/* 0x9c */ RESERVED_OP(WORD_LEN), +/* 0x9d */ RESERVED_OP(WORD_LEN), +/* 0x9e */ RESERVED_OP(WORD_LEN), +/* 0x9f */ RESERVED_OP(WORD_LEN), /* 0xa0 */ { "ShortComment", 2, ShortComment, "kind (word)" }, /* 0xa1 */ { "LongComment", NA, LongComment, "kind (word), size (word), data" } @@ -4099,7 +4111,7 @@ static struct opdef const optable[] = { static void -processOpcode(word const opcode, +processOpcode(Word const opcode, struct canvas * const canvasP, blitList * const blitListP, unsigned int const version) { @@ -4118,13 +4130,14 @@ processOpcode(word const opcode, else if (optable[opcode].len >= 0) skip(optable[opcode].len); else { + /* It's a special length code */ switch (optable[opcode].len) { case WORD_LEN: { - word const len = read_word(); + Word const len = readWord(); skip(len); - } break; + } break; default: - pm_error("can't do length %u", optable[opcode].len); + pm_error("can't do length %d", optable[opcode].len); } } } else if (opcode == 0xc00) { @@ -4136,7 +4149,7 @@ processOpcode(word const opcode, stage = "skipping reserved"; if (verbose) pm_message("%s 0x%x", stage, opcode); - skip(read_word()); + skip(readWord()); } else if (opcode >= 0xb0 && opcode <= 0xcf) { /* just a reserved opcode, no data */ if (verbose) @@ -4145,21 +4158,21 @@ processOpcode(word const opcode, stage = "skipping reserved"; if (verbose) pm_message("%s 0x%x", stage, opcode); - skip(read_long()); + skip(readLong()); } else if (opcode >= 0x100 && opcode <= 0x7fff) { stage = "skipping reserved"; if (verbose) pm_message("%s 0x%x", stage, opcode); skip((opcode >> 7) & 255); } else if (opcode >= 0x8000 && opcode <= 0x80ff) { - /* just a reserved opcode */ + /* just a reserved opcode, no data */ if (verbose) pm_message("reserved 0x%x", opcode); } else if (opcode >= 0x8100) { stage = "skipping reserved"; if (verbose) pm_message("%s 0x%x", stage, opcode); - skip(read_long()); + skip(readLong()); } else pm_error("This program does not understand opcode 0x%04x", opcode); } @@ -4167,13 +4180,13 @@ processOpcode(word const opcode, static void -interpret_pict(FILE * const ofP) { +interpretPict(FILE * const ofP) { - byte ch; - word picSize; - word opcode; + Byte ch; + Word picSize; + Word opcode; unsigned int version; - int i; + unsigned int i; struct canvas canvas; blitList blitList; @@ -4188,13 +4201,13 @@ interpret_pict(FILE * const ofP) { text_trf = transfer(text_mode); stage = "Reading picture size"; - picSize = read_word(); + picSize = readWord(); if (verbose) pm_message("picture size = %u (0x%x)", picSize, picSize); stage = "reading picture frame"; - read_rect(&picFrame); + readRect(&picFrame); if (verbose) { dumpRect("Picture frame:", picFrame); @@ -4212,18 +4225,18 @@ interpret_pict(FILE * const ofP) { clip_rect = picFrame; } - while ((ch = read_byte()) == 0) + while ((ch = readByte()) == 0) ; if (ch != 0x11) pm_error("No version number"); - version = read_byte(); + version = readByte(); switch (version) { case 1: break; case 2: { - unsigned char const subcode = read_byte(); + unsigned char const subcode = readByte(); if (subcode != 0xff) pm_error("The only Version 2 PICT images this program " "undertands are subcode 0xff. This image has " @@ -4322,7 +4335,7 @@ main(int argc, char * argv[]) { skip(512); } - interpret_pict(stdout); + interpretPict(stdout); pm_close(stdout); diff --git a/converter/ppm/ppmtoacad.c b/converter/ppm/ppmtoacad.c index 4f927f02..b5ee4d65 100644 --- a/converter/ppm/ppmtoacad.c +++ b/converter/ppm/ppmtoacad.c @@ -20,10 +20,9 @@ */ #include -#include "ppm.h" -#define TRUE 1 -#define FALSE 0 +#include "pm_c_util.h" +#include "ppm.h" #define EOS '\0' diff --git a/converter/ppm/ppmtoapplevol.c b/converter/ppm/ppmtoapplevol.c new file mode 100644 index 00000000..e1c7f2dc --- /dev/null +++ b/converter/ppm/ppmtoapplevol.c @@ -0,0 +1,95 @@ +/* ppmtoapplevol.c - read a portable pixmap and produce an Apple volume label + * + * Copyright 2011 Red Hat + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. This software is provided "as is" without express or + * implied warranty. + */ + +#include "pm.h" +#include "ppm.h" + + + +static unsigned char const map[] = { + 0x00, 0xf6, 0xf7, 0x2a, 0xf8, 0xf9, 0x55, 0xfa, + 0xfb, 0x80, 0xfc, 0xfd, 0xab, 0xfe, 0xff, 0xd6 +}; + + + +static void +writeHeader(unsigned int const cols, + FILE * const ofP) { + + unsigned char header[5]; + + header[0] = 0x01; + header[1] = 0x00; + header[2] = cols; + header[3] = 0x00; + header[4] = 0x0c; + + fwrite(header, sizeof(header), 1, ofP); +} + + + +int +main (int argc, const char * argv[]) { + + const char * inputFilename; + FILE * ifP; + int rows, cols; + pixval maxval; + int format; + pixel * pixelrow; + unsigned int row; + + pm_proginit(&argc, argv); + + if (argc-1 > 1) + pm_error("Too many arguments: %u. There is at most one argument: " + "the input file name", argc-1); + + if (argc-1 >= 1) + inputFilename = argv[1]; + else + inputFilename = "-"; + + ifP = pm_openr(inputFilename); + + ppm_readppminit(ifP, &cols, &rows, &maxval, &format); + + if (rows != 12) + pm_error("Input image must be 12 rows tall. Yours is %u", rows); + + writeHeader(cols, stdout); + + pixelrow = ppm_allocrow(cols); + + for (row = 0; row < rows; row++) { + unsigned int col; + + ppm_readppmrow(stdin, pixelrow, cols, maxval, format); + + for (col = 0; col < cols; ++col) { + unsigned int const maxval15Value = + ((unsigned int)PPM_GETR(pixelrow[col]) * 15 + maxval/2) / + maxval; + unsigned char const appleValue = + (unsigned char)map[15 - maxval15Value]; + fwrite(&appleValue, sizeof(appleValue), 1, stdout); + } + } + + ppm_freerow(pixelrow); + + pm_close(ifP); + + return 0; +} diff --git a/converter/ppm/ppmtoarbtxt.c b/converter/ppm/ppmtoarbtxt.c index df859c84..fc8927ce 100644 --- a/converter/ppm/ppmtoarbtxt.c +++ b/converter/ppm/ppmtoarbtxt.c @@ -1,4 +1,4 @@ -/* ppmtoarbtxt.c - convert portable pixmap to cleartext +/* ppmtoarbtxt.c - convert PPM to a custom text-based format ** ** Renamed from ppmtotxt.c by Bryan Henderson in January 2003. ** @@ -12,51 +12,151 @@ ** implied warranty. */ +#include #include +#ifdef __GLIBC__ + #include /* Necessary for parse_printf_format() */ +#endif -#include "ppm.h" +#include "pm_c_util.h" #include "mallocvar.h" #include "nstring.h" +#include "shhopt.h" +#include "ppm.h" + +/* HAVE_PARSE_PRINTF_FORMAT means the system library has + parse_printf_format(), declared in . This essentially means + systems with GNU libc. +*/ + +#ifndef HAVE_PARSE_PRINTF_FORMAT + #ifdef PA_FLAG_MASK /* Defined in printf.h */ + #define HAVE_PARSE_PRINTF_FORMAT 1 + #else + #define HAVE_PARSE_PRINTF_FORMAT 0 + #endif +#endif + + + +struct CmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + const char * inputFileName; + const char * bodySklFileName; + const char * hd; + const char * tl; + unsigned int debug; +}; + + + +static void +parseCommandLine(int argc, const char ** argv, + struct CmdlineInfo * const cmdlineP) { +/*---------------------------------------------------------------------------- + Note that many of the strings that this function returns in the + *cmdline_p structure are actually in the supplied argv array. And + sometimes, one of these strings is actually just a suffix of an entry + in argv! +-----------------------------------------------------------------------------*/ + optEntry * option_def; + /* Instructions to OptParseOptions3 on how to parse our options. + */ + optStruct3 opt; + + unsigned int hdSpec, tlSpec; + + unsigned int option_def_index; + + MALLOCARRAY(option_def, 100); + + option_def_index = 0; /* incremented by OPTENTRY */ + OPTENT3(0, "hd", OPT_STRING, &cmdlineP->hd, + &hdSpec, 0); + OPTENT3(0, "tl", OPT_STRING, &cmdlineP->tl, + &tlSpec, 0); + OPTENT3(0, "debug", OPT_FLAG, NULL, + &cmdlineP->debug, 0); + + opt.opt_table = option_def; + opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ + opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ + + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); + free(option_def); + + if (!hdSpec) + cmdlineP->hd = NULL; + + if (!tlSpec) + cmdlineP->tl = NULL; + + if (argc-1 < 1) + pm_error("You must specify the body skeleton file name as an " + "argument"); + else { + cmdlineP->bodySklFileName = strdup(argv[1]); + + if (argc-1 < 2) + cmdlineP->inputFileName = strdup("-"); /* he wants stdin */ + else { + cmdlineP->inputFileName = strdup(argv[2]); + if (argc-1 > 2) + pm_error("Too many arguments. The only possible arguments " + "are the body skeleton file name and input image " + "file name"); + } + } +} + + + typedef enum { /* The types of object we handle */ BDATA, IRED, IGREEN, IBLUE, ILUM, FRED, FGREEN, FBLUE, FLUM, WIDTH, HEIGHT, POSX, POSY -} SKL_OBJ_TYP; +} SkeletonObjectType; typedef enum { OBJTYP_ICOLOR, OBJTYP_FCOLOR, OBJTYP_INT, OBJTYP_BDATA -} SKL_OBJ_CLASS; +} SkeletonObjectClass; /* Maximum size for a format string ("%d" etc.) */ +/* Add one to this size for the terminating '\0'. */ #define MAXFORMAT 16 +typedef union { /* The data we keep for each object */ -typedef union - { - struct BNDAT { char *bdat; /* Binary data (text with newlines etc.) */ - int ndat; - } bin_data; - - struct ICDAT { char icformat[MAXFORMAT]; /* Integer colors */ - int icolmin, icolmax; - } icol_data; - - struct FCDAT { char fcformat[MAXFORMAT]; /* Float colors */ - double fcolmin, fcolmax; - } fcol_data; - - struct IDAT { char iformat[MAXFORMAT]; /* Integer data */ - } i_data; - } SKL_OBJ_DATA; + struct Bndat { + char * bdat; /* Binary data (text with newlines etc.) */ + unsigned int ndat; + } binData; + + struct Icdat { + char icformat[MAXFORMAT+1]; /* Integer colors */ + unsigned int icolmin, icolmax; + } icolData; + + struct Fcdat { + char fcformat[MAXFORMAT+1]; /* Float colors */ + double fcolmin, fcolmax; + } fcolData; + + struct Idat { + char iformat[MAXFORMAT+1]; /* Integer data */ + } iData; +} SkeletonObjectData; /* Each object has a type and some data */ -typedef struct - { - SKL_OBJ_TYP otyp; - SKL_OBJ_DATA odata; - } SKL_OBJ; +typedef struct { + SkeletonObjectType objType; + SkeletonObjectData odata; +} SkeletonObject; + #define MAX_SKL_HEAD_OBJ 64 @@ -66,199 +166,168 @@ typedef struct #define MAX_OBJ_BUF 80 -static void write_txt (fout, nobj, obj, width, height, x, y, red, green, blue) -FILE *fout; -int nobj; -SKL_OBJ *obj[]; -int width, height, x, y; -double red, green, blue; - -{register int count; - -#define WRITE_BNDAT(fd,theobj) \ - {struct BNDAT *bdata = &((theobj)->odata.bin_data); \ - fwrite (bdata->bdat,bdata->ndat,1,fd); } - -#define WRITE_ICOL(fd,theobj,thecol) \ - {struct ICDAT *icdata = &((theobj)->odata.icol_data); \ - fprintf (fd,icdata->icformat,(int)(icdata->icolmin \ - + (icdata->icolmax - icdata->icolmin)*(thecol))); } - -#define WRITE_FCOL(fd,theobj,thecol) \ - {struct FCDAT *fcdata = &((theobj)->odata.fcol_data); \ - fprintf (fd,fcdata->fcformat,(double)(fcdata->fcolmin \ - + (fcdata->fcolmax - fcdata->fcolmin)*(thecol))); } - -#define WRITE_IDAT(fd,theobj,thedat) \ - {struct IDAT *idata = &((theobj)->odata.i_data); \ - fprintf (fd,idata->iformat,thedat); } - - for (count = 0; count < nobj; count++) - { - switch (obj[count]->otyp) - { - case BDATA: - WRITE_BNDAT (fout,obj[count]); - break; - case IRED: - WRITE_ICOL (fout,obj[count],red); - break; - case IGREEN: - WRITE_ICOL (fout,obj[count],green); - break; - case IBLUE: - WRITE_ICOL (fout,obj[count],blue); - break; - case ILUM: - WRITE_ICOL (fout,obj[count],0.299*red+0.587*green+0.114*blue); - break; - case FRED: - WRITE_FCOL (fout,obj[count],red); - break; - case FGREEN: - WRITE_FCOL (fout,obj[count],green); - break; - case FBLUE: - WRITE_FCOL (fout,obj[count],blue); - break; - case FLUM: - WRITE_FCOL (fout,obj[count],0.299*red+0.587*green+0.114*blue); - break; - case WIDTH: - WRITE_IDAT (fout,obj[count],width); - break; - case HEIGHT: - WRITE_IDAT (fout,obj[count],height); - break; - case POSX: - WRITE_IDAT (fout,obj[count],x); - break; - case POSY: - WRITE_IDAT (fout,obj[count],y); - break; - } - } -} +static void +dumpSkeleton(SkeletonObject ** const skeletonPList, + unsigned int const nSkeleton) { -static SKL_OBJ * -save_bin_data(int const ndat, - char * const bdat) { + unsigned int i; - /* Save binary data in Object */ + pm_message("%u objects", nSkeleton); - SKL_OBJ *obj; + for (i = 0; i < nSkeleton; ++i) { + SkeletonObject * const skeletonP = skeletonPList[i]; - obj = (SKL_OBJ *)malloc (sizeof (SKL_OBJ) + ndat); - if (obj != NULL) - { - obj->otyp = BDATA; - obj->odata.bin_data.ndat = ndat; - obj->odata.bin_data.bdat = ((char *)(obj))+sizeof (SKL_OBJ); - memcpy (obj->odata.bin_data.bdat,bdat,ndat); + pm_message(" Object: Type %u", skeletonP->objType); } - return (obj); } -static SKL_OBJ * -save_icol_data(SKL_OBJ_TYP const ctyp, - const char * const format, - int const icolmin, - int const icolmax) { -/* Save integer color data in Object */ - - SKL_OBJ * objP; +static void +dumpAllSkeleton(SkeletonObject ** const bodySkeletonPList, + unsigned int const bodyNskl, + SkeletonObject ** const headSkeletonPList, + unsigned int const headNskl, + SkeletonObject ** const tailSkeletonPList, + unsigned int const tailNskl) { + + pm_message("Body skeleton:"); + dumpSkeleton(bodySkeletonPList, bodyNskl); + + pm_message("Head skeleton:"); + dumpSkeleton(headSkeletonPList, headNskl); + + pm_message("Tail skeleton:"); + dumpSkeleton(tailSkeletonPList, tailNskl); +} - MALLOCVAR(objP); - if (objP) { - objP->otyp = ctyp; - strcpy(objP->odata.icol_data.icformat, format); - objP->odata.icol_data.icolmin = icolmin; - objP->odata.icol_data.icolmax = icolmax; - } - return objP; -} +static void +writeBndat(FILE * const ofP, + SkeletonObject * const objectP) { + struct Bndat * const bdataP = &objectP->odata.binData; -static SKL_OBJ * -save_fcol_data(SKL_OBJ_TYP const ctyp, - const char * const format, - double const fcolmin, - double const fcolmax) { -/* Save float color data in Object */ + fwrite(bdataP->bdat, bdataP->ndat, 1, ofP); +} - SKL_OBJ * objP; - MALLOCVAR(objP); - if (objP) { - objP->otyp = ctyp; - strcpy(objP->odata.fcol_data.fcformat, format); - objP->odata.fcol_data.fcolmin = fcolmin; - objP->odata.fcol_data.fcolmax = fcolmax; - } - return objP; -} +static void +writeIcol(FILE * const ofP, + SkeletonObject * const objectP, + double const value) { + /* Unlike Netpbm, the output format does not have an upper limit for + maxval. Here we allow all values representable by unsigned int. + */ + struct Icdat * const icdataP = &objectP->odata.icolData; + unsigned int const outValue = + ROUNDU( icdataP->icolmin + + ((double)icdataP->icolmax - icdataP->icolmin) * value); -static SKL_OBJ * -save_i_data(SKL_OBJ_TYP const ctyp, - const char * const format) { + fprintf(ofP, icdataP->icformat, outValue); +} -/* Save universal data in Object */ - SKL_OBJ * objP; - MALLOCVAR(objP); - if (objP) { - objP->otyp = ctyp; - strcpy(objP->odata.i_data.iformat, format); - } - return objP; +static void +writeFcol(FILE * const ofP, + SkeletonObject * const objectP, + double const value) { + + struct Fcdat * const fcdataP = &objectP->odata.fcolData; + + fprintf(ofP, fcdataP->fcformat, + (double) + (fcdataP->fcolmin + + (fcdataP->fcolmax - fcdataP->fcolmin) * value)); } -static char const escape = '#'; +static void +writeIdat(FILE * const ofP, + SkeletonObject * const objectP, + unsigned int const value) { + + struct Idat * const idataP = &objectP->odata.iData; + + fprintf(ofP, idataP->iformat, value); +} -static SKL_OBJ_TYP -interpretObjType(const char * const typstr) { +static void +writeText(FILE * const ofP, + unsigned int const nObj, + SkeletonObject ** const obj, + unsigned int const width, + unsigned int const height, + unsigned int const x, + unsigned int const y, + double const red, + double const green, + double const blue) { + + unsigned int i; - SKL_OBJ_TYP otyp; - - /* Check for integer colors */ - if (streq(typstr, "ired") ) otyp = IRED; - else if (streq(typstr, "igreen")) otyp = IGREEN; - else if (streq(typstr, "iblue") ) otyp = IBLUE; - else if (streq(typstr, "ilum") ) otyp = ILUM; - /* Check for real colors */ - else if (streq(typstr, "fred") ) otyp = FRED; - else if (streq(typstr, "fgreen")) otyp = FGREEN; - else if (streq(typstr, "fblue") ) otyp = FBLUE; - else if (streq(typstr, "flum") ) otyp = FLUM; - /* Check for integer data */ - else if (streq(typstr, "width") ) otyp = WIDTH; - else if (streq(typstr, "height")) otyp = HEIGHT; - else if (streq(typstr, "posx") ) otyp = POSX; - else if (streq(typstr, "posy") ) otyp = POSY; - else otyp = BDATA; - - return otyp; + for (i = 0; i < nObj; ++i) { + switch (obj[i]->objType) { + case BDATA: + writeBndat(ofP, obj[i]); + break; + case IRED: + writeIcol(ofP, obj[i], red); + break; + case IGREEN: + writeIcol(ofP, obj[i], green); + break; + case IBLUE: + writeIcol(ofP, obj[i], blue); + break; + case ILUM: + writeIcol(ofP, obj[i], + PPM_LUMINR*red + PPM_LUMING*green + PPM_LUMINB*blue); + break; + case FRED: + writeFcol(ofP, obj[i], red); + break; + case FGREEN: + writeFcol(ofP, obj[i], green); + break; + case FBLUE: + writeFcol(ofP, obj[i], blue); + break; + case FLUM: + writeFcol(ofP, obj[i], + PPM_LUMINR*red + PPM_LUMING*green + PPM_LUMINB*blue); + break; + case WIDTH: + writeIdat(ofP, obj[i], width); + break; + case HEIGHT: + writeIdat(ofP, obj[i], height); + break; + case POSX: + writeIdat(ofP, obj[i], x); + break; + case POSY: + writeIdat(ofP, obj[i], y); + break; + } + } } -static SKL_OBJ_CLASS -objClass(SKL_OBJ_TYP const otyp) { +static SkeletonObjectClass +objClass(SkeletonObjectType const objType) { - switch (otyp) { + switch (objType) { case IRED: case IGREEN: case IBLUE: @@ -283,298 +352,873 @@ objClass(SKL_OBJ_TYP const otyp) { } +/*---------------------------------------------------------------------------- + Format string validation + + We validate format strings (such as "%f" "%03d") found in the skeleton files + for convenience, even though behavior is documented as undefined when the + user supplies a bogus format string. Certain strings, most notably those + with "%n", are especially risky; they pose a security threat. + + On systems with Glibc, we check with parse_printf_format(). On other + systems we conduct a cursory scan of the characters in the format string, + looking for characters that trigger non-numeric conversions, etc. + + Documentation for parse_printf_format() is usually available in texinfo + format on GNU/Linux systems. As of Dec. 2014 there is no official man page. + + Online documentation is available from: + https:// + www.gnu.org/software/libc/manual/html_node/Parsing-a-Template-String.html +-----------------------------------------------------------------------------*/ +#if HAVE_PARSE_PRINTF_FORMAT static void -addImpostorReplacementSeq(char * const line, - unsigned int const startCursor, - const char * const seqContents, - unsigned int const seqContentsLen, - unsigned int * const newCursorP) { +validateParsePrintfFlag(int const printfConversion, + SkeletonObjectType const ctyp, + const char ** const errorP) { /*---------------------------------------------------------------------------- - Add to line line[], at position 'startCursor', text that looks like a - replacement sequence but doesn't have the proper contents (the - stuff between the parentheses) to be one. For example, + Assuming 'printfConversion' is the value reported by parse_printf_format() + as the type of argument a format string requires, + return an explanation of how it is incompatible with 'ctyp' as + *errorP -- return null string if it is compatible. +-----------------------------------------------------------------------------*/ + /* We first check for "%n", then the type modifiers, and finally the + actual conversion type (char, int, float, double, string or pointer.) + */ + switch (printfConversion & PA_FLAG_MASK) { + case PA_FLAG_PTR: /* This means %n */ + pm_asprintf(errorP, "Contains a %%n conversion specifier"); + break; + + case PA_FLAG_SHORT: + case PA_FLAG_LONG: + case PA_FLAG_LONG_LONG: + /* We omit PA_FLAG_LONG_DOUBLE because it is a synonym for + PA_FLAG_LONG_LONG: listing both causes compilation errors. + */ + pm_asprintf(errorP, "Invalid type modifier"); + break; + + default: + switch (printfConversion & ~PA_FLAG_MASK) { + case PA_CHAR: + pm_message("Warning: char type conversion."); + case PA_INT: + if(objClass(ctyp) == OBJTYP_ICOLOR || + objClass(ctyp) == OBJTYP_INT ) + *errorP = NULL; + else + pm_asprintf(errorP, "Conversion specifier requires a " + "character or integer argument, but it is in " + "a replacement sequence for a different type"); + break; + case PA_DOUBLE: + if(objClass(ctyp) == OBJTYP_FCOLOR) + *errorP = NULL; + else + pm_asprintf(errorP, "Conversion specifier requires a " + "double precision floating point argument, " + "but it is in " + "a replacement sequence for a different type"); + break; + case PA_FLOAT: + case PA_STRING: /* %s */ + case PA_POINTER: /* %p */ + default: + pm_asprintf(errorP, "Conversion specifier requires an argument of " + "a type that this program never provides for " + "any replacement sequence"); + } + } +} +#endif - "#(fread x)" - seqContents[] is the contents; 'seqContentsLen' its length. - Return as *newCursorP where the line[] cursor ends up after adding - the sequence. +#if HAVE_PARSE_PRINTF_FORMAT +static void +validateFormatWithPpf(const char * const format, + SkeletonObjectType const ctyp, + const char ** const errorP) { +/*---------------------------------------------------------------------------- + Validate format string 'format' for use with a skeleton of type 'ctyp', + using the system parse_printf_format() function. + + Return as *errorP an explanation of how it is invalid, or a null string + if it is valid. -----------------------------------------------------------------------------*/ - unsigned int cursor; - unsigned int i; + /* We request parse_printf_format() to report the details of the first + 8 conversions. 8 because the maximum length of format is 16 means it + can have up to 8 conversions: "%d%d%d%d%d%d%d%d". + + Actually this is more than necessary: we are concerned with only the + first conversion and whether there it is the only one. + */ - cursor = startCursor; + int printfConversion[MAXFORMAT/2] = {0, 0, 0, 0, 0, 0, 0, 0}; - line[cursor++] = escape; - line[cursor++] = '('; + size_t const n = + parse_printf_format(format, MAXFORMAT/2, printfConversion); + + switch (n) { + case 0: + pm_asprintf(errorP, "No transformation found"); + break; + + case 1: + validateParsePrintfFlag(printfConversion[0], ctyp, errorP); + break; + + default: + pm_asprintf(errorP, "Has %lu extra transformation%s ", + (unsigned long)n-1, n-1 > 1 ? "s" : ""); + break; + } +} +#endif - for (i = 0; i < seqContentsLen; ++i) - line[cursor++] = seqContents[i]; - line[cursor++] = ')'; - *newCursorP = cursor; +static void +validateFormatOne(char const typeSpecifier, + bool const isLastInString, + SkeletonObjectType const ctyp, + bool * const validatedP, + const char ** const errorP) { + + switch (typeSpecifier) { + /* Valid character encountered. Skip. */ + /* ' ' (space) is listed here, but should never occur for + we use sscanf() to parse the fields. + */ + case ' ': case '-': case '+': case '\'': case '#': case '.': + case '0': case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + break; + + case 'c': case 'C': + pm_message("Warning: char type conversion: %%%c.", typeSpecifier); + case 'i': case 'd': case 'u': case 'o': case 'x': case 'X': + if (!isLastInString) + pm_asprintf(errorP, "Extra characters at end"); + else if(objClass(ctyp) != OBJTYP_ICOLOR && + objClass(ctyp) != OBJTYP_INT ) + pm_asprintf(errorP, "Conversion type mismatch"); + else + *validatedP = true; + break; + + case 'f': case 'F': case 'g': case 'G': case 'a': case 'A': + if (!isLastInString) + pm_asprintf(errorP, "Extra characters at end"); + else if(objClass(ctyp) != OBJTYP_FCOLOR) + pm_asprintf(errorP, "Conversion type mismatch"); + else + *validatedP = true; + break; + + case '\0': + pm_asprintf(errorP, "No conversion specified"); + break; + case '%': + pm_asprintf(errorP, "No more than one %% is allowed"); + break; + case '$': + case '*': + pm_asprintf(errorP, "%c is not allowed", typeSpecifier); + break; + case 'h': case 'l': case 'L': case 'q': case 'j': case 'Z': case 't': + pm_asprintf(errorP, "Modifier %c is not allowed in format", + typeSpecifier); + break; + case 's': case 'S': case 'm': case 'p': case 'n': + pm_asprintf(errorP, "Invalid conversion type"); + break; + default: + pm_asprintf(errorP, "Abnormal character"); + break; + } } -static int -read_skeleton(const char * const filename, - unsigned int const maxskl, - unsigned int * const nsklP, - SKL_OBJ ** const skl) { +static void +validateFormatGen(const char * const format, + SkeletonObjectType const ctyp, + const char ** const errorP) { /*---------------------------------------------------------------------------- - Read skeleton file + Validate format string 'format' for use with a skeleton of type 'ctyp', + without using the system parse_printf_format() function. + + The string must begin with "%" and end with the translation type character + ("%d", "%x", "%f", etc.) + + We check only for invalid characters. Invalid constructs, such as + "%00.00.00d" will pass this test. + + Return as *errorP an explanation of how it is invalid, or a null string + if it is valid. -----------------------------------------------------------------------------*/ - FILE * sklfile; - unsigned int slen; - unsigned int objlen; - int chr; - SKL_OBJ_TYP otyp; - char line[MAX_LINE_BUF+MAX_OBJ_BUF+16]; - char objstr[MAX_OBJ_BUF],typstr[MAX_OBJ_BUF]; - unsigned int nskl; - -#define SAVE_BIN(slen,line) \ - { if (slen > 0 && (skl[nskl] = save_bin_data(slen,line)) != NULL) ++nskl; \ - slen = 0; } - - sklfile = pm_openr(filename); - - /* Parse skeleton file */ - nskl = 0; /* initial value */ - - slen = 0; - while ((chr = getc (sklfile)) != EOF) { /* Up to end of skeleton file */ - if (nskl >= maxskl) - return -1; - - if (slen+1 >= MAX_LINE_BUF) { - /* Buffer finished. Save as binary object */ - SAVE_BIN(slen,line); + if (format[0] != '%') + pm_asprintf(errorP, "Does not start with %%"); + else { + unsigned int i; + bool validated; + + for (i = 1, validated = false, *errorP = NULL; + !validated && !*errorP; + ++i) { + + validateFormatOne(format[i], format[i+1] == '\0', ctyp, + &validated, errorP); } + } +} - if (chr != escape) { - /* Not a replacement sequence; just a literal character */ - line[slen++] = chr; - continue; - } - chr = getc(sklfile); - if (chr == EOF) { - /* Not a valid replacement sequence */ - line[slen++] = escape; - break; - } - if (chr != '(') { - /* Not a valid replacement sequence */ - line[slen++] = escape; - line[slen++] = chr; - continue; + +static void +validateFormat(const char * const format, + SkeletonObjectType const ctyp) { + + const char * error; + + if (strlen(format) > MAXFORMAT) + pm_asprintf(&error, "Too long"); + else { +#if HAVE_PARSE_PRINTF_FORMAT + if (true) + validateFormatWithPpf(format, ctyp, &error); + else /* Silence compiler warning about unused function */ + validateFormatGen(format, ctyp, &error); +#else + validateFormatGen(format, ctyp, &error); +#endif + } + + if (error) + pm_error("Invalid format string '%s'. %s", format, error); +} + + + +static SkeletonObject * +newBinDataObj(unsigned int const nDat, + const char * const bdat) { +/*---------------------------------------------------------------------------- + Create a binary data object. +-----------------------------------------------------------------------------*/ + SkeletonObject * objectP; + + objectP = malloc(sizeof(*objectP) + nDat); + + if (!objectP) + pm_error("Failed to allocate memory for binary data object " + "with %u bytes", nDat); + + objectP->objType = BDATA; + objectP->odata.binData.ndat = nDat; + objectP->odata.binData.bdat = ((char *)objectP) + sizeof(SkeletonObject); + memcpy(objectP->odata.binData.bdat, bdat, nDat); + + return objectP; +} + + + +static SkeletonObject * +newIcolDataObj(SkeletonObjectType const ctyp, + const char * const format, + unsigned int const icolmin, + unsigned int const icolmax) { +/*---------------------------------------------------------------------------- + Create integer color data object. +-----------------------------------------------------------------------------*/ + SkeletonObject * objectP; + + MALLOCVAR(objectP); + + if (!objectP) + pm_error("Failed to allocate memory for an integer color data " + "object"); + + objectP->objType = ctyp; + validateFormat(format, ctyp); + strcpy(objectP->odata.icolData.icformat, format); + objectP->odata.icolData.icolmin = icolmin; + objectP->odata.icolData.icolmax = icolmax; + + return objectP; +} + + + +static SkeletonObject * +newFcolDataObj(SkeletonObjectType const ctyp, + const char * const format, + double const fcolmin, + double const fcolmax) { +/*---------------------------------------------------------------------------- + Create float color data object. +-----------------------------------------------------------------------------*/ + SkeletonObject * objectP; + + MALLOCVAR(objectP); + + if (!objectP) + pm_error("Failed to allocate memory for a float color data object"); + + objectP->objType = ctyp; + validateFormat(format, ctyp); + strcpy(objectP->odata.fcolData.fcformat, format); + objectP->odata.fcolData.fcolmin = fcolmin; + objectP->odata.fcolData.fcolmax = fcolmax; + + return objectP; +} + + + +static SkeletonObject * +newIdataObj(SkeletonObjectType const ctyp, + const char * const format) { +/*---------------------------------------------------------------------------- + Create universal data object. +-----------------------------------------------------------------------------*/ + SkeletonObject * objectP; + + MALLOCVAR(objectP); + + if (!objectP) + pm_error("Failed to allocate memory for a universal data object"); + + objectP->objType = ctyp; + validateFormat(format, ctyp); + strcpy(objectP->odata.iData.iformat, format); + + return objectP; +} + + + +static char const escape = '#'; + + + +static SkeletonObjectType +interpretObjType(const char * const typstr) { + + SkeletonObjectType objType; + + /* handle integer colors */ + if (streq(typstr, "ired") ) objType = IRED; + else if (streq(typstr, "igreen")) objType = IGREEN; + else if (streq(typstr, "iblue") ) objType = IBLUE; + else if (streq(typstr, "ilum") ) objType = ILUM; + /* handle real colors */ + else if (streq(typstr, "fred") ) objType = FRED; + else if (streq(typstr, "fgreen")) objType = FGREEN; + else if (streq(typstr, "fblue") ) objType = FBLUE; + else if (streq(typstr, "flum") ) objType = FLUM; + /* handle integer data */ + else if (streq(typstr, "width") ) objType = WIDTH; + else if (streq(typstr, "height")) objType = HEIGHT; + else if (streq(typstr, "posx") ) objType = POSX; + else if (streq(typstr, "posy") ) objType = POSY; + else objType = BDATA; + + return objType; +} + + + +static SkeletonObject * +newIcSkelFromReplString(const char * const objstr, + SkeletonObjectType const objType) { + + SkeletonObject * retval; + unsigned int icolmin, icolmax; + char formstr[MAX_OBJ_BUF]; + unsigned int nOdata; + + nOdata = sscanf(objstr, "%*s%s%u%u", formstr, &icolmin, &icolmax); + + if (nOdata == 3) + retval = newIcolDataObj(objType, formstr, icolmin, icolmax); + else if (nOdata == EOF) { + /* No arguments specified. Use defaults */ + retval = newIcolDataObj(objType, "%u", 0, 255); + } else + retval = NULL; + + return retval; +} + + + +static SkeletonObject * +newFcSkelFromReplString(const char * const objstr, + SkeletonObjectType const objType) { + + SkeletonObject * retval; + double fcolmin, fcolmax; + char formstr[MAX_OBJ_BUF]; + unsigned int nOdata; + + nOdata = sscanf(objstr, "%*s%s%lf%lf", formstr, + &fcolmin, &fcolmax); + + if (nOdata == 3) + retval = newFcolDataObj(objType, formstr, fcolmin, fcolmax); + else if (nOdata == EOF) { + /* No arguments specified. Use defaults */ + retval = newFcolDataObj(objType, "%f", 0.0, 1.0); + } else + retval = NULL; + + return retval; +} + + + +static SkeletonObject * +newISkelFromReplString(const char * const objstr, + SkeletonObjectType const objType) { + + SkeletonObject * retval; + char formstr[MAX_OBJ_BUF]; + unsigned int const nOdata = sscanf(objstr, "%*s%s", formstr); + + if (nOdata == 1) + retval = newIdataObj(objType, formstr); + else if (nOdata == EOF) { + /* No arguments specified. Use defaults */ + retval = newIdataObj(objType, "%u"); + } else + retval = NULL; + + return retval; +} + + + +static SkeletonObject * +newSkeletonFromReplString(const char * const objstr) { +/*---------------------------------------------------------------------------- + Create a skeleton from the replacement string 'objstr' (the stuff + between the parentheses in #(...) ). + + Return NULL if it isn't a valid replacement string. +-----------------------------------------------------------------------------*/ + /* We use sscanf() to parse the contents of objstr, giving it a format + template with the largest number of fields possible plus one extra to + pick up and check for the existence of invalid trailing characters. We + read and discard fields beyond the first, if any. The appropriate + new**SkelFromReplString() function determines their contents with a + separate call to sscanf(). + */ + + SkeletonObject * retval; + char typstr[MAX_OBJ_BUF]; + SkeletonObjectType objType; + int conversionCt; + char s1[MAX_OBJ_BUF]; /* Dry read. */ + char s2[MAX_OBJ_BUF]; /* Extra tailing characters. */ + float f1, f2; /* Dry read. */ + + typstr[0] = '\0'; /* initial value */ + + conversionCt = sscanf(objstr, "%s%s%f%f%s", typstr, s1, &f1, &f2, s2); + switch (conversionCt) { + case 1: case 2: case 4: + objType = interpretObjType(typstr); + break; + default: + objType = BDATA; + } + + switch (objClass(objType)) { + case OBJTYP_ICOLOR: + retval = newIcSkelFromReplString(objstr, objType); + break; + case OBJTYP_FCOLOR: + retval = newFcSkelFromReplString(objstr, objType); + break; + case OBJTYP_INT: + retval = newISkelFromReplString(objstr, objType); + break; + case OBJTYP_BDATA: + retval = NULL; + } + return retval; +} + + + +static void +readThroughCloseParen(FILE * const ifP, + char * const objstr, + size_t const objstrSize, + bool * const unclosedP) { +/*---------------------------------------------------------------------------- + Read *ifP up through close parenthesis ( ')' ) into 'objstr', which + is of size 'objstrSize'. Make it a NUL-terminated string. + + Return *unclosedP true iff we run out of file or run out of objstr + before we see a close parenthesis. In this case, return the rest of + the file, or as much as fits, in 'objstr', not NUL-terminated. +-----------------------------------------------------------------------------*/ + unsigned int i; + bool eof; + bool gotEscSeq; + + for (i= 0, eof = false, gotEscSeq = false; + i < objstrSize - 1 && !gotEscSeq && !eof; + ++i) { + + int rc; + + rc = getc(ifP); + if (rc == EOF) + eof = true; + else { + char const chr = rc; + if (chr == ')') { + gotEscSeq = true; + objstr[i] = '\0'; + } else + objstr[i] = chr; } - /* Read replacement string up through ')'. Put contents of - parentheses in objstr[]. + } + *unclosedP = !gotEscSeq; +} + + + +typedef struct { + unsigned int capacity; + SkeletonObject ** skeletonPList; + unsigned int nSkeleton; +} SkeletonBuffer; + + + +static void +SkeletonBuffer_init(SkeletonBuffer * const bufferP, + unsigned int const capacity, + SkeletonObject ** const skeletonPList) { + + bufferP->capacity = capacity; + bufferP->skeletonPList = skeletonPList; + bufferP->nSkeleton = 0; +} + + + +static void +SkeletonBuffer_add(SkeletonBuffer * const bufferP, + SkeletonObject * const skeletonP) { + + if (bufferP->nSkeleton >= bufferP->capacity) + pm_error("Too many skeletons. Max = %u", bufferP->capacity); + + bufferP->skeletonPList[bufferP->nSkeleton++] = skeletonP; +} + + + +typedef struct { + + char data[MAX_LINE_BUF + MAX_OBJ_BUF + 16]; + + unsigned int length; + + SkeletonBuffer * skeletonBufferP; + /* The buffer to which we flush. Flushing means turning all the + characters currently in our buffer into a binary skeleton object + here. */ - for (objlen = 0; objlen < sizeof(objstr)-1; ++objlen) { - chr = getc(sklfile); - if (chr == EOF) break; - if (chr == ')') break; - objstr[objlen] = chr; - } - objstr[objlen] = '\0'; - - if (chr != ')') { - /* Not valid replacement sequence */ - unsigned int i; - line[slen++] = escape; - line[slen++] = chr; - for (i = 0; i < objlen; ++i) - line[slen++] = objstr[i]; - if (chr == EOF) - break; - continue; - } - typstr[0] = '\0'; /* Get typ of data */ - sscanf(objstr, "%s", typstr); - - otyp = interpretObjType(typstr); - - switch (objClass(otyp)) { - case OBJTYP_ICOLOR: { - int icolmin, icolmax; - char formstr[MAX_OBJ_BUF]; - int n_odata; - - n_odata = sscanf(objstr, "%*s%s%d%d", formstr, &icolmin, &icolmax); - - if (n_odata == 3) { - SAVE_BIN(slen, line); - skl[nskl] = save_icol_data(otyp, formstr, icolmin, icolmax); - if (skl[nskl] != NULL) - ++nskl; - } else if (n_odata == EOF) { - /* No arguments specified. Use defaults */ - SAVE_BIN(slen, line); - skl[nskl] = save_icol_data(otyp, "%d", 0, 255); - if (skl[nskl] != NULL) - ++nskl; - } else - addImpostorReplacementSeq(line, slen, objstr, objlen, &slen); - } break; - case OBJTYP_FCOLOR: { - double fcolmin, fcolmax; - char formstr[MAX_OBJ_BUF]; - int n_odata; - - n_odata = sscanf(objstr, "%*s%s%lf%lf", formstr, - &fcolmin, &fcolmax); - - if (n_odata == 3) { - SAVE_BIN(slen, line); - skl[nskl] = save_fcol_data(otyp, formstr, fcolmin, fcolmax); - if (skl[nskl] != NULL) - ++nskl; - } else if (n_odata == EOF) { - /* No arguments specified. Use defaults */ - SAVE_BIN(slen, line); - skl[nskl] = save_fcol_data(otyp, "%f", 0.0, 1.0); - if (skl[nskl] != NULL) - ++nskl; - } else - addImpostorReplacementSeq(line, slen, objstr, objlen, &slen); - } break; - - case OBJTYP_INT: { - char formstr[MAX_OBJ_BUF]; - int const n_odata = sscanf(objstr, "%*s%s", formstr); - - if (n_odata == 1) { - SAVE_BIN(slen, line); - skl[nskl] = save_i_data(otyp, formstr); - if (skl[nskl] != NULL) - ++nskl; - } else if (n_odata == EOF) { - /* No arguments specified. Use defaults */ - SAVE_BIN(slen, line); - skl[nskl] = save_i_data(otyp, "%d"); - if (skl[nskl] != NULL) - ++nskl; - } else - addImpostorReplacementSeq(line, slen, objstr, objlen, &slen); - } break; - case OBJTYP_BDATA: - addImpostorReplacementSeq(line, slen, objstr, objlen, &slen); +} Buffer; + + + +static void +Buffer_init(Buffer * const bufferP, + SkeletonBuffer * const skeletonBufferP) { + + bufferP->skeletonBufferP = skeletonBufferP; + bufferP->length = 0; +} + + + +static void +Buffer_flush(Buffer * const bufferP) { +/*---------------------------------------------------------------------------- + Flush the buffer out to a binary skeleton object. +-----------------------------------------------------------------------------*/ + SkeletonBuffer_add(bufferP->skeletonBufferP, + newBinDataObj(bufferP->length, bufferP->data)); + + bufferP->length = 0; +} + + + +static void +Buffer_add(Buffer * const bufferP, + char const newChar) { + + if (bufferP->length >= MAX_LINE_BUF) + Buffer_flush(bufferP); + + assert(bufferP->length < MAX_LINE_BUF); + + bufferP->data[bufferP->length++] = newChar; +} + + + +static void +Buffer_dropFinalNewline(Buffer * const bufferP) { +/*---------------------------------------------------------------------------- + If the last thing in the buffer is a newline, remove it. +-----------------------------------------------------------------------------*/ + if (bufferP->length >= 1 && bufferP->data[bufferP->length-1] == '\n') { + /* Drop finishing newline character */ + --bufferP->length; + } +} + + + +static void +addImpostorReplacementSeq(Buffer * const bufferP, + const char * const seqContents) { +/*---------------------------------------------------------------------------- + Add to buffer *bufferP something that looks like a replacement sequence but + doesn't have the proper contents (the stuff between the parentheses) to be + one. For example, + + "#(fread x)" + + seqContents[] is the contents, NUL-terminated. +-----------------------------------------------------------------------------*/ + const char * p; + + Buffer_add(bufferP, escape); + Buffer_add(bufferP, '('); + + for (p = &seqContents[0]; *p; ++p) + Buffer_add(bufferP, *p); + + Buffer_add(bufferP, ')'); +} + + + +static void +readSkeletonFile(const char * const filename, + unsigned int const maxskl, + const char ** const errorP, + unsigned int * const nSkeletonP, + SkeletonObject ** const skeletonPList) { +/*---------------------------------------------------------------------------- +-----------------------------------------------------------------------------*/ + FILE * sklfileP; + SkeletonBuffer skeletonBuffer; + /* A buffer for accumulating skeleton objects */ + Buffer buffer; + /* A buffer for accumulating binary (literal; unsubstituted) data, on + its way to becoming a binary skeleton object. + */ + bool eof; + const char * error; + + SkeletonBuffer_init(&skeletonBuffer, maxskl, skeletonPList); + + Buffer_init(&buffer, &skeletonBuffer); + + sklfileP = pm_openr(filename); + + for (eof = false, error = NULL; !eof && !error; ) { + + int rc; + + rc = getc(sklfileP); + + if (rc == EOF) + eof = true; + else { + char const chr = rc; + + if (chr != escape) { + /* Not a replacement sequence; just a literal character */ + Buffer_add(&buffer, chr); + } else { + int rc; + rc = getc(sklfileP); + if (rc == EOF) { + /* Not a replacement sequence, just an escape caharacter + at the end of the file. + */ + Buffer_add(&buffer, escape); + eof = true; + } else { + char const chr = rc; + + if (chr != '(') { + /* Not a replacement sequence, just a lone escape + character + */ + Buffer_add(&buffer, escape); + Buffer_add(&buffer, chr); + } else { + char objstr[MAX_OBJ_BUF]; + bool unclosed; + readThroughCloseParen(sklfileP, + objstr, sizeof(objstr), + &unclosed); + if (unclosed) + pm_asprintf(&error, "Unclosed parentheses " + "in #() escape sequence"); + else { + SkeletonObject * const skeletonP = + newSkeletonFromReplString(objstr); + + if (skeletonP) { + Buffer_flush(&buffer); + SkeletonBuffer_add(&skeletonBuffer, skeletonP); + } else + addImpostorReplacementSeq(&buffer, objstr); + } + } + } + } } - } /* EOF of skeleton file */ + } - if (slen >= 1 && line[slen-1] == '\n') - /* Drop finishing newline character */ - --slen; + if (!error) { + Buffer_dropFinalNewline(&buffer); + Buffer_flush(&buffer); + } + *errorP = error; + *nSkeletonP = skeletonBuffer.nSkeleton; - SAVE_BIN(slen, line); /* Save whatever is left */ + fclose(sklfileP); +} - *nsklP = nskl; - fclose(sklfile); - return 0; + +static void +convertIt(FILE * const ifP, + FILE * const ofP, + SkeletonObject ** const bodySkeletonPList, + unsigned int const bodyNskl, + SkeletonObject ** const headSkeletonPList, + unsigned int const headNskl, + SkeletonObject ** const tailSkeletonPList, + unsigned int const tailNskl) { + + pixel * pixelrow; + pixval maxval; + double dmaxval; + int rows, cols; + int format; + unsigned int row; + + ppm_readppminit(ifP, &cols, &rows, &maxval, &format); + + pixelrow = ppm_allocrow(cols); + + dmaxval = (double)maxval; + + /* Write header */ + writeText(ofP, headNskl, headSkeletonPList, + cols, rows , 0, 0, 0.0, 0.0, 0.0); + + /* Write raster */ + for (row = 0; row < rows; ++row) { + unsigned int col; + + ppm_readppmrow(ifP, pixelrow, cols, maxval, format); + + for (col = 0; col < cols; ++col) { + pixel const thisPixel = pixelrow[col]; + + writeText(ofP, bodyNskl, bodySkeletonPList, + cols, rows, col, row, + PPM_GETR(thisPixel)/dmaxval, + PPM_GETG(thisPixel)/dmaxval, + PPM_GETB(thisPixel)/dmaxval); + } + } + + /* Write trailer */ + writeText(ofP, tailNskl, tailSkeletonPList, + cols, rows, 0, 0, 0.0, 0.0, 0.0); } -int main( argc, argv ) -int argc; -char* argv[]; - -{register int col; - register pixel* xP; - pixel* pixelrow; - pixval maxval,red,green,blue; - double dmaxval; - int argn, rows, cols, format, row; - unsigned int head_nskl,body_nskl,tail_nskl; - SKL_OBJ *head_skl[MAX_SKL_HEAD_OBJ]; - SKL_OBJ *body_skl[MAX_SKL_BODY_OBJ]; - SKL_OBJ *tail_skl[MAX_SKL_TAIL_OBJ]; - FILE *ifp; - const char *usage = "bodyskl [ -hd headskl ] [ -tl tailskl ] [pnmfile]"; - - ppm_init( &argc, argv ); - - argn = 1; - if (argn == argc) - pm_usage( usage ); - /* Read body skeleton file */ - if (read_skeleton (argv[argn],sizeof (body_skl)/sizeof (SKL_OBJ *), - &body_nskl,body_skl) < 0) - pm_usage ( usage ); - ++argn; - - head_nskl = tail_nskl = 0; - - while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') - { - if ( pm_keymatch ( argv[argn], "-hd", 1) && argn+1 < argc ) - { - argn++; /* Read header skeleton */ - if (read_skeleton (argv[argn],sizeof (head_skl)/sizeof (SKL_OBJ *), - &head_nskl,head_skl) < 0) - pm_usage ( usage ); - } - else if ( pm_keymatch ( argv[argn], "-tl", 1) && argn+1 < argc ) - { - argn++; /* Read tail skeleton */ - if (read_skeleton (argv[argn],sizeof (tail_skl)/sizeof (SKL_OBJ *), - &tail_nskl,tail_skl) < 0) - pm_usage ( usage ); - } - else - { - pm_usage ( usage ); - } - argn++; - } - - if ( argn != argc ) - { - ifp = pm_openr( argv[argn] ); - ++argn; - } - else - { - ifp = stdin; - } - - if ( argn != argc ) - pm_usage( usage ); - - ppm_readppminit( ifp, &cols, &rows, &maxval, &format ); - pixelrow = ppm_allocrow( cols ); - dmaxval = (double)maxval; - - if (head_nskl > 0) /* Write header */ - write_txt (stdout,head_nskl,head_skl,cols,rows,0,0,0.0,0.0,0.0); - - for ( row = 0; row < rows; ++row ) - { - ppm_readppmrow( ifp, pixelrow, cols, maxval, format ); - - for ( col = 0, xP = pixelrow; col < cols; ++col, ++xP ) - { - red = PPM_GETR( *xP ); - green = PPM_GETG( *xP ); - blue = PPM_GETB( *xP ); - write_txt (stdout,body_nskl,body_skl,cols,rows,col,row, - red/dmaxval,green/dmaxval,blue/dmaxval); - } - } - - if (tail_nskl > 0) /* Write trailer */ - write_txt (stdout,tail_nskl,tail_skl,cols,rows,0,0,0.0,0.0,0.0); - - pm_close( ifp ); - - exit( 0 ); +int +main(int argc, + const char ** argv) { + + struct CmdlineInfo cmdline; + + unsigned int headNskl, bodyNskl, tailNskl; + SkeletonObject * headSkeletonPList[MAX_SKL_HEAD_OBJ]; + SkeletonObject * bodySkeletonPList[MAX_SKL_BODY_OBJ]; + SkeletonObject * tailSkeletonPList[MAX_SKL_TAIL_OBJ]; + FILE * ifP; + const char * error; + + pm_proginit(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + ifP = pm_openr(cmdline.inputFileName); + + readSkeletonFile(cmdline.bodySklFileName, ARRAY_SIZE(bodySkeletonPList), + &error, &bodyNskl, bodySkeletonPList); + if (error) + pm_error("Invalid body skeleton file '%s'. %s", + cmdline.bodySklFileName, error); + + if (cmdline.hd) { + readSkeletonFile(cmdline.hd, ARRAY_SIZE(headSkeletonPList), + &error, &headNskl, headSkeletonPList); + if (error) + pm_error("Invalid head skeleton file '%s'. %s", + cmdline.hd, error); + } else + headNskl = 0; + + if (cmdline.tl) { + readSkeletonFile(cmdline.tl, ARRAY_SIZE(tailSkeletonPList), + &error, &tailNskl, tailSkeletonPList); + if (error) + pm_error("Invalid tail skeleton file '%s'. %s", + cmdline.tl, error); + } else + tailNskl = 0; + + if (cmdline.debug) + dumpAllSkeleton(bodySkeletonPList, bodyNskl, + headSkeletonPList, headNskl, + tailSkeletonPList, tailNskl); + + convertIt(ifP, stdout, + bodySkeletonPList, bodyNskl, + headSkeletonPList, headNskl, + tailSkeletonPList, tailNskl); + + pm_close(ifP); + + return 0; } + + diff --git a/converter/ppm/ppmtoascii.c b/converter/ppm/ppmtoascii.c new file mode 100644 index 00000000..6b0b04d7 --- /dev/null +++ b/converter/ppm/ppmtoascii.c @@ -0,0 +1,236 @@ +/*============================================================================= + ppmtoascii +=============================================================================== + + Convert a PPM image to ASCII with ANSI color graphics terminal controls + + Based on pbmtoascii. + Copyright (C) 1988, 1992 by Jef Poskanzer. + Copyright (C) 2010 by Frank Ch. Eigler. + + Permission to use, copy, modify, and distribute this software and its + documentation for any purpose and without fee is hereby granted, provided + that the above copyright notice appear in all copies and that both that + copyright notice and this permission notice appear in supporting + documentation. This software is provided "as is" without express or + implied warranty. +=============================================================================*/ + +#include "pm_c_util.h" +#include "mallocvar.h" +#include "shhopt.h" +#include "ppm.h" +#include "pm_gamma.h" + +/* We use the same algorithm for converting many pixels into a character + as Pbmtoascii. See pbmtoascii.c for a full explanation. +*/ + + +#define SQQ '\'' +#define BSQ '\\' + +/* Bit-map for 1x2 mode: +** 1 +** 2 +*/ +static char const carr1x2[4] = { +/* 0 1 2 3 */ + ' ', '"', 'o', 'M' }; + +/* Bit-map for 2x4 mode (hex): +** 1 2 +** 4 8 +** 10 20 +** 40 80 +** The idea here is first to preserve geometry, then to show density. +*/ +#define D08 'M' +#define D07 'H' +#define D06 '&' +#define D05 '$' +#define D04 '?' +static char const carr2x4[256] = { +/*0 1 2 3 4 5 6 7 8 9 A B C D E F */ +' ',SQQ, '`','"', '-',SQQ, SQQ,SQQ, '-','`', '`','`', '-','^','^','"',/*00-0F*/ +'.',':', ':',':', '|','|', '/',D04, '/','>', '/','>', '~','+','/','*',/*10-1F*/ +'.',':', ':',':', BSQ,BSQ, '<','<', '|',BSQ, '|',D04, '~',BSQ,'+','*',/*20-2F*/ +'-',':', ':',':', '~',D04, '<','<', '~','>', D04,'>', '=','b','d','#',/*30-3F*/ +'.',':', ':',':', ':','!', '/',D04, ':',':', '/',D04, ':',D04,D04,'P',/*40-4F*/ +',','i', '/',D04, '|','|', '|','T', '/',D04, '/','7', 'r','}','/','P',/*50-5F*/ +',',':', ';',D04, '>',D04, 'S','S', '/',')', '|','7', '>',D05,D05,D06,/*60-6F*/ +'v',D04, D04,D05, '+','}', D05,'F', '/',D05, '/',D06, 'p','D',D06,D07,/*70-7F*/ +'.',':', ':',':', ':',BSQ, ':',D04, ':',BSQ, '!',D04, ':',D04,D04,D05,/*80-8F*/ +BSQ,BSQ, ':',D04, BSQ,'|', '(',D05, '<','%', D04,'Z', '<',D05,D05,D06,/*90-9F*/ +',',BSQ, 'i',D04, BSQ,BSQ, D04,BSQ, '|','|', '|','T', D04,BSQ,'4','9',/*A0-AF*/ +'v',D04, D04,D05, BSQ,BSQ, D05,D06, '+',D05, '{',D06, 'q',D06,D06,D07,/*B0-BF*/ +'_',':', ':',D04, ':',D04, D04,D05, ':',D04, D04,D05, ':',D05,D05,D06,/*C0-CF*/ +BSQ,D04, D04,D05, D04,'L', D05,'[', '<','Z', '/','Z', 'c','k',D06,'R',/*D0-DF*/ +',',D04, D04,D05, '>',BSQ, 'S','S', D04,D05, 'J',']', '>',D06,'1','9',/*E0-EF*/ +'o','b', 'd',D06, 'b','b', D06,'6', 'd',D06, 'd',D07, '#',D07,D07,D08 /*F0-FF*/ +}; + + + +static const char* rgb2x2x2fg[2][2][2] = { + {{"\x1b[30m", /* 000 black */ + "\x1b[34m"}, /* 001 blue */ + {"\x1b[32m", /* 010 green */ + "\x1b[36m"}}, /* 011 cyan */ + {{"\x1b[31m", /* 100 red */ + "\x1b[35m"}, /* 101 magenta */ + {"\x1b[33m", /* 110 yellow */ + "\x1b[37m"}}, /* 111 white */ +}; + + + +struct cmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + const char * inputFileName; /* Name of input file */ + unsigned int cellWidth; + unsigned int cellHeight; + const char * carr; +}; + + + +static void +parseCommandLine(int argc, const char **argv, + struct cmdlineInfo * const cmdlineP) { + + optEntry * option_def; + /* Instructions to OptParseOptions3 on how to parse our options */ + optStruct3 opt; + + unsigned int option_def_index; + unsigned int dim1x2Spec, dim2x4Spec; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENTRY */ + OPTENT3(0, "1x2", OPT_FLAG, NULL, &dim1x2Spec, 0); + OPTENT3(0, "2x4", OPT_FLAG, NULL, &dim2x4Spec, 0); + + opt.opt_table = option_def; + opt.short_allowed = false; /* We have no short (old-fashioned) options */ + opt.allowNegNum = false; /* We have no parms that are negative numbers */ + + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + if (dim1x2Spec && dim2x4Spec) + pm_error("You cannot specify both -1x2 and -2x4"); + else if (dim2x4Spec) { + cmdlineP->cellWidth = 2; + cmdlineP->cellHeight = 4; + cmdlineP->carr = carr2x4; + } else { + cmdlineP->cellWidth = 1; + cmdlineP->cellHeight = 2; + cmdlineP->carr = carr1x2; + } + + if (argc-1 < 1) + cmdlineP->inputFileName = "-"; + else { + cmdlineP->inputFileName = argv[1]; + + if (argc-1 > 1) + pm_error("Too many arguments: %u. The only possible argument " + "is the input file name", argc-1); + } +} + + + +static void +ppmtoascii(pixel * const * const pixels, + unsigned int const cols, + unsigned int const rows, + pixval const maxval, + struct cmdlineInfo const cmdline, + FILE * const ofP) { + + unsigned int const cellHeight = cmdline.cellHeight; + unsigned int const cellWidth = cmdline.cellWidth; + const char * const carr = cmdline.carr; + unsigned int row; + + fprintf(ofP, "\x1b[0m"); /* Clear initial ansi attributes */ + /* TODO: set background to black */ + + for (row = 0; row < rows; row += cellHeight) { + unsigned int col; + for (col = 0; col < cols; col += cellWidth) { + unsigned int const sumthresh = cellWidth * cellHeight * 1.0 / 2; + + float sumr, sumg, sumb; + /* sum of intensity within cell so far, by component */ + unsigned int b; + const char * colorstr; + unsigned int subrow; + + sumr = sumg = sumb = 0; /* initial value */ + b = 0; /* initial value */ + + for (subrow = 0; subrow < cellHeight; ++subrow) { + unsigned int subcol; + for (subcol = 0; subcol < cellWidth; ++subcol) { + pixel color; + pixval value; + + if (row + subrow < rows && col + subcol < cols) + color = pixels[row + subrow][col + subcol]; + else + color = ppm_whitepixel (maxval); + + sumr += pm_ungamma709((float)PPM_GETR(color)/maxval); + sumg += pm_ungamma709((float)PPM_GETG(color)/maxval); + sumb += pm_ungamma709((float)PPM_GETB(color)/maxval); + + value = ppm_colorvalue(color); + b <<= 1; + if (value > maxval/2) + b |= 1; + } + } + colorstr = rgb2x2x2fg + [sumr >= sumthresh] + [sumg >= sumthresh] + [sumb >= sumthresh]; + fprintf(ofP, "%s%c", colorstr, carr[b]); + } + fprintf(ofP, "\n"); + } + fprintf(ofP, "\x1b[0m"); /* Clear final ansi attributes */ +} + + + +int +main(int argc, const char ** argv) { + + struct cmdlineInfo cmdline; + FILE * ifP; + + pixval maxval; + pixel ** pixels; + int rows, cols; + + pm_proginit(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + ifP = pm_openr(cmdline.inputFileName); + + pixels = ppm_readppm(ifP, &cols, &rows, &maxval); + + pm_close(ifP); + + ppmtoascii(pixels, cols, rows, maxval, cmdline, stdout); + + return 0; +} diff --git a/converter/ppm/ppmtobmp.c b/converter/ppm/ppmtobmp.c index c295f70c..6d65d744 100644 --- a/converter/ppm/ppmtobmp.c +++ b/converter/ppm/ppmtobmp.c @@ -20,6 +20,7 @@ #include #include "pm_c_util.h" +#include "nstring.h" #include "mallocvar.h" #include "shhopt.h" #include "bmp.h" @@ -63,11 +64,11 @@ freeColorMap(const colorMap * const colorMapP) { -struct cmdlineInfo { +struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ - char *input_filename; + const char * inputFilename; int class; /* C_WIN or C_OS2 */ unsigned int bppSpec; unsigned int bpp; @@ -77,7 +78,7 @@ struct cmdlineInfo { static void parseCommandLine(int argc, const char ** argv, - struct cmdlineInfo * const cmdlineP) { + struct CmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- Note that many of the strings that this function returns in the *cmdline_p structure are actually in the supplied argv array. And @@ -107,7 +108,7 @@ parseCommandLine(int argc, const char ** argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); if (windowsSpec && os2Spec) pm_error("Can't specify both -windows and -os2 options."); @@ -131,13 +132,22 @@ parseCommandLine(int argc, const char ** argv, cmdlineP->mapfile = NULL; if (argc - 1 == 0) - cmdlineP->input_filename = strdup("-"); /* he wants stdin */ + cmdlineP->inputFilename = pm_strdup("-"); /* he wants stdin */ else if (argc - 1 == 1) - cmdlineP->input_filename = strdup(argv[1]); + cmdlineP->inputFilename = pm_strdup(argv[1]); else pm_error("Too many arguments. The only argument accepted " "is the input file specificaton"); + free(option_def); +} + + + +static void +freeCommandLine(struct CmdlineInfo const cmdline) { + + pm_strfree(cmdline.inputFilename); } @@ -177,20 +187,18 @@ PutLong(FILE * const fp, long const v) { * BMP writing */ -static int +static unsigned int BMPwritefileheader(FILE * const fp, - int const class, - unsigned long const bitcount, - unsigned long const x, - unsigned long const y) { + unsigned int const cbSize, + unsigned int const offBits) { /*---------------------------------------------------------------------------- - Return the number of bytes written, or -1 on error. + Return the number of bytes written. -----------------------------------------------------------------------------*/ PutByte(fp, 'B'); PutByte(fp, 'M'); /* cbSize */ - PutLong(fp, BMPlenfile(class, bitcount, -1, x, y)); + PutLong(fp, cbSize); /* xHotSpot */ PutShort(fp, 0); @@ -199,7 +207,7 @@ BMPwritefileheader(FILE * const fp, PutShort(fp, 0); /* offBits */ - PutLong(fp, BMPoffbits(class, bitcount, -1)); + PutLong(fp, offBits); return 14; } @@ -213,9 +221,9 @@ BMPwriteinfoheader(FILE * const fp, unsigned long const x, unsigned long const y) { /*---------------------------------------------------------------------------- - Return the number of bytes written, or -1 on error. + Return the number of bytes written. ----------------------------------------------------------------------------*/ - long cbFix; + unsigned int cbFix; switch (class) { case C_WIN: { @@ -266,7 +274,7 @@ BMPwriteRgb(FILE * const fp, pixval const G, pixval const B) { /*---------------------------------------------------------------------------- - Return the number of bytes written, or -1 on error. + Return the number of bytes written. -----------------------------------------------------------------------------*/ switch (class) { case C_WIN: @@ -282,8 +290,8 @@ BMPwriteRgb(FILE * const fp, return 3; default: pm_error(er_internal, "BMPwriteRgb"); + return -1; /* avoid compiler warning. */ } - return -1; } @@ -294,7 +302,7 @@ BMPwriteColormap(FILE * const ifP, int const bpp, const colorMap * const colorMapP) { /*---------------------------------------------------------------------------- - Return the number of bytes written, or -1 on error. + Return the number of bytes written. -----------------------------------------------------------------------------*/ unsigned int const ncolors = (1 << bpp); @@ -445,7 +453,7 @@ BMPwritebits(FILE * const fp, pixval const maxval, colorhash_table const cht) { /*---------------------------------------------------------------------------- - Return the number of bytes written, or -1 on error. + Return the number of bytes written. -----------------------------------------------------------------------------*/ unsigned int nbyte; int row; @@ -490,6 +498,9 @@ bmpEncode(FILE * const ifP, /*---------------------------------------------------------------------------- Write a BMP file of the given class. -----------------------------------------------------------------------------*/ + unsigned int const cbSize = BMPlenfile(class, bpp, 0, x, y); + unsigned int const offbits = BMPoffbits(class, bpp, 0); + unsigned long nbyte; if (colortype == PALETTE) @@ -498,19 +509,17 @@ bmpEncode(FILE * const ifP, pm_message("Writing %u bits per pixel truecolor (no palette)", bpp); nbyte = 0; /* initial value */ - nbyte += BMPwritefileheader(ifP, class, bpp, x, y); + nbyte += BMPwritefileheader(ifP, cbSize, offbits); nbyte += BMPwriteinfoheader(ifP, class, bpp, x, y); if (colortype == PALETTE) nbyte += BMPwriteColormap(ifP, class, bpp, colorMapP); - if (nbyte != (BMPlenfileheader(class) - + BMPleninfoheader(class) - + BMPlencolormap(class, bpp, 0))) + if (nbyte != offbits) pm_error(er_internal, "BmpEncode 1"); nbyte += BMPwritebits(ifP, x, y, colortype, bpp, pixels, maxval, colorMapP->cht); - if (nbyte != BMPlenfile(class, bpp, -1, x, y)) + if (nbyte != cbSize) pm_error(er_internal, "BmpEncode 2"); } @@ -544,6 +553,8 @@ bmpEncodePbm(FILE * const ifP, Only PBM input uses this routine. Color images represented by 1 bpp via color palette use the general bmpEncode(). */ + unsigned int const cbSize = BMPlenfile(class, 1, 0, cols, rows); + unsigned int const offbits = BMPoffbits(class, 1, 0); unsigned int const adjustedCols = (cols + 31) / 32 * 32; unsigned int const packedBytes = adjustedCols / 8; @@ -555,18 +566,16 @@ bmpEncodePbm(FILE * const ifP, pm_message("Writing 1 bit per pixel with a black-white palette"); nbyte = 0; /* initial value */ - nbyte += BMPwritefileheader(ifP, class, 1, cols, rows); + nbyte += BMPwritefileheader(ifP, cbSize, offbits); nbyte += BMPwriteinfoheader(ifP, class, 1, cols, rows); makeBilevelColorMap(&bilevelColorMap); nbyte += BMPwriteColormap(ifP, class, 1, &bilevelColorMap); - if (nbyte != (BMPlenfileheader(class) - + BMPleninfoheader(class) - + BMPlencolormap(class, 1, 0))) - pm_error(er_internal, "bmpEncodePBM 1"); - + if (nbyte != offbits) + pm_error(er_internal, "bmpEncodePbm 1"); + for (row = 0; row < rows; ++row){ size_t bytesWritten; @@ -581,7 +590,7 @@ bmpEncodePbm(FILE * const ifP, nbyte += bytesWritten; } - if (nbyte != BMPlenfile(class, 1, -1, cols, rows)) + if (nbyte != cbSize) pm_error(er_internal, "bmpEncodePbm 2"); } @@ -822,7 +831,6 @@ doPbm(FILE * const ifP, 32 bit borders and that in BMP the bottom row comes first in order. */ - int const CHARBITS = (sizeof(unsigned char)*8); int const colChars = pbm_packed_bytes(cols); int const adjustedCols = (cols+31) /32 * 32; int const packedBytes = adjustedCols /8; @@ -854,11 +862,8 @@ doPbm(FILE * const ifP, some BMP viewers may get confused with that. */ - if (cols % 8 >0) { - /* adjust final partial byte */ - thisRow[colChars-1] >>= CHARBITS - cols % CHARBITS; - thisRow[colChars-1] <<= CHARBITS - cols % CHARBITS; - } + /* Clean off remainder of fractional last character */ + pbm_cleanrowend_packed(thisRow, cols); } bmpEncodePbm(ofP, class, cols, rows, bitrow); @@ -908,6 +913,8 @@ doPgmPpm(FILE * const ifP, cols, rows, (const pixel**)pixels, maxval, &colorMap); freeColorMap(&colorMap); + + ppm_freearray(pixels, rows); } @@ -916,7 +923,7 @@ int main(int argc, const char ** argv) { - struct cmdlineInfo cmdline; + struct CmdlineInfo cmdline; FILE * ifP; int rows; int cols; @@ -927,7 +934,7 @@ main(int argc, parseCommandLine(argc, argv, &cmdline); - ifP = pm_openr(cmdline.input_filename); + ifP = pm_openr(cmdline.inputFilename); ppm_readppminit(ifP, &cols, &rows, &maxval, &ppmFormat); @@ -938,6 +945,8 @@ main(int argc, cmdline.class, cmdline.bppSpec, cmdline.bpp, cmdline.mapfile, stdout); + freeCommandLine(cmdline); + pm_close(ifP); pm_close(stdout); diff --git a/converter/ppm/ppmtogif.c b/converter/ppm/ppmtogif.c index 93feaa95..fa7d1dbe 100644 --- a/converter/ppm/ppmtogif.c +++ b/converter/ppm/ppmtogif.c @@ -68,7 +68,7 @@ handleLatex2htmlHack(void) { This program used to put out a "usage" message when it saw an option it didn't understand. Latex2html's configure program does a ppmtogif -h (-h was never a valid option) to elicit that message and - then parses the message to see if it included the strings + then parses the message to see if it includes the strings "-interlace" and "-transparent". That way it knows if the 'ppmtogif' program it found has those options or not. I don't think any 'ppmtogif' you're likely to find today lacks those options, but @@ -91,7 +91,7 @@ handleLatex2htmlHack(void) { static void -parseCommandLine(int argc, char ** argv, +parseCommandLine(int argc, const char ** argv, struct cmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- Parse the program arguments (given by argc and argv) into a form @@ -146,7 +146,7 @@ parseCommandLine(int argc, char ** argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (latex2htmlhack) @@ -183,8 +183,8 @@ openPnmremapStream(const char * const inputFileName, assert(inputFileName != NULL); assert(mapFileName != NULL); - asprintfN(&pnmremapCommand, "pnmremap -mapfile='%s' %s", - mapFileName, inputFileName); + pm_asprintf(&pnmremapCommand, "pnmremap -mapfile='%s' %s", + mapFileName, inputFileName); if (verbose) pm_message("Preprocessing Pamtogif input with shell command '%s'", @@ -198,7 +198,7 @@ openPnmremapStream(const char * const inputFileName, else *pnmremapPipeP = pnmremapPipe; - strfree(pnmremapCommand); + pm_strfree(pnmremapCommand); } @@ -221,39 +221,39 @@ pamtogifCommand(const char * const arg0, struct stat statbuf; - asprintfN(&progName, "%s/%s", arg0DirName, pamtogifName); + pm_asprintf(&progName, "%s/%s", arg0DirName, pamtogifName); if (stat(progName, &statbuf) == 0) commandVerb = progName; else commandVerb = strdup(pamtogifName); - strfree(arg0DirName); + pm_strfree(arg0DirName); } else commandVerb = strdup(pamtogifName); if (cmdline.transparent) - asprintfN(&transparentOpt, "-transparent=%s", cmdline.transparent); + pm_asprintf(&transparentOpt, "-transparent=%s", cmdline.transparent); else transparentOpt = strdup(""); if (cmdline.comment) - asprintfN(&commentOpt, "-comment=%s", cmdline.comment); + pm_asprintf(&commentOpt, "-comment=%s", cmdline.comment); else commentOpt = strdup(""); - asprintfN(&retval, "%s - -alphacolor=%s %s %s %s %s %s %s", - commandVerb, - cmdline.alphacolor, - cmdline.interlace ? "-interlace" : "", - cmdline.sort ? "-sort" : "", - transparentOpt, - commentOpt, - cmdline.nolzw ? "-nolzw" : "", - cmdline.verbose ? "-verbose" : ""); + pm_asprintf(&retval, "%s - -alphacolor=%s %s %s %s %s %s %s", + commandVerb, + cmdline.alphacolor, + cmdline.interlace ? "-interlace" : "", + cmdline.sort ? "-sort" : "", + transparentOpt, + commentOpt, + cmdline.nolzw ? "-nolzw" : "", + cmdline.verbose ? "-verbose" : ""); - strfree(transparentOpt); - strfree(commentOpt); + pm_strfree(transparentOpt); + pm_strfree(commentOpt); return retval; } @@ -374,8 +374,8 @@ feedPamtogif(struct pam * const inPamP, int -main(int argc, - char * argv[]) { +main(int argc, + const char ** argv) { struct cmdlineInfo cmdline; FILE * ifP; @@ -384,7 +384,7 @@ main(int argc, FILE * pipeToPamtogif; int rc; - pnm_init(&argc, argv); + pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); @@ -413,7 +413,7 @@ main(int argc, if (rc != 0) pm_error("Pamtogif process failed. pclose() failed."); - strfree(command); + pm_strfree(command); pm_close(ifP); pm_close(stdout); diff --git a/converter/ppm/ppmtoicr.c b/converter/ppm/ppmtoicr.c index feca0c18..3c8be421 100644 --- a/converter/ppm/ppmtoicr.c +++ b/converter/ppm/ppmtoicr.c @@ -10,311 +10,255 @@ ** implied warranty. */ +#include +#include #include "ppm.h" -#define MAXCOLORS 256 -#define CLUTCOLORS 768 +#define MAXCOLORCT 256 +#define CLUTCOLORCT 768 -static int colorstobpp ARGS(( int colors )); -static int GetPixel ARGS(( int x, int y )); -static int rleit ARGS(( char* buf, char* bufto, int len )); -static pixel** pixels; -static colorhash_table cht; -static char* testimage; -int -main(argc, argv) -int argc; -char* argv[]; -{ - FILE* ifp; - int argn, rows, cols, colors, i, j, BitsPerPixel, newxsize; - pixval maxval; - colorhist_vector chv; - char rgb[CLUTCOLORS]; - const char* windowname; - char* thischar; - char* thisline; - char* space; - register unsigned char c; - register char* p; - int display, expand; - int rleflag, winflag; - const char* const usage = "[-windowname windowname] [-expand expand] [-display display] [-rle] [ppmfile]"; - - - ppm_init( &argc, argv ); - - argn = 1; - windowname = "untitled"; - winflag = 0; - expand = 1; - display = 0; - rleflag = 0; - - while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) - { - if ( pm_keymatch(argv[argn],"-windowname",2) && argn + 1 < argc ) - { - ++argn; - windowname = argv[argn]; - winflag = 1; - } - else if ( pm_keymatch(argv[argn],"-expand",2) && argn + 1 < argc ) - { - ++argn; - if ( sscanf( argv[argn], "%d",&expand ) != 1 ) - pm_usage( usage ); - } - else if ( pm_keymatch(argv[argn],"-display",2) && argn + 1 < argc ) - { - ++argn; - if ( sscanf( argv[argn], "%d",&display ) != 1 ) - pm_usage( usage ); - } - else if ( pm_keymatch(argv[argn],"-rle",2) ) - rleflag = 1; - else if ( pm_keymatch(argv[argn],"-norle",2) ) - rleflag = 0; - else - pm_usage( usage ); - } - - if ( argn < argc ) - { - ifp = pm_openr( argv[argn] ); - if ( ! winflag ) - windowname = argv[argn]; - ++argn; - } - else - ifp = stdin; - - if ( argn != argc ) - pm_usage( usage ); - - pixels = ppm_readppm( ifp, &cols, &rows, &maxval ); - - pm_close( ifp ); - - for (i = 0; i < CLUTCOLORS; i++) - rgb[i] = 0; - - /* Figure out the colormap. */ - pm_message("computing colormap..." ); - chv = ppm_computecolorhist(pixels, cols, rows, MAXCOLORS, &colors); - if (chv == (colorhist_vector) 0) - pm_error( "too many colors - try doing a 'pnmquant %d'", MAXCOLORS ); - pm_message("%d colors found", colors ); - - /* Turn the ppm colormap into an ICR colormap. */ - if (maxval > 255) - pm_message( - "maxval is not 255 - automatically rescaling colors" ); - for (i = 0; i < colors; i++) - { - j = (3 * i); - if (maxval == 255) - { - rgb[j] = PPM_GETR(chv[i].color) ; - j++; - rgb[j] = PPM_GETG(chv[i].color) ; - j++; - rgb[j] = PPM_GETB(chv[i].color) ; - } - else - { - rgb[j] = (int) PPM_GETR(chv[i].color) * 255 / maxval; - j++; - rgb[j] = (int) PPM_GETG(chv[i].color) * 255 / maxval; - j++; - rgb[j] = (int) PPM_GETB(chv[i].color) * 255 / maxval; - } - } - BitsPerPixel = colorstobpp(colors); - - /* And make a hash table for fast lookup. */ - cht = ppm_colorhisttocolorhash(chv, colors); - ppm_freecolorhist(chv); - - - /************** Create a new window using ICR protocol *********/ - /* Format is "ESC^W;left;top;width;height;display;windowname" */ - - pm_message("creating window %s ...", windowname ); - (void)printf("\033^W;%d;%d;%d;%d;%d;%s^",0,0,cols*expand,rows*expand,display,windowname); - fflush(stdout); - - - /****************** Download the colormap. ********************/ - pm_message("downloading colormap for %s ...", windowname ); - - (void)printf("\033^M;%d;%d;%d;%s^",0,MAXCOLORS,CLUTCOLORS,windowname); - thischar = rgb; - for (j=0; j 31 && c < 123 ) { /* printable ASCII */ - putchar(c); - } - else { - putchar((c>>6)+123); /* non-printable, so encode it */ - putchar((c & 0x3f) + 32); - } - } - fflush(stdout); - - /**************** send out picture *************************/ - /* Protocol's RLE scheme is quicker but buggy */ - - if (rleflag) { - pm_message("sending run-length encoded picture data ..." ); - testimage = (char*) malloc(rows*cols); - p = testimage; - for (i=0; i31 && c <123) { - putchar(c); - } - else { - putchar((c>>6) + 123); - putchar((c & 0x3f) + 32); - } - } - fflush(stdout); - } - free(space); - exit(0); - } - - /* Otherwise, send out uncompressed pixel data via the slow method */ - - else { - pm_message("sending picture data ..." ); - for (i = 0; i < rows; i++) { - (void)printf("\033^P;%d;%d;%d;%d;%s^",0,i*expand,expand,cols,windowname); - for (j = 0; j < cols; j++) { - c = GetPixel(j,i); - if (c > 31 && c < 123) { - putchar(c); - } - else { - putchar((c>>6)+123); - putchar((c & 0x3f) + 32); - } - } - } - fflush(stdout); - exit(0); - } - } +static void +makeIcrColormap(colorhist_vector const chv, + unsigned int const colorCt, + pixval const maxval, + char * const rgb) { + + unsigned int i; + + if (maxval > 255) + pm_message("Maxval is not 255 - automatically rescaling colors" ); + + for (i = 0; i < CLUTCOLORCT; ++i) + rgb[i] = 0; + + for (i = 0; i < colorCt; ++i) { + unsigned int j; + + j = (3 * i); + + if (maxval == 255) { + rgb[j++] = PPM_GETR(chv[i].color) ; + rgb[j++] = PPM_GETG(chv[i].color) ; + rgb[j++] = PPM_GETB(chv[i].color) ; + } else { + rgb[j++] = (unsigned int) PPM_GETR(chv[i].color) * 255 / maxval; + rgb[j++] = (unsigned int) PPM_GETG(chv[i].color) * 255 / maxval; + rgb[j++] = (unsigned int) PPM_GETB(chv[i].color) * 255 / maxval; + } + } +} + + static int -colorstobpp(colors) -int colors; - { - int bpp; - - if (colors <= 2) - bpp = 1; - else if (colors <= 4) - bpp = 2; - else if (colors <= 8) - bpp = 3; - else if (colors <= 16) - bpp = 4; - else if (colors <= 32) - bpp = 5; - else if (colors <= 64) - bpp = 6; - else if (colors <= 128) - bpp = 7; - else if (colors <= 256) - bpp = 8; - else - pm_error("can't happen" ); - return bpp; - } +bppFromColorCt(unsigned int const colorCt) { + + unsigned int bpp; + + if (colorCt <= 2) + bpp = 1; + else if (colorCt <= 4) + bpp = 2; + else if (colorCt <= 8) + bpp = 3; + else if (colorCt <= 16) + bpp = 4; + else if (colorCt <= 32) + bpp = 5; + else if (colorCt <= 64) + bpp = 6; + else if (colorCt <= 128) + bpp = 7; + else if (colorCt <= 256) + bpp = 8; + else + assert(false); + + return bpp; +} + + static int -GetPixel(x, y) -int x, y; - { - int color; +colorIndexAtPosition(unsigned int const x, + unsigned int const y, + pixel ** const pixels, + colorhash_table const cht) { - color = ppm_lookupcolor(cht, &pixels[y][x]); - return color; - } + int rc; + rc = ppm_lookupcolor(cht, &pixels[y][x]); -/* rleit compress with run length encoding as per NCSA's documentation */ + /* Every color in the image is in the palette */ + assert(rc >= 0); -static int -rleit(buf,bufto,len) - char* buf; - char* bufto; - int len; - { - register char* p; - register char* q; - register char* cfoll; - register char* clead; - char* begp; - int i; - - p = buf; - cfoll = bufto; - clead = cfoll + 1; - - begp = p; - while (len > 0 ) { /* encode until gone */ - - q = p + 1; - i = len-1; - while (*p == *q && i+120 > len && i) { - q++; - i--; - } - - if (q > p +2) { /* three in a row */ - if (p > begp) { - *cfoll = p - begp; - cfoll = clead; - } - *cfoll++ = 128 | (q-p); /*len of seq*/ - *cfoll++ = *p; /* char of seq */ - len -= q-p; /* subtract len of seq */ - p = q; - clead = cfoll+1; - begp = p; - } - else { - *clead++ = *p++; /* copy one char */ - len--; - if (p>begp + 120) { - *cfoll = p - begp; - cfoll = clead++; - begp = p; - } - } - } - -/* fillin last bytecount */ - - if (p>begp) - *cfoll = (p - begp); - else - clead--; - - return((int) (clead-bufto)); /*how many stored as encoded */ + return rc; } + + + +static void +downloadColormap(char const rgb[CLUTCOLORCT], + const char * const windowName) { + + unsigned int i; + + pm_message("Downloading colormap for %s ...", windowName); + + printf("\033^M;%d;%d;%d;%s^", + 0, MAXCOLORCT, CLUTCOLORCT, windowName); + + for (i = 0; i < CLUTCOLORCT; ++i) { + unsigned char const c = rgb[i]; + + if (c > 31 && c < 123) { + /* printable ASCII */ + putchar(c); + } else { + /* non-printable, so encode it */ + putchar((c >> 6) + 123); + putchar((c & 0x3f) + 32); + } + } + fflush(stdout); +} + + + +static void +sendOutPicture(pixel ** const pixels, + unsigned int const rows, + unsigned int const cols, + colorhash_table const cht, + int const expand, + const char * const windowName) { + + unsigned int row; + + pm_message("Sending picture data ..." ); + + for (row = 0; row < rows; ++row) { + unsigned int col; + printf("\033^P;%d;%d;%d;%d;%s^", + 0, row * expand, expand, cols, windowName); + for (col = 0; col < cols; ++col) { + unsigned char const c = + colorIndexAtPosition(col, row, pixels, cht); + if (c > 31 && c < 123) { + putchar(c); + } else { + putchar((c >> 6) + 123); + putchar((c & 0x3f) + 32); + } + } + } + fflush(stdout); +} + + + +int +main(int argc, const char ** const argv) { + + FILE * ifP; + int rows, cols; + int colorCt; + int argn; + unsigned int bitsPerPixel; + pixval maxval; + colorhist_vector chv; + char rgb[CLUTCOLORCT]; + const char * windowName; + int display, expand; + int winflag; + const char* const usage = "[-windowname windowname] [-expand expand] [-display display] [ppmfile]"; + pixel** pixels; + colorhash_table cht; + + pm_proginit(&argc, argv); + + argn = 1; + windowName = "untitled"; + winflag = 0; + expand = 1; + display = 0; + + while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) + { + if ( pm_keymatch(argv[argn],"-windowname",2) && argn + 1 < argc ) + { + ++argn; + windowName = argv[argn]; + winflag = 1; + } + else if ( pm_keymatch(argv[argn],"-expand",2) && argn + 1 < argc ) + { + ++argn; + if ( sscanf( argv[argn], "%d",&expand ) != 1 ) + pm_usage( usage ); + } + else if ( pm_keymatch(argv[argn],"-display",2) && argn + 1 < argc ) + { + ++argn; + if ( sscanf( argv[argn], "%d",&display ) != 1 ) + pm_usage( usage ); + } + else + pm_usage( usage ); + } + + if ( argn < argc ) + { + ifP = pm_openr( argv[argn] ); + if ( ! winflag ) + windowName = argv[argn]; + ++argn; + } + else + ifP = stdin; + + if ( argn != argc ) + pm_usage( usage ); + + pixels = ppm_readppm(ifP, &cols, &rows, &maxval); + + pm_close(ifP); + + /* Figure out the colormap. */ + pm_message("Computing colormap..." ); + chv = ppm_computecolorhist(pixels, cols, rows, MAXCOLORCT, &colorCt); + if (!chv) + pm_error("Too many colors - try doing a 'pnmquant %u'", MAXCOLORCT); + pm_message("%u colors found", colorCt ); + + makeIcrColormap(chv, colorCt, maxval, rgb); + + bitsPerPixel = bppFromColorCt(colorCt); + + /* And make a hash table for fast lookup. */ + cht = ppm_colorhisttocolorhash(chv, colorCt); + + ppm_freecolorhist(chv); + + /************** Create a new window using ICR protocol *********/ + /* Format is "ESC^W;left;top;width;height;display;windowname" */ + + pm_message("Creating window %s ...", windowName); + + printf("\033^W;%d;%d;%d;%d;%d;%s^", + 0, 0, cols * expand, rows * expand, display, windowName); + fflush(stdout); + + /****************** Download the colormap. ********************/ + + downloadColormap(rgb, windowName); + + sendOutPicture(pixels, rows, cols, cht, expand, windowName); + + return 0; +} + + + diff --git a/converter/ppm/ppmtoilbm.c b/converter/ppm/ppmtoilbm.c index d296f498..595aa3f4 100644 --- a/converter/ppm/ppmtoilbm.c +++ b/converter/ppm/ppmtoilbm.c @@ -38,8 +38,11 @@ ** - added IFF text chunks ** ** Feb 2010: afu -** Added dimension check to prevent short int from overflowing. -** +** - added dimension check to prevent short int from overflowing. +** +** June 2015: afu +** - moved byterun1 (or Packbits) compression to lib/util/runlenth.c +** - fixed bug with HAM -nocompress ** ** TODO: ** - multipalette capability (PCHG chunk) for std and HAM @@ -64,6 +67,7 @@ ** implied warranty. */ +#include #include #include "pm_c_util.h" @@ -71,6 +75,7 @@ #include "ppm.h" #include "ppmfloyd.h" #include "pbm.h" +#include "runlength.h" #include "ilbm.h" #include "lum.h" @@ -106,31 +111,6 @@ #define INT16MAX 32767 -static void put_big_short ARGS((short s)); -static void put_big_long ARGS((long l)); -#define put_byte(b) (void)(putc((unsigned char)(b), stdout)) -static void write_bytes ARGS((unsigned char *buffer, int bytes)); -static void ppm_to_ham ARGS((FILE *fp, int cols, int rows, int maxval, pixel *colormap, int colors, int cmapmaxval, int hamplanes)); -static void ppm_to_deep ARGS((FILE *fp, int cols, int rows, int maxval, int bitspercolor)); -static void ppm_to_dcol ARGS((FILE *fp, int cols, int rows, int maxval, DirectColor *dcol)); -static void ppm_to_rgb8 ARGS((FILE *fp, int cols, int rows, int maxval)); -static void ppm_to_rgbn ARGS((FILE *fp, int cols, int rows, int maxval)); -static void ppm_to_std ARGS((FILE *fp, int cols, int rows, int maxval, pixel *colormap, int colors, int cmapmaxval, int maxcolors, int nPlanes)); -static void ppm_to_cmap ARGS((pixel *colormap, int colors, int maxval)); -static void write_bmhd ARGS((int cols, int rows, int nPlanes)); -static void write_cmap ARGS((pixel *colormap, int colors, int maxval)); -static long encode_row ARGS((FILE *outfile, rawtype *rawrow, int cols, int nPlanes)); -static long encode_maskrow ARGS((FILE *outfile, rawtype *rawrow, int cols)); -static int compress_row ARGS((int bytes)); -static void store_bodyrow ARGS((unsigned char *row, int len)); -static int runbyte1 ARGS((int bytes)); -static pixel * next_pixrow ARGS((FILE *fp, int row)); -static int * make_val_table ARGS((int oldmaxval, int newmaxval)); -static void init_read ARGS((FILE *fp, int *colsP, int *rowsP, pixval *maxvalP, int *formatP, int readall)); -static void write_body_rows ARGS((void)); -static void write_camg ARGS((void)); -static int length_of_text_chunks ARGS((void)); -static void write_text_chunks ARGS((void)); #define PAD(n) (ODD(n) ? 1 : 0) /* pad to a word */ @@ -183,469 +163,720 @@ static short gen_camg = 0; /* write CAMG chunk */ #define WORSTCOMPR(bytes) ((bytes) + (bytes)/128 + 1) #define DO_COMPRESS (compmethod != cmpNone) +#define NEWDEPTH(pix, table) PPM_ASSIGN((pix), (table)[PPM_GETR(pix)], (table)[PPM_GETG(pix)], (table)[PPM_GETB(pix)]) -/***** parse options and figure out what kind of ILBM to write *****/ +#define putByte(b) (void)(putc((unsigned char)(b), stdout)) -static int get_int_val ARGS((char *string, char *option, int bot, int top)); -static int get_compr_method ARGS((char *string)); -static int get_mask_type ARGS((char *string)); -static int get_hammap_mode ARGS((char *string)); +/************ other utility functions ************/ -#define NEWDEPTH(pix, table) PPM_ASSIGN((pix), (table)[PPM_GETR(pix)], (table)[PPM_GETG(pix)], (table)[PPM_GETB(pix)]) static void -report_too_many_colors(int const ifmode, - int const maxplanes, - int const hamplanes, - DirectColor const dcol, - int const deepbits) { - - int const maxcolors = 1 << maxplanes; +writeBytes(unsigned char * const buffer, + int const bytes) { - switch( ifmode ) { - case MODE_HAM: - pm_message("too many colors for %d planes - " - "proceeding to write a HAM%d file", - maxplanes, hamplanes); - pm_message("if you want a non-HAM file, try doing a 'pnmquant %d'", - maxcolors); - break; - case MODE_DCOL: - pm_message("too many colors for %d planes - " - "proceeding to write a %d:%d:%d direct color ILBM", - maxplanes, dcol.r, dcol.g, dcol.b); - pm_message("if you want a non-direct color file, " - "try doing a 'pnmquant %d'", maxcolors); - break; - case MODE_DEEP: - pm_message("too many colors for %d planes - " - "proceeding to write a %d-bit \'deep\' ILBM", - maxplanes, deepbits*3); - pm_message("if you want a non-deep file, " - "try doing a 'pnmquant %d'", - maxcolors); - break; - default: - pm_error("too many colors for %d planes - " - "try doing a 'pnmquant %d'", - maxplanes, maxcolors); - break; - } + if( fwrite(buffer, 1, bytes, stdout) != bytes ) + pm_error("write error"); } -static int -get_int_val(string, option, bot, top) - char *string, *option; - int bot, top; -{ - int val; - - if( sscanf(string, "%d", &val) != 1 ) - pm_error("option \"%s\" needs integer argument", option); - if( val < bot || val > top ) - pm_error("option \"%s\" argument value out of range (%d..%d)", - option, bot, top); +static int * +makeValTable(int const oldmaxval, + int const newmaxval) { - return val; -} + unsigned int i; + int * table; + MALLOCARRAY_NOFAIL(table, oldmaxval + 1); + for (i = 0; i <= oldmaxval; ++i) + table[i] = ROUNDDIV(i * newmaxval, oldmaxval); -static int -get_compr_method(string) - char *string; -{ - int retval; - if( pm_keymatch(string, "none", 1) || pm_keymatch(string, "0", 1) ) - retval = cmpNone; - else if( pm_keymatch(string, "byterun1", 1) || - pm_keymatch(string, "1", 1) ) - retval = cmpByteRun1; - else - pm_error("unknown compression method: %s", string); - return retval; + return table; } -static int -get_mask_type(string) - char *string; -{ - int retval; - if( pm_keymatch(string, "none", 1) || pm_keymatch(string, "0", 1) ) - retval = mskNone; - else - if( pm_keymatch(string, "plane", 1) || - pm_keymatch(string, "maskplane", 1) || - pm_keymatch(string, "1", 1) ) - retval = mskHasMask; - else - if( pm_keymatch(string, "transparentcolor", 1) || - pm_keymatch(string, "2", 1) ) - retval = mskHasTransparentColor; - else - if( pm_keymatch(string, "lasso", 1) || pm_keymatch(string, "3", 1) ) - retval = mskLasso; - else - pm_error("unknown masking method: %s", string); - return retval; -} +static int gFormat; +static int gCols; +static int gMaxval; +static void +initRead(FILE * const fp, + int * const colsP, + int * const rowsP, + pixval * const maxvalP, + int * const formatP, + int const readall) { -static int -get_hammap_mode(string) - char *string; -{ - int retval; + ppm_readppminit(fp, colsP, rowsP, maxvalP, formatP); - if( pm_keymatch(string, "grey", 1) || pm_keymatch(string, "gray", 1) ) - retval = HAMMODE_GRAY; - else - if( pm_keymatch(string, "fixed", 1) ) - retval = HAMMODE_FIXED; - else - if( pm_keymatch(string, "rgb4", 4) ) - retval = HAMMODE_RGB4; - else - if( pm_keymatch(string, "rgb5", 4) ) - retval = HAMMODE_RGB5; - else - pm_error("unknown HAM colormap selection mode: %s", string); - return retval; -} + if( *rowsP >INT16MAX || *colsP >INT16MAX ) + pm_error ("Input image is too large."); + if( readall ) { + int row; -/************ colormap file ************/ + pixels = ppm_allocarray(*colsP, *rowsP); + for( row = 0; row < *rowsP; row++ ) + ppm_readppmrow(fp, pixels[row], *colsP, *maxvalP, *formatP); + /* pixels = ppm_readppm(fp, colsP, rowsP, maxvalP); */ + } + else { + pixrow = ppm_allocrow(*colsP); + } + gCols = *colsP; + gMaxval = *maxvalP; + gFormat = *formatP; +} -static void -ppm_to_cmap(colorrow, colors, maxval) - pixel *colorrow; - int colors; - int maxval; -{ - int formsize, cmapsize; - cmapsize = colors * 3; - formsize = - 4 + /* ILBM */ - 4 + 4 + BitMapHeaderSize + /* BMHD size header */ - 4 + 4 + cmapsize + PAD(cmapsize) + /* CMAP size colormap */ - length_of_text_chunks(); +static pixel * +nextPixrow(FILE * const fp, + int const row) { - put_big_long(ID_FORM); - put_big_long(formsize); - put_big_long(ID_ILBM); + if( pixels ) + pixrow = pixels[row]; + else { + ppm_readppmrow(fp, pixrow, gCols, gMaxval, gFormat); + } + if( maskrow ) { + int col; - write_bmhd(0, 0, 0); - write_text_chunks(); - write_cmap(colorrow, colors, maxval); + if( maskfile ) + pbm_readpbmrow(maskfile, maskrow, maskcols, maskformat); + else { + for( col = 0; col < gCols; col++ ) + maskrow[col] = PBM_BLACK; + } + if( transpColor ) { + for( col = 0; col < gCols; col++ ) + if( PPM_EQUAL(pixrow[col], *transpColor) ) + maskrow[col] = PBM_WHITE; + } + } + return pixrow; } -/************ HAM ************/ -static long -do_ham_body ARGS((FILE *ifP, FILE *ofp, int cols, int rows, pixval maxval, - pixval hammaxval, int nPlanes, pixel *cmap, int colors)); +/************ ILBM functions ************/ -static int hcmp (const void *va, const void *vb); -static pixel *compute_ham_cmap ARGS((int cols, int rows, int maxval, - int maxcolors, int *colorsP, int hbits)); -typedef struct { - long count; - pixval r, g, b; -} hentry; +static int +lengthOfTextChunks(void) { + int len, n; -static int -hcmp(const void *va, const void *vb) -{ - return(((hentry *)vb)->count - ((hentry *)va)->count); - /* reverse sort, highest count first */ + len = 0; + if( anno_chunk ) { + n = strlen(anno_chunk); + len += 4 + 4 + n + PAD(n); /* ID chunksize text */ + } + if( auth_chunk ) { + n = strlen(auth_chunk); + len += 4 + 4 + n + PAD(n); /* ID chunksize text */ + } + if( name_chunk ) { + n = strlen(name_chunk); + len += 4 + 4 + n + PAD(n); /* ID chunksize text */ + } + if( copyr_chunk ) { + n = strlen(copyr_chunk); + len += 4 + 4 + n + PAD(n); /* ID chunksize text */ + } + if( text_chunk ) { + n = strlen(text_chunk); + len += 4 + 4 + n + PAD(n); /* ID chunksize text */ + } + return len; } -static pixel * -compute_ham_cmap(cols, rows, maxval, maxcolors, colorsP, hbits) - int cols, rows, maxval, maxcolors; - int *colorsP; - int hbits; -{ - int colors; - hentry *hmap; - pixel *cmap; - pixval hmaxval; - int i, r, g, b, col, row, *htable; - unsigned long dist, maxdist; - pm_message("initializing HAM colormap..."); +static void +writeTextChunks(void) { - colors = 1<<(3*hbits); - MALLOCARRAY(hmap, colors); - if (hmap == NULL) - pm_error("Unable to allocate memory for HAM colormap."); - hmaxval = pm_bitstomaxval(hbits); + int n; - i = 0; - for( r = 0; r <= hmaxval; r++ ) { - for( g = 0; g <= hmaxval; g++ ) { - for( b = 0; b <= hmaxval; b++ ) { - hmap[i].r = r; hmap[i].g = g; hmap[i].b = b; - hmap[i].count = 0; - i++; - } - } + if( anno_chunk ) { + n = strlen(anno_chunk); + pm_writebiglong(stdout, ID_ANNO); + pm_writebiglong(stdout, n); + writeBytes((unsigned char *)anno_chunk, n); + if( ODD(n) ) + putByte(0); } - - htable = make_val_table(maxval, hmaxval); - for( row = 0; row < rows; row++ ) { - unsigned int col; - for( col = 0; col < cols; ++col) { - pixel const p = pixels[row][col]; - pixval const r = PPM_GETR(p); - pixval const g = PPM_GETG(p); - pixval const b = PPM_GETB(p); - i = (htable[r]<<(2*hbits)) + (htable[g]<= 0; i-- ) { - if( hmap[i].count ) - break; + if( copyr_chunk ) { + n = strlen(copyr_chunk); + pm_writebiglong(stdout, ID_copy); + pm_writebiglong(stdout, n); + writeBytes((unsigned char *)copyr_chunk, n); + if( ODD(n) ) + putByte(0); } - colors = i+1; + if( name_chunk ) { + n = strlen(name_chunk); + pm_writebiglong(stdout, ID_NAME); + pm_writebiglong(stdout, n); + writeBytes((unsigned char *)name_chunk, n); + if( ODD(n) ) + putByte(0); + } + if( text_chunk ) { + n = strlen(text_chunk); + pm_writebiglong(stdout, ID_TEXT); + pm_writebiglong(stdout, n); + writeBytes((unsigned char *)text_chunk, n); + if( ODD(n) ) + putByte(0); + } +} - if( colors > maxcolors ) { - pm_message("selecting HAM colormap from %d colors...", colors); - for( maxdist = 1; ; maxdist++ ) { - for( col = colors-1; col > 0; col-- ) { - r = hmap[col].r; g = hmap[col].g; b = hmap[col].b; - for( i = 0; i < col; i++ ) { - register int tmp; - tmp = hmap[i].r - r; dist = tmp * tmp; - tmp = hmap[i].g - g; dist += tmp * tmp; - tmp = hmap[i].b - b; dist += tmp * tmp; +static void +writeCmap(pixel * const colormap, + int const colors, + int const maxval) { - if( dist <= maxdist ) { - unsigned int sum = hmap[i].count + hmap[col].count; + int cmapsize, i; - hmap[i].r = ROUNDDIV(hmap[i].r * hmap[i].count + - r * hmap[col].count, sum); - hmap[i].g = ROUNDDIV(hmap[i].g * hmap[i].count + - g * hmap[col].count, sum); - hmap[i].b = ROUNDDIV(hmap[i].b * hmap[i].count + - b * hmap[col].count, sum); - hmap[i].count = sum; + cmapsize = 3 * colors; - hmap[col] = hmap[i]; /* temp store */ - for( tmp = i-1; - tmp >= 0 && hmap[tmp].count < hmap[col].count; - tmp-- ) - hmap[tmp+1] = hmap[tmp]; - hmap[tmp+1] = hmap[col]; + /* write colormap */ + pm_writebiglong(stdout, ID_CMAP); + pm_writebiglong(stdout, cmapsize); + if( maxval != MAXCOLVAL ) { + int *table; + pm_message("maxval is not %d - automatically rescaling colors", + MAXCOLVAL); + table = makeValTable(maxval, MAXCOLVAL); + for( i = 0; i < colors; i++ ) { + putByte(table[PPM_GETR(colormap[i])]); + putByte(table[PPM_GETG(colormap[i])]); + putByte(table[PPM_GETB(colormap[i])]); + } + free(table); + } + else { + for( i = 0; i < colors; i++ ) { + putByte(PPM_GETR(colormap[i])); + putByte(PPM_GETG(colormap[i])); + putByte(PPM_GETB(colormap[i])); + } + } + if( ODD(cmapsize) ) + putByte(0); +} - for( tmp = col; tmp < colors-1; tmp++ ) - hmap[tmp] = hmap[tmp+1]; - if( --colors <= maxcolors ) - goto out; - break; - } - } + + +static void +writeBmhd(int const cols, + int const rows, + int const nPlanes) { + + unsigned char xasp, yasp; + + xasp = 10; /* initial value */ + yasp = 10; /* initial value */ + + if( viewportmodes & vmLACE ) + xasp *= 2; + if( viewportmodes & vmHIRES ) + yasp *= 2; + + pm_writebiglong(stdout, ID_BMHD); + pm_writebiglong(stdout, BitMapHeaderSize); + + pm_writebigshort(stdout, cols); + pm_writebigshort(stdout, rows); + pm_writebigshort(stdout, 0); /* x-offset */ + pm_writebigshort(stdout, 0); /* y-offset */ + putByte(nPlanes); /* no of planes */ + putByte(maskmethod); /* masking */ + putByte(compmethod); /* compression */ + putByte(BMHD_FLAGS_CMAPOK); /* flags */ + if( maskmethod == mskHasTransparentColor ) + pm_writebigshort(stdout, transpIndex); + else + pm_writebigshort(stdout, 0); + putByte(xasp); /* x-aspect */ + putByte(yasp); /* y-aspect */ + pm_writebigshort(stdout, cols); /* pageWidth */ + pm_writebigshort(stdout, rows); /* pageHeight */ +} + + + +/************ compression ************/ + +static void +storeBodyrow(unsigned char * const row, + int const len) { + + int idx; + + idx = cur_block->used; /* initial value */ + + if (idx >= ROWS_PER_BLOCK) { + MALLOCVAR_NOFAIL(cur_block->next); + cur_block = cur_block->next; + cur_block->used = idx = 0; + cur_block->next = NULL; + } + MALLOCARRAY_NOFAIL(cur_block->row[idx], len); + cur_block->len[idx] = len; + memcpy(cur_block->row[idx], row, len); + ++cur_block->used; +} + + + +static unsigned int +compressRow(unsigned int const bytes) { + + size_t compressedByteCt; + + switch (compmethod) { + case cmpByteRun1: + pm_rlenc_compressbyte( + coded_rowbuf, compr_rowbuf, PM_RLE_PACKBITS, bytes, + &compressedByteCt); + break; + default: + pm_error("compressRow(): unknown compression method %d", + compmethod); + } + storeBodyrow(compr_rowbuf, compressedByteCt); + + assert((unsigned)compressedByteCt == compressedByteCt); + + return (unsigned)compressedByteCt; +} + + + +static const unsigned char bitmask[] = {1, 2, 4, 8, 16, 32, 64, 128}; + + + +static long +encodeRow(FILE * const outfile, + /* if non-NULL, write uncompressed row to this file */ + rawtype * const rawrow, + int const cols, + int const nPlanes) { + + /* encode algorithm by Johan Widen (jw@jwdata.se) */ + + int plane, bytes; + long retbytes = 0; + + bytes = RowBytes(cols); + + /* Encode and write raw bytes in plane-interleaved form. */ + for( plane = 0; plane < nPlanes; plane++ ) { + register int col, cbit; + register rawtype *rp; + register unsigned char *cp; + int mask; + + mask = 1 << plane; + cbit = -1; + cp = coded_rowbuf-1; + rp = rawrow; + for( col = 0; col < cols; col++, cbit--, rp++ ) { + if( cbit < 0 ) { + cbit = 7; + *++cp = 0; } -#ifdef DEBUG - pm_message("\tmaxdist=%ld: %d colors left", maxdist, colors); -#endif + if( *rp & mask ) + *cp |= bitmask[cbit]; + } + if( outfile ) { + writeBytes(coded_rowbuf, bytes); + retbytes += bytes; } + else + retbytes += compressRow(bytes); } -out: - pm_message("%d colors in HAM colormap", colors); + return retbytes; +} - cmap = ppm_allocrow(colors); - *colorsP = colors; - for( i = 0; i < colors; i++ ) { - r = hmap[i].r; g = hmap[i].g; b = hmap[i].b; - PPM_ASSIGN(cmap[i], r, g, b); + +static long +encodeMaskrow(FILE * const ofP, + rawtype * const rawrow, + int const cols) { + + int col; + + for( col = 0; col < cols; col++ ) { + if( maskrow[col] == PBM_BLACK ) + rawrow[col] = 1; + else + rawrow[col] = 0; } + return encodeRow(ofP, rawrow, cols, 1); +} - ppm_freerow(hmap); - return cmap; + + +static void +writeCamg(void) { + pm_writebiglong(stdout, ID_CAMG); + pm_writebiglong(stdout, CAMGChunkSize); + pm_writebiglong(stdout, viewportmodes); } + static void -ppm_to_ham(fp, cols, rows, maxval, colormap, colors, cmapmaxval, hamplanes) - FILE *fp; - int cols, rows, maxval; - pixel *colormap; - int colors, cmapmaxval, hamplanes; -{ - int hamcolors, nPlanes, i, hammaxval; - long oldsize, bodysize, formsize, cmapsize; - int *table = NULL; +reportTooManyColors(int const ifmode, + int const maxplanes, + int const hamplanes, + DirectColor const dcol, + int const deepbits) { + + int const maxcolors = 1 << maxplanes; - if( maskmethod == mskHasTransparentColor ) { - pm_message("masking method '%s' not usable with HAM - " - "using '%s' instead", - mskNAME[mskHasTransparentColor], mskNAME[mskHasMask]); - maskmethod = mskHasMask; + switch( ifmode ) { + case MODE_HAM: + pm_message("too many colors for %d planes - " + "proceeding to write a HAM%d file", + maxplanes, hamplanes); + pm_message("if you want a non-HAM file, try doing a 'pnmquant %d'", + maxcolors); + break; + case MODE_DCOL: + pm_message("too many colors for %d planes - " + "proceeding to write a %d:%d:%d direct color ILBM", + maxplanes, dcol.r, dcol.g, dcol.b); + pm_message("if you want a non-direct color file, " + "try doing a 'pnmquant %d'", maxcolors); + break; + case MODE_DEEP: + pm_message("too many colors for %d planes - " + "proceeding to write a %d-bit \'deep\' ILBM", + maxplanes, deepbits*3); + pm_message("if you want a non-deep file, " + "try doing a 'pnmquant %d'", + maxcolors); + break; + default: + pm_error("too many colors for %d planes - " + "try doing a 'pnmquant %d'", + maxplanes, maxcolors); + break; } +} - hamcolors = 1 << (hamplanes-2); - hammaxval = pm_bitstomaxval(hamplanes-2); - if( colors == 0 ) { - /* no colormap, make our own */ - switch( hammapmode ) { - case HAMMODE_GRAY: - colors = hamcolors; - MALLOCARRAY_NOFAIL(colormap, colors); -#ifdef DEBUG - pm_message("generating grayscale colormap"); -#endif - table = make_val_table(hammaxval, MAXCOLVAL); - for( i = 0; i < colors; i++ ) - PPM_ASSIGN(colormap[i], table[i], table[i], table[i]); - free(table); - cmapmaxval = MAXCOLVAL; - break; - case HAMMODE_FIXED: { - int entries, val; - double step; -#ifdef DEBUG - pm_message("generating rgb colormap"); +static int +getIntVal(const char * const string, + const char * const option, + int const bot, + int const top) { + + int val; + + if (sscanf(string, "%d", &val) != 1 ) + pm_error("option \"%s\" needs integer argument", option); + + if (val < bot || val > top) + pm_error("option \"%s\" argument value out of range (%d..%d)", + option, bot, top); + + return val; +} + + + +static int +getComprMethod(const char * const string) { + + int retval; + if( pm_keymatch(string, "none", 1) || pm_keymatch(string, "0", 1) ) + retval = cmpNone; + else if( pm_keymatch(string, "byterun1", 1) || + pm_keymatch(string, "1", 1) ) + retval = cmpByteRun1; + else + pm_error("unknown compression method: %s", string); + return retval; +} + + + +static int +getMaskType(const char * const string) { + + int retval; + + if( pm_keymatch(string, "none", 1) || pm_keymatch(string, "0", 1) ) + retval = mskNone; + else + if( pm_keymatch(string, "plane", 1) || + pm_keymatch(string, "maskplane", 1) || + pm_keymatch(string, "1", 1) ) + retval = mskHasMask; + else + if( pm_keymatch(string, "transparentcolor", 1) || + pm_keymatch(string, "2", 1) ) + retval = mskHasTransparentColor; + else + if( pm_keymatch(string, "lasso", 1) || pm_keymatch(string, "3", 1) ) + retval = mskLasso; + else + pm_error("unknown masking method: %s", string); + return retval; +} + + + +static int +getHammapMode(const char * const string) { + + int retval; + + if( pm_keymatch(string, "grey", 1) || pm_keymatch(string, "gray", 1) ) + retval = HAMMODE_GRAY; + else + if( pm_keymatch(string, "fixed", 1) ) + retval = HAMMODE_FIXED; + else + if( pm_keymatch(string, "rgb4", 4) ) + retval = HAMMODE_RGB4; + else + if( pm_keymatch(string, "rgb5", 4) ) + retval = HAMMODE_RGB5; + else + pm_error("unknown HAM colormap selection mode: %s", string); + return retval; +} + + + +/************ colormap file ************/ + + + +static void +ppmToCmap(pixel * const colorrow, + int const colors, + int const maxval) { + + int formsize, cmapsize; + + cmapsize = colors * 3; + + formsize = + 4 + /* ILBM */ + 4 + 4 + BitMapHeaderSize + /* BMHD size header */ + 4 + 4 + cmapsize + PAD(cmapsize) + /* CMAP size colormap */ + lengthOfTextChunks(); + + pm_writebiglong(stdout, ID_FORM); + pm_writebiglong(stdout, formsize); + pm_writebiglong(stdout, ID_ILBM); + + writeBmhd(0, 0, 0); + writeTextChunks(); + writeCmap(colorrow, colors, maxval); +} + + + +/************ HAM ************/ + + + +typedef struct { + long count; + pixval r, g, b; +} hentry; + + + +#ifndef LITERAL_FN_DEF_MATCH +static qsort_comparison_fn hcmp; #endif - /* generate a colormap of 7 "rays" in an RGB color cube: - r, g, b, r+g, r+b, g+b, r+g+b - we need one colormap entry for black, so the number of - entries per ray is (maxcolors-1)/7 */ - entries = (hamcolors-1)/7; - colors = 7*entries+1; - MALLOCARRAY_NOFAIL(colormap, colors); - step = (double)MAXCOLVAL / (double)entries; +static int +hcmp(const void * const a, + const void * const b) { - PPM_ASSIGN(colormap[0], 0, 0, 0); - for( i = 1; i <= entries; i++ ) { - val = (int)((double)i * step); - PPM_ASSIGN(colormap[ i], val, 0, 0); /* r */ - PPM_ASSIGN(colormap[ entries+i], 0, val, 0); /* g */ - PPM_ASSIGN(colormap[2*entries+i], 0, 0, val); /* b */ - PPM_ASSIGN(colormap[3*entries+i], val, val, 0); /* r+g */ - PPM_ASSIGN(colormap[4*entries+i], val, 0, val); /* r+b */ - PPM_ASSIGN(colormap[5*entries+i], 0, val, val); /* g+b */ - PPM_ASSIGN(colormap[6*entries+i], val, val, val); /*r+g+b*/ - } - cmapmaxval = MAXCOLVAL; + /* reverse sort, highest count first */ + + const hentry * const vaP = a; + const hentry * const vbP = b; + + return(vbP->count - vaP->count); +} + + + +static pixel * +computeHamCmap(int const cols, + int const rows, + int const maxval, + int const maxcolors, + int * const colorsP, + int const hbits) { + + int colors; + hentry *hmap; + pixel *cmap; + pixval hmaxval; + int i, r, g, b, col, row, *htable; + unsigned long dist, maxdist; + + pm_message("initializing HAM colormap..."); + + colors = 1<<(3*hbits); + MALLOCARRAY(hmap, colors); + if (hmap == NULL) + pm_error("Unable to allocate memory for HAM colormap."); + hmaxval = pm_bitstomaxval(hbits); + + i = 0; + for( r = 0; r <= hmaxval; r++ ) { + for( g = 0; g <= hmaxval; g++ ) { + for( b = 0; b <= hmaxval; b++ ) { + hmap[i].r = r; hmap[i].g = g; hmap[i].b = b; + hmap[i].count = 0; + i++; } - break; - case HAMMODE_RGB4: - colormap = compute_ham_cmap(cols, rows, maxval, hamcolors, - &colors, 4); - cmapmaxval = 15; - break; - case HAMMODE_RGB5: - colormap = compute_ham_cmap(cols, rows, maxval, - hamcolors, &colors, 5); - cmapmaxval = 31; - break; - default: - pm_error("ppm_to_ham(): unknown hammapmode - can't happen"); } } - else { - hammapmode = HAMMODE_MAPFILE; - if( colors > hamcolors ) { - pm_message("colormap too large - using first %d colors", - hamcolors); - colors = hamcolors; + + htable = makeValTable(maxval, hmaxval); + for( row = 0; row < rows; row++ ) { + unsigned int col; + for( col = 0; col < cols; ++col) { + pixel const p = pixels[row][col]; + pixval const r = PPM_GETR(p); + pixval const g = PPM_GETG(p); + pixval const b = PPM_GETB(p); + i = (htable[r]<<(2*hbits)) + (htable[g]<= 0; i-- ) { + if( hmap[i].count ) + break; + } + colors = i+1; + + if( colors > maxcolors ) { + pm_message("selecting HAM colormap from %d colors...", colors); + for( maxdist = 1; ; maxdist++ ) { + for( col = colors-1; col > 0; col-- ) { + r = hmap[col].r; g = hmap[col].g; b = hmap[col].b; + for( i = 0; i < col; i++ ) { + register int tmp; + + tmp = hmap[i].r - r; dist = tmp * tmp; + tmp = hmap[i].g - g; dist += tmp * tmp; + tmp = hmap[i].b - b; dist += tmp * tmp; + + if( dist <= maxdist ) { + unsigned int sum = hmap[i].count + hmap[col].count; + + hmap[i].r = ROUNDDIV(hmap[i].r * hmap[i].count + + r * hmap[col].count, sum); + hmap[i].g = ROUNDDIV(hmap[i].g * hmap[i].count + + g * hmap[col].count, sum); + hmap[i].b = ROUNDDIV(hmap[i].b * hmap[i].count + + b * hmap[col].count, sum); + hmap[i].count = sum; + + hmap[col] = hmap[i]; /* temp store */ + for( tmp = i-1; + tmp >= 0 && hmap[tmp].count < hmap[col].count; + tmp-- ) + hmap[tmp+1] = hmap[tmp]; + hmap[tmp+1] = hmap[col]; + + for( tmp = col; tmp < colors-1; tmp++ ) + hmap[tmp] = hmap[tmp+1]; + if( --colors <= maxcolors ) + goto out; + break; + } + } + } +#ifdef DEBUG + pm_message("\tmaxdist=%ld: %d colors left", maxdist, colors); +#endif } } +out: + pm_message("%d colors in HAM colormap", colors); - if( cmapmaxval != maxval ) { - int i, *table; - pixel *newcmap; + cmap = ppm_allocrow(colors); + *colorsP = colors; - newcmap = ppm_allocrow(colors); - table = make_val_table(cmapmaxval, maxval); - for( i = 0; i < colors; i++ ) - PPM_ASSIGN(newcmap[i], - table[PPM_GETR(colormap[i])], - table[PPM_GETG(colormap[i])], - table[PPM_GETB(colormap[i])]); - free(table); - ppm_freerow(colormap); - colormap = newcmap; + for( i = 0; i < colors; i++ ) { + r = hmap[i].r; g = hmap[i].g; b = hmap[i].b; + PPM_ASSIGN(cmap[i], r, g, b); } - if( sortcmap ) - ppm_sortcolorrow(colormap, colors, PPM_STDSORT); - nPlanes = hamplanes; - cmapsize = colors * 3; - - bodysize = oldsize = rows * TOTALPLANES(nPlanes) * RowBytes(cols); - if( DO_COMPRESS ) { - bodysize = do_ham_body(fp, NULL, cols, rows, maxval, - hammaxval, nPlanes, colormap, colors); - /*bodysize = do_ham_body(fp, NULL, cols, - rows, maxval, hammaxval, nPlanes, colbits, nocolor);*/ - if( bodysize > oldsize ) - pm_message("warning - %s compression increases BODY size " - "by %ld%%", - cmpNAME[compmethod], 100*(bodysize-oldsize)/oldsize); - else - pm_message("BODY compression (%s): %ld%%", - cmpNAME[compmethod], 100*(oldsize-bodysize)/oldsize); - } + ppm_freerow(hmap); + return cmap; +} - formsize = - 4 + /* ILBM */ - 4 + 4 + BitMapHeaderSize + /* BMHD size header */ - 4 + 4 + CAMGChunkSize + /* CAMG size viewportmodes */ - 4 + 4 + cmapsize + PAD(cmapsize) + /* CMAP size colormap */ - 4 + 4 + bodysize + PAD(bodysize) + /* BODY size data */ - length_of_text_chunks(); - put_big_long(ID_FORM); - put_big_long(formsize); - put_big_long(ID_ILBM); +static void +writeBodyRows(void) { - write_bmhd(cols, rows, nPlanes); - write_text_chunks(); - write_camg(); /* HAM requires CAMG chunk */ - write_cmap(colormap, colors, maxval); + bodyblock *b; + int i; + long total = 0; - /* write body */ - put_big_long(ID_BODY); - put_big_long(bodysize); - if( DO_COMPRESS ) - write_body_rows(); - else - do_ham_body(fp, stdout, cols, rows, maxval, hammaxval, - nPlanes, colormap, colors); + for( b = &firstblock; b != NULL; b = b->next ) { + for( i = 0; i < b->used; i++ ) { + writeBytes(b->row[i], b->len[i]); + total += b->len[i]; + } + } + if( ODD(total) ) + putByte(0); } + static long -do_ham_body(FILE *ifP, FILE *ofp, int cols, int rows, - pixval maxval, pixval hammaxval, int nPlanes, - pixel *colormap, int colors) -{ - register int col, row, i; +doHamBody(FILE * const ifP, + FILE * const ofP, + int const cols, + int const rows, + pixval const maxval, + pixval const hammaxval, + int const nPlanes, + pixel * const colormap, + int const colors) { + + int col, row, i; rawtype *raw_rowbuf; ppm_fs_info *fi = NULL; colorhash_table cht, cht2; @@ -665,7 +896,7 @@ do_ham_body(FILE *ifP, FILE *ofp, int cols, int rows, hamcode_green = HAMCODE_GREEN << colbits; hamcode_blue = HAMCODE_BLUE << colbits; - itoh = make_val_table(maxval, hammaxval); + itoh = makeValTable(maxval, hammaxval); if( floyd ) fi = ppm_fs_init(cols, maxval, 0); @@ -677,7 +908,7 @@ do_ham_body(FILE *ifP, FILE *ofp, int cols, int rows, pixel *prow; noprev = 1; - prow = next_pixrow(ifP, row); + prow = nextPixrow(ifP, row); for( col = ppm_fs_startrow(fi, prow); col < cols; col = ppm_fs_next(fi, col) ) { @@ -790,13 +1021,13 @@ do_ham_body(FILE *ifP, FILE *ofp, int cols, int rows, } ppm_fs_update3(fi, col, upr, upg, upb); } - bodysize += encode_row(ofp, raw_rowbuf, cols, nPlanes); + bodysize += encodeRow(ofP, raw_rowbuf, cols, nPlanes); if( maskmethod == mskHasMask ) - bodysize += encode_maskrow(ofp, raw_rowbuf, cols); + bodysize += encodeMaskrow(ofP, raw_rowbuf, cols); ppm_fs_endrow(fi); } - if( ofp && ODD(bodysize) ) - put_byte(0); + if( ofP && ODD(bodysize) ) + putByte(0); free(itoh); @@ -808,34 +1039,132 @@ do_ham_body(FILE *ifP, FILE *ofp, int cols, int rows, } -/************ deep (24-bit) ************/ - -static long do_deep_body ARGS((FILE *ifP, FILE *ofp, - int cols, int rows, - pixval maxval, int bitspercolor)); static void -ppm_to_deep(fp, cols, rows, maxval, bitspercolor) - FILE *fp; - int cols, rows, maxval, bitspercolor; -{ - int nPlanes; - long bodysize, oldsize, formsize; +ppmToHam(FILE * const ifP, + int const cols, + int const rows, + int const maxval, + pixel * const colormapArg, + int const colorsArg, + int const cmapmaxvalArg, + int const hamplanes) { + + int hamcolors, nPlanes, i, hammaxval; + long oldsize, bodysize, formsize, cmapsize; + int * table; + int colors; + pixel * colormap; + int cmapmaxval; + + table = NULL; /* initial value */ + colors = colorsArg; /* initial value*/ + colormap = colormapArg; /* initial value */ + cmapmaxval = cmapmaxvalArg; /* initial value */ if( maskmethod == mskHasTransparentColor ) { - pm_message("masking method '%s' not usable with deep ILBM - " + pm_message("masking method '%s' not usable with HAM - " "using '%s' instead", - mskNAME[mskHasTransparentColor], mskNAME[mskHasMask]); + mskNAME[mskHasTransparentColor], mskNAME[mskHasMask]); maskmethod = mskHasMask; } - nPlanes = 3*bitspercolor; + hamcolors = 1 << (hamplanes-2); + hammaxval = pm_bitstomaxval(hamplanes-2); + + if( colors == 0 ) { + /* no colormap, make our own */ + switch( hammapmode ) { + case HAMMODE_GRAY: + colors = hamcolors; + MALLOCARRAY_NOFAIL(colormap, colors); + table = makeValTable(hammaxval, MAXCOLVAL); + for( i = 0; i < colors; i++ ) + PPM_ASSIGN(colormap[i], table[i], table[i], table[i]); + free(table); + cmapmaxval = MAXCOLVAL; + break; + case HAMMODE_FIXED: { + int entries, val; + double step; + + /* generate a colormap of 7 "rays" in an RGB color cube: + r, g, b, r+g, r+b, g+b, r+g+b + we need one colormap entry for black, so the number of + entries per ray is (maxcolors-1)/7 */ + + entries = (hamcolors-1)/7; + colors = 7*entries+1; + MALLOCARRAY_NOFAIL(colormap, colors); + step = (double)MAXCOLVAL / (double)entries; + + PPM_ASSIGN(colormap[0], 0, 0, 0); + for( i = 1; i <= entries; i++ ) { + val = (int)((double)i * step); + PPM_ASSIGN(colormap[ i], val, 0, 0); /* r */ + PPM_ASSIGN(colormap[ entries+i], 0, val, 0); /* g */ + PPM_ASSIGN(colormap[2*entries+i], 0, 0, val); /* b */ + PPM_ASSIGN(colormap[3*entries+i], val, val, 0); /* r+g */ + PPM_ASSIGN(colormap[4*entries+i], val, 0, val); /* r+b */ + PPM_ASSIGN(colormap[5*entries+i], 0, val, val); /* g+b */ + PPM_ASSIGN(colormap[6*entries+i], val, val, val); /*r+g+b*/ + } + cmapmaxval = MAXCOLVAL; + } + break; + case HAMMODE_RGB4: + colormap = computeHamCmap(cols, rows, maxval, hamcolors, + &colors, 4); + cmapmaxval = 15; + break; + case HAMMODE_RGB5: + colormap = computeHamCmap(cols, rows, maxval, + hamcolors, &colors, 5); + cmapmaxval = 31; + break; + default: + pm_error("ppm_to_ham(): unknown hammapmode - can't happen"); + } + } + else { + hammapmode = HAMMODE_MAPFILE; + if( colors > hamcolors ) { + pm_message("colormap too large - using first %d colors", + hamcolors); + colors = hamcolors; + } + } + + if( cmapmaxval != maxval ) { + int i, *table; + pixel *newcmap; + + newcmap = ppm_allocrow(colors); + table = makeValTable(cmapmaxval, maxval); + for( i = 0; i < colors; i++ ) + PPM_ASSIGN(newcmap[i], + table[PPM_GETR(colormap[i])], + table[PPM_GETG(colormap[i])], + table[PPM_GETB(colormap[i])]); + free(table); + ppm_freerow(colormap); + colormap = newcmap; + } + if( sortcmap ) + ppm_sortcolorrow(colormap, colors, PPM_STDSORT); + + nPlanes = hamplanes; + cmapsize = colors * 3; bodysize = oldsize = rows * TOTALPLANES(nPlanes) * RowBytes(cols); if( DO_COMPRESS ) { - bodysize = do_deep_body(fp, NULL, cols, rows, maxval, bitspercolor); + bodysize = doHamBody(ifP, NULL, cols, rows, maxval, + hammaxval, nPlanes, colormap, colors); + /*bodysize = doHamBody(ifP, NULL, cols, + rows, maxval, hammaxval, nPlanes, colbits, nocolor);*/ if( bodysize > oldsize ) - pm_message("warning - %s compression increases BODY size by %ld%%", + pm_message("warning - %s compression increases BODY size " + "by %ld%%", cmpNAME[compmethod], 100*(bodysize-oldsize)/oldsize); else pm_message("BODY compression (%s): %ld%%", @@ -846,35 +1175,45 @@ ppm_to_deep(fp, cols, rows, maxval, bitspercolor) formsize = 4 + /* ILBM */ 4 + 4 + BitMapHeaderSize + /* BMHD size header */ + 4 + 4 + CAMGChunkSize + /* CAMG size viewportmodes */ + 4 + 4 + cmapsize + PAD(cmapsize) + /* CMAP size colormap */ 4 + 4 + bodysize + PAD(bodysize) + /* BODY size data */ - length_of_text_chunks(); - if( gen_camg ) - formsize += 4 + 4 + CAMGChunkSize; /* CAMG size viewportmodes */ + lengthOfTextChunks(); - put_big_long(ID_FORM); - put_big_long(formsize); - put_big_long(ID_ILBM); + pm_writebiglong(stdout, ID_FORM); + pm_writebiglong(stdout, formsize); + pm_writebiglong(stdout, ID_ILBM); - write_bmhd(cols, rows, nPlanes); - write_text_chunks(); - if( gen_camg ) - write_camg(); + writeBmhd(cols, rows, nPlanes); + writeTextChunks(); + writeCamg(); /* HAM requires CAMG chunk */ + writeCmap(colormap, colors, maxval); /* write body */ - put_big_long(ID_BODY); - put_big_long(bodysize); + pm_writebiglong(stdout, ID_BODY); + pm_writebiglong(stdout, bodysize); if( DO_COMPRESS ) - write_body_rows(); + writeBodyRows(); else - do_deep_body(fp, stdout, cols, rows, maxval, bitspercolor); + doHamBody(ifP, stdout, cols, rows, maxval, hammaxval, + nPlanes, colormap, colors); } + +/************ deep (24-bit) ************/ + + + static long -do_deep_body(FILE *ifP, FILE *ofp, int cols, int rows, pixval maxval, - int bitspercolor) -{ - register int row, col; +doDeepBody(FILE * const ifP, + FILE * const ofP, + int const cols, + int const rows, + pixval const maxval, + int const bitspercolor) { + + int row, col; pixel *pP; int *table = NULL; long bodysize = 0; @@ -889,11 +1228,11 @@ do_deep_body(FILE *ifP, FILE *ofp, int cols, int rows, pixval maxval, if( maxval != newmaxval ) { pm_message("maxval is not %d - automatically rescaling colors", newmaxval); - table = make_val_table(maxval, newmaxval); + table = makeValTable(maxval, newmaxval); } for( row = 0; row < rows; row++ ) { - pP = next_pixrow(ifP, row); + pP = nextPixrow(ifP, row); if( table ) { for( col = 0; col < cols; col++, pP++ ) { redbuf[col] = table[PPM_GETR(*pP)]; @@ -902,142 +1241,24 @@ do_deep_body(FILE *ifP, FILE *ofp, int cols, int rows, pixval maxval, } } else { - for( col = 0; col < cols; col++, pP++ ) { - redbuf[col] = PPM_GETR(*pP); - greenbuf[col] = PPM_GETG(*pP); - bluebuf[col] = PPM_GETB(*pP); - } - } - bodysize += encode_row(ofp, redbuf, cols, bitspercolor); - bodysize += encode_row(ofp, greenbuf, cols, bitspercolor); - bodysize += encode_row(ofp, bluebuf, cols, bitspercolor); - if( maskmethod == mskHasMask ) - bodysize += encode_maskrow(ofp, redbuf, cols); - } - if( ofp && ODD(bodysize) ) - put_byte(0); - - /* clean up */ - if( table ) - free(table); - free(redbuf); - free(greenbuf); - free(bluebuf); - - return bodysize; -} - - -/************ direct color ************/ - -static long do_dcol_body ARGS((FILE *ifP, FILE *ofp, int cols, int rows, - pixval maxval, DirectColor *dcol)); - -static void -ppm_to_dcol(fp, cols, rows, maxval, dcol) - FILE *fp; - int cols, rows, maxval; - DirectColor *dcol; -{ - int nPlanes; - long bodysize, oldsize, formsize; - - if( maskmethod == mskHasTransparentColor ) { - pm_message("masking method '%s' not usable with deep ILBM - " - "using '%s' instead", - mskNAME[mskHasTransparentColor], mskNAME[mskHasMask]); - maskmethod = mskHasMask; - } - - nPlanes = dcol->r + dcol->g + dcol->b; - - bodysize = oldsize = rows * TOTALPLANES(nPlanes) * RowBytes(cols); - if( DO_COMPRESS ) { - bodysize = do_dcol_body(fp, NULL, cols, rows, maxval, dcol); - if( bodysize > oldsize ) - pm_message("warning - %s compression increases BODY size by %ld%%", - cmpNAME[compmethod], - 100*(bodysize-oldsize)/oldsize); - else - pm_message("BODY compression (%s): %ld%%", cmpNAME[compmethod], - 100*(oldsize-bodysize)/oldsize); - } - - - formsize = - 4 + /* ILBM */ - 4 + 4 + BitMapHeaderSize + /* BMHD size header */ - 4 + 4 + DirectColorSize + /* DCOL size dcol */ - 4 + 4 + bodysize + PAD(bodysize) + /* BODY size data */ - length_of_text_chunks(); - if( gen_camg ) - formsize += 4 + 4 + CAMGChunkSize; /* CAMG size viewportmodes */ - - put_big_long(ID_FORM); - put_big_long(formsize); - put_big_long(ID_ILBM); - - write_bmhd(cols, rows, nPlanes); - write_text_chunks(); - - put_big_long(ID_DCOL); - put_big_long(DirectColorSize); - put_byte(dcol->r); - put_byte(dcol->g); - put_byte(dcol->b); - put_byte(0); /* pad */ - - if( gen_camg ) - write_camg(); - - /* write body */ - put_big_long(ID_BODY); - put_big_long(bodysize); - if( DO_COMPRESS ) - write_body_rows(); - else - do_dcol_body(fp, stdout, cols, rows, maxval, dcol); -} - - -static long -do_dcol_body(FILE *ifP, FILE *ofp, int cols, int rows, pixval maxval, - DirectColor *dcol) -{ - register int row, col; - pixel *pP; - long bodysize = 0; - rawtype *redbuf, *greenbuf, *bluebuf; - int *redtable, *greentable, *bluetable; - - MALLOCARRAY_NOFAIL(redbuf, cols); - MALLOCARRAY_NOFAIL(greenbuf, cols); - MALLOCARRAY_NOFAIL(bluebuf, cols); - - redtable = make_val_table(maxval, pm_bitstomaxval(dcol->r)); - greentable = make_val_table(maxval, pm_bitstomaxval(dcol->g)); - bluetable = make_val_table(maxval, pm_bitstomaxval(dcol->b)); - - for( row = 0; row < rows; row++ ) { - pP = next_pixrow(ifP, row); - for( col = 0; col < cols; col++, pP++ ) { - redbuf[col] = redtable[PPM_GETR(*pP)]; - greenbuf[col] = greentable[PPM_GETG(*pP)]; - bluebuf[col] = bluetable[PPM_GETB(*pP)]; + for( col = 0; col < cols; col++, pP++ ) { + redbuf[col] = PPM_GETR(*pP); + greenbuf[col] = PPM_GETG(*pP); + bluebuf[col] = PPM_GETB(*pP); + } } - bodysize += encode_row(ofp, redbuf, cols, dcol->r); - bodysize += encode_row(ofp, greenbuf, cols, dcol->g); - bodysize += encode_row(ofp, bluebuf, cols, dcol->b); + bodysize += encodeRow(ofP, redbuf, cols, bitspercolor); + bodysize += encodeRow(ofP, greenbuf, cols, bitspercolor); + bodysize += encodeRow(ofP, bluebuf, cols, bitspercolor); if( maskmethod == mskHasMask ) - bodysize += encode_maskrow(ofp, redbuf, cols); + bodysize += encodeMaskrow(ofP, redbuf, cols); } - if( ofp && ODD(bodysize) ) - put_byte(0); + if( ofP && ODD(bodysize) ) + putByte(0); /* clean up */ - free(redtable); - free(greentable); - free(bluetable); + if( table ) + free(table); free(redbuf); free(greenbuf); free(bluebuf); @@ -1046,60 +1267,29 @@ do_dcol_body(FILE *ifP, FILE *ofp, int cols, int rows, pixval maxval, } -/************ normal colormapped ************/ - -static long do_std_body ARGS((FILE *ifP, FILE *ofp, int cols, int rows, - pixval maxval, pixel *colormap, - int colors, int nPlanes)); static void -ppm_to_std(fp, cols, rows, maxval, colormap, colors, cmapmaxval, - maxcolors, nPlanes) - FILE *fp; - int cols, rows, maxval; - pixel *colormap; - int cmapmaxval, colors, maxcolors, nPlanes; -{ - long formsize, cmapsize, bodysize, oldsize; +ppmToDeep(FILE * const ifP, + int const cols, + int const rows, + int const maxval, + int const bitspercolor) { - if( maskmethod == mskHasTransparentColor ) { - if( transpColor ) { - transpIndex = - ppm_addtocolorrow(colormap, &colors, maxcolors, transpColor); - } - else - if( colors < maxcolors ) - transpIndex = colors; + int nPlanes; + long bodysize, oldsize, formsize; - if( transpIndex < 0 ) { - pm_message("too many colors for masking method '%s' - " - "using '%s' instead", - mskNAME[mskHasTransparentColor], mskNAME[mskHasMask]); - maskmethod = mskHasMask; - } + if( maskmethod == mskHasTransparentColor ) { + pm_message("masking method '%s' not usable with deep ILBM - " + "using '%s' instead", + mskNAME[mskHasTransparentColor], mskNAME[mskHasMask]); + maskmethod = mskHasMask; } - if( cmapmaxval != maxval ) { - int i, *table; - pixel *newcmap; - - newcmap = ppm_allocrow(colors); - table = make_val_table(cmapmaxval, maxval); - for (i = 0; i < colors; ++i) - PPM_ASSIGN(newcmap[i], - table[PPM_GETR(colormap[i])], - table[PPM_GETG(colormap[i])], - table[PPM_GETB(colormap[i])]); - free(table); - colormap = newcmap; - } - if( sortcmap ) - ppm_sortcolorrow(colormap, colors, PPM_STDSORT); + nPlanes = 3*bitspercolor; bodysize = oldsize = rows * TOTALPLANES(nPlanes) * RowBytes(cols); if( DO_COMPRESS ) { - bodysize = do_std_body(fp, NULL, cols, rows, maxval, colormap, - colors, nPlanes); + bodysize = doDeepBody(ifP, NULL, cols, rows, maxval, bitspercolor); if( bodysize > oldsize ) pm_message("warning - %s compression increases BODY size by %ld%%", cmpNAME[compmethod], 100*(bodysize-oldsize)/oldsize); @@ -1108,753 +1298,567 @@ ppm_to_std(fp, cols, rows, maxval, colormap, colors, cmapmaxval, cmpNAME[compmethod], 100*(oldsize-bodysize)/oldsize); } - cmapsize = colors * 3; - formsize = 4 + /* ILBM */ 4 + 4 + BitMapHeaderSize + /* BMHD size header */ - 4 + 4 + cmapsize + PAD(cmapsize) + /* CMAP size colormap */ 4 + 4 + bodysize + PAD(bodysize) + /* BODY size data */ - length_of_text_chunks(); + lengthOfTextChunks(); if( gen_camg ) formsize += 4 + 4 + CAMGChunkSize; /* CAMG size viewportmodes */ - put_big_long(ID_FORM); - put_big_long(formsize); - put_big_long(ID_ILBM); + pm_writebiglong(stdout, ID_FORM); + pm_writebiglong(stdout, formsize); + pm_writebiglong(stdout, ID_ILBM); - write_bmhd(cols, rows, nPlanes); - write_text_chunks(); + writeBmhd(cols, rows, nPlanes); + writeTextChunks(); if( gen_camg ) - write_camg(); - write_cmap(colormap, colors, maxval); + writeCamg(); /* write body */ - put_big_long(ID_BODY); - put_big_long(bodysize); + pm_writebiglong(stdout, ID_BODY); + pm_writebiglong(stdout, bodysize); if( DO_COMPRESS ) - write_body_rows(); + writeBodyRows(); else - do_std_body(fp, stdout, cols, rows, maxval, colormap, colors, nPlanes); + doDeepBody(ifP, stdout, cols, rows, maxval, bitspercolor); } -static long -do_std_body(FILE *ifP, FILE *ofp, int cols, int rows, pixval maxval, - pixel *colormap, int colors, int nPlanes) -{ - register int row, col, i; - pixel *pP; - rawtype *raw_rowbuf; - ppm_fs_info *fi = NULL; - long bodysize = 0; - int usehash = 1; - colorhash_table cht; - - MALLOCARRAY_NOFAIL(raw_rowbuf, cols); - cht = ppm_colorrowtocolorhash(colormap, colors); - if( floyd ) - fi = ppm_fs_init(cols, maxval, FS_ALTERNATE); - - for( row = 0; row < rows; row++ ) { - pixel *prow; - prow = next_pixrow(ifP, row); - - for( col = ppm_fs_startrow(fi, prow); - col < cols; - col = ppm_fs_next(fi, col) ) { - pP = &prow[col]; - - if( maskmethod == mskHasTransparentColor && - maskrow[col] == PBM_WHITE ) - i = transpIndex; - else { - /* Check hash table to see if we have already matched - this color. - */ - i = ppm_lookupcolor(cht, pP); - if( i == -1 ) { - i = ppm_findclosestcolor(colormap, colors, pP); - /* No; search colormap for closest match. */ - if( usehash ) { - if( ppm_addtocolorhash(cht, pP, i) < 0 ) { - pm_message("out of memory adding to hash table, " - "proceeding without it"); - usehash = 0; - } - } - } - } - raw_rowbuf[col] = i; - ppm_fs_update(fi, col, &colormap[i]); - } - bodysize += encode_row(ofp, raw_rowbuf, cols, nPlanes); - if( maskmethod == mskHasMask ) - bodysize += encode_maskrow(ofp, raw_rowbuf, cols); - ppm_fs_endrow(fi); - } - if( ofp && ODD(bodysize) ) - put_byte(0); - /* clean up */ - ppm_freecolorhash(cht); - free(raw_rowbuf); - ppm_fs_free(fi); +/************ direct color ************/ - return bodysize; -} -/************ RGB8 ************/ -static void -ppm_to_rgb8(ifP, cols, rows, maxval) - FILE *ifP; - int cols, rows; - int maxval; -{ - long bodysize, oldsize, formsize; +static long +doDcolBody(FILE * const ifP, + FILE * const ofP, + int const cols, + int const rows, + pixval const maxval, + DirectColor * const dcol) { + + int row, col; pixel *pP; - int *table = NULL; - int row, col1, col2, compr_len, len; - unsigned char *compr_row; + long bodysize = 0; + rawtype *redbuf, *greenbuf, *bluebuf; + int *redtable, *greentable, *bluetable; - maskmethod = 0; /* no masking - RGB8 uses genlock bits */ - compmethod = 4; /* RGB8 files are always compressed */ - MALLOCARRAY_NOFAIL(compr_row, cols * 4); + MALLOCARRAY_NOFAIL(redbuf, cols); + MALLOCARRAY_NOFAIL(greenbuf, cols); + MALLOCARRAY_NOFAIL(bluebuf, cols); - if( maxval != 255 ) { - pm_message("maxval is not 255 - automatically rescaling colors"); - table = make_val_table(maxval, 255); - } + redtable = makeValTable(maxval, pm_bitstomaxval(dcol->r)); + greentable = makeValTable(maxval, pm_bitstomaxval(dcol->g)); + bluetable = makeValTable(maxval, pm_bitstomaxval(dcol->b)); - oldsize = cols * rows * 4; - bodysize = 0; for( row = 0; row < rows; row++ ) { - pP = next_pixrow(ifP, row); - compr_len = 0; - for( col1 = 0; col1 < cols; col1 = col2 ) { - col2 = col1 + 1; - if( maskrow ) { - while( col2 < cols && PPM_EQUAL(pP[col1], pP[col2]) && - maskrow[col1] == maskrow[col2] ) - col2++; - } - else { - while( col2 < cols && PPM_EQUAL(pP[col1], pP[col2]) ) - col2++; - } - len = col2 - col1; - while( len ) { - int count; - count = (len > 127 ? 127 : len); - len -= count; - if( table ) { - compr_row[compr_len++] = table[PPM_GETR(pP[col1])]; - compr_row[compr_len++] = table[PPM_GETG(pP[col1])]; - compr_row[compr_len++] = table[PPM_GETB(pP[col1])]; - } - else { - compr_row[compr_len++] = PPM_GETR(pP[col1]); - compr_row[compr_len++] = PPM_GETG(pP[col1]); - compr_row[compr_len++] = PPM_GETB(pP[col1]); - } - compr_row[compr_len] = count; - if( maskrow && maskrow[col1] == PBM_WHITE ) - compr_row[compr_len] |= 1<<7; /* genlock bit */ - ++compr_len; - } + pP = nextPixrow(ifP, row); + for( col = 0; col < cols; col++, pP++ ) { + redbuf[col] = redtable[PPM_GETR(*pP)]; + greenbuf[col] = greentable[PPM_GETG(*pP)]; + bluebuf[col] = bluetable[PPM_GETB(*pP)]; } - store_bodyrow(compr_row, compr_len); - bodysize += compr_len; + bodysize += encodeRow(ofP, redbuf, cols, dcol->r); + bodysize += encodeRow(ofP, greenbuf, cols, dcol->g); + bodysize += encodeRow(ofP, bluebuf, cols, dcol->b); + if( maskmethod == mskHasMask ) + bodysize += encodeMaskrow(ofP, redbuf, cols); } + if( ofP && ODD(bodysize) ) + putByte(0); - pm_message("BODY compression: %ld%%", 100*(oldsize-bodysize)/oldsize); - - formsize = - 4 + /* RGB8 */ - 4 + 4 + BitMapHeaderSize + /* BMHD size header */ - 4 + 4 + CAMGChunkSize + /* CAMG size viewportmode */ - 4 + 4 + bodysize + PAD(bodysize) + /* BODY size data */ - length_of_text_chunks(); - - /* write header */ - put_big_long(ID_FORM); - put_big_long(formsize); - put_big_long(ID_RGB8); - - write_bmhd(cols, rows, 25); - write_text_chunks(); - write_camg(); /* RGB8 requires CAMG chunk */ + /* clean up */ + free(redtable); + free(greentable); + free(bluetable); + free(redbuf); + free(greenbuf); + free(bluebuf); - put_big_long(ID_BODY); - put_big_long(bodysize); - write_body_rows(); + return bodysize; } -/************ RGBN ************/ static void -ppm_to_rgbn(ifP, cols, rows, maxval) - FILE *ifP; - int cols, rows; - int maxval; -{ - long bodysize, oldsize, formsize; - pixel *pP; - int *table = NULL; - int row, col1, col2, compr_len, len; - unsigned char *compr_row; - - maskmethod = 0; /* no masking - RGBN uses genlock bits */ - compmethod = 4; /* RGBN files are always compressed */ - MALLOCARRAY_NOFAIL(compr_row, cols * 2); +ppmToDcol(FILE * const ifP, + int const cols, + int const rows, + int const maxval, + DirectColor * const dcol) { - if( maxval != 15 ) { - pm_message("maxval is not 15 - automatically rescaling colors"); - table = make_val_table(maxval, 15); - } + int nPlanes; + long bodysize, oldsize, formsize; - oldsize = cols * rows * 2; - bodysize = 0; - for( row = 0; row < rows; row++ ) { - pP = next_pixrow(ifP, row); - compr_len = 0; - for( col1 = 0; col1 < cols; col1 = col2 ) { - col2 = col1 + 1; - if( maskrow ) { - while( col2 < cols && PPM_EQUAL(pP[col1], pP[col2]) && - maskrow[col1] == maskrow[col2] ) - col2++; - } - else { - while( col2 < cols && PPM_EQUAL(pP[col1], pP[col2]) ) - col2++; - } - len = col2 - col1; - while( len ) { - int count; - count = (len > 65535 ? 65535 : len); - len -= count; - if( table ) { - compr_row[compr_len] = table[PPM_GETR(pP[col1])] << 4; - compr_row[compr_len] |= table[PPM_GETG(pP[col1])]; - ++compr_len; - compr_row[compr_len] = table[PPM_GETB(pP[col1])] << 4; - } - else { - compr_row[compr_len] = PPM_GETR(pP[col1]) << 4; - compr_row[compr_len] |= PPM_GETG(pP[col1]); - ++compr_len; - compr_row[compr_len] = PPM_GETB(pP[col1]) << 4; - } - if( maskrow && maskrow[col1] == PBM_WHITE ) - compr_row[compr_len] |= 1<<3; /* genlock bit */ - if( count <= 7 ) - compr_row[compr_len++] |= count; /* 3 bit repeat count */ - else { - ++compr_len; /* 3 bit repeat count = 0 */ - if( count <= 255 ) - compr_row[compr_len++] = (unsigned char)count; - /* byte repeat count */ - else { - compr_row[compr_len++] = (unsigned char)0; - /* byte repeat count = 0 */ - compr_row[compr_len++] = (count >> 8) & 0xff; - /* word repeat count MSB */ - compr_row[compr_len++] = count & 0xff; - /* word repeat count LSB */ - } - } - } - } - store_bodyrow(compr_row, compr_len); - bodysize += compr_len; + if( maskmethod == mskHasTransparentColor ) { + pm_message("masking method '%s' not usable with deep ILBM - " + "using '%s' instead", + mskNAME[mskHasTransparentColor], mskNAME[mskHasMask]); + maskmethod = mskHasMask; + } + + nPlanes = dcol->r + dcol->g + dcol->b; + + bodysize = oldsize = rows * TOTALPLANES(nPlanes) * RowBytes(cols); + if( DO_COMPRESS ) { + bodysize = doDcolBody(ifP, NULL, cols, rows, maxval, dcol); + if( bodysize > oldsize ) + pm_message("warning - %s compression increases BODY size by %ld%%", + cmpNAME[compmethod], + 100*(bodysize-oldsize)/oldsize); + else + pm_message("BODY compression (%s): %ld%%", cmpNAME[compmethod], + 100*(oldsize-bodysize)/oldsize); } - pm_message("BODY compression: %ld%%", 100*(oldsize-bodysize)/oldsize); formsize = - 4 + /* RGBN */ + 4 + /* ILBM */ 4 + 4 + BitMapHeaderSize + /* BMHD size header */ - 4 + 4 + CAMGChunkSize + /* CAMG size viewportmode */ + 4 + 4 + DirectColorSize + /* DCOL size dcol */ 4 + 4 + bodysize + PAD(bodysize) + /* BODY size data */ - length_of_text_chunks(); - - /* write header */ - put_big_long(ID_FORM); - put_big_long(formsize); - put_big_long(ID_RGBN); - - write_bmhd(cols, rows, 13); - write_text_chunks(); - write_camg(); /* RGBN requires CAMG chunk */ - - put_big_long(ID_BODY); - put_big_long(bodysize); - write_body_rows(); -} - + lengthOfTextChunks(); + if( gen_camg ) + formsize += 4 + 4 + CAMGChunkSize; /* CAMG size viewportmodes */ -/************ multipalette ************/ + pm_writebiglong(stdout, ID_FORM); + pm_writebiglong(stdout, formsize); + pm_writebiglong(stdout, ID_ILBM); -#ifdef ILBM_PCHG -static pixel *ppmslice[2]; /* need 2 for laced ILBMs, else 1 */ + writeBmhd(cols, rows, nPlanes); + writeTextChunks(); -void ppm_to_pchg() -{ -/* - read first slice - build a colormap from this slice - select upto colors - build colormap from selected colors - map slice to colormap - write slice - while( !finished ) { - read next slice - compute distances for each pixel and select upto - unused colors in this slice - modify selected colors to the ones with maximum(?) distance - map slice to colormap - write slice - } + pm_writebiglong(stdout, ID_DCOL); + pm_writebiglong(stdout, DirectColorSize); + putByte(dcol->r); + putByte(dcol->g); + putByte(dcol->b); + putByte(0); /* pad */ + if( gen_camg ) + writeCamg(); - for HAM use a different mapping: - compute distance to closest color in colormap - if( there is no matching color in colormap ) { - compute distances for the three "modify" cases - use the shortest distance from the four cases - } -*/ + /* write body */ + pm_writebiglong(stdout, ID_BODY); + pm_writebiglong(stdout, bodysize); + if( DO_COMPRESS ) + writeBodyRows(); + else + doDcolBody(ifP, stdout, cols, rows, maxval, dcol); } -#endif - -/************ ILBM functions ************/ -static int -length_of_text_chunks ARGS((void)) -{ - int len, n; - len = 0; - if( anno_chunk ) { - n = strlen(anno_chunk); - len += 4 + 4 + n + PAD(n); /* ID chunksize text */ - } - if( auth_chunk ) { - n = strlen(auth_chunk); - len += 4 + 4 + n + PAD(n); /* ID chunksize text */ - } - if( name_chunk ) { - n = strlen(name_chunk); - len += 4 + 4 + n + PAD(n); /* ID chunksize text */ - } - if( copyr_chunk ) { - n = strlen(copyr_chunk); - len += 4 + 4 + n + PAD(n); /* ID chunksize text */ - } - if( text_chunk ) { - n = strlen(text_chunk); - len += 4 + 4 + n + PAD(n); /* ID chunksize text */ - } - return len; -} +/************ normal colormapped ************/ -static void -write_text_chunks ARGS((void)) -{ - int n; - if( anno_chunk ) { - n = strlen(anno_chunk); - put_big_long(ID_ANNO); - put_big_long(n); - write_bytes((unsigned char *)anno_chunk, n); - if( ODD(n) ) - put_byte(0); - } - if( auth_chunk ) { - n = strlen(auth_chunk); - put_big_long(ID_AUTH); - put_big_long(n); - write_bytes((unsigned char *)auth_chunk, n); - if( ODD(n) ) - put_byte(0); - } - if( copyr_chunk ) { - n = strlen(copyr_chunk); - put_big_long(ID_copy); - put_big_long(n); - write_bytes((unsigned char *)copyr_chunk, n); - if( ODD(n) ) - put_byte(0); - } - if( name_chunk ) { - n = strlen(name_chunk); - put_big_long(ID_NAME); - put_big_long(n); - write_bytes((unsigned char *)name_chunk, n); - if( ODD(n) ) - put_byte(0); - } - if( text_chunk ) { - n = strlen(text_chunk); - put_big_long(ID_TEXT); - put_big_long(n); - write_bytes((unsigned char *)text_chunk, n); - if( ODD(n) ) - put_byte(0); - } -} +static long +doStdBody(FILE * const ifP, + FILE * const ofP, + int const cols, + int const rows, + pixval const maxval, + pixel * const colormap, + int const colors, + int const nPlanes) { + + int row, col, i; + pixel *pP; + rawtype *raw_rowbuf; + ppm_fs_info *fi = NULL; + long bodysize = 0; + int usehash = 1; + colorhash_table cht; + MALLOCARRAY_NOFAIL(raw_rowbuf, cols); + cht = ppm_colorrowtocolorhash(colormap, colors); + if( floyd ) + fi = ppm_fs_init(cols, maxval, FS_ALTERNATE); -static void -write_cmap(colormap, colors, maxval) - pixel *colormap; - int colors, maxval; -{ - int cmapsize, i; + for( row = 0; row < rows; row++ ) { + pixel *prow; + prow = nextPixrow(ifP, row); - cmapsize = 3 * colors; + for( col = ppm_fs_startrow(fi, prow); + col < cols; + col = ppm_fs_next(fi, col) ) { + pP = &prow[col]; - /* write colormap */ - put_big_long(ID_CMAP); - put_big_long(cmapsize); - if( maxval != MAXCOLVAL ) { - int *table; - pm_message("maxval is not %d - automatically rescaling colors", - MAXCOLVAL); - table = make_val_table(maxval, MAXCOLVAL); - for( i = 0; i < colors; i++ ) { - put_byte(table[PPM_GETR(colormap[i])]); - put_byte(table[PPM_GETG(colormap[i])]); - put_byte(table[PPM_GETB(colormap[i])]); - } - free(table); - } - else { - for( i = 0; i < colors; i++ ) { - put_byte(PPM_GETR(colormap[i])); - put_byte(PPM_GETG(colormap[i])); - put_byte(PPM_GETB(colormap[i])); + if( maskmethod == mskHasTransparentColor && + maskrow[col] == PBM_WHITE ) + i = transpIndex; + else { + /* Check hash table to see if we have already matched + this color. + */ + i = ppm_lookupcolor(cht, pP); + if( i == -1 ) { + i = ppm_findclosestcolor(colormap, colors, pP); + /* No; search colormap for closest match. */ + if( usehash ) { + if( ppm_addtocolorhash(cht, pP, i) < 0 ) { + pm_message("out of memory adding to hash table, " + "proceeding without it"); + usehash = 0; + } + } + } + } + raw_rowbuf[col] = i; + ppm_fs_update(fi, col, &colormap[i]); } + bodysize += encodeRow(ofP, raw_rowbuf, cols, nPlanes); + if( maskmethod == mskHasMask ) + bodysize += encodeMaskrow(ofP, raw_rowbuf, cols); + ppm_fs_endrow(fi); } - if( ODD(cmapsize) ) - put_byte(0); -} - + if( ofP && ODD(bodysize) ) + putByte(0); -static void -write_bmhd(cols, rows, nPlanes) - int cols, rows, nPlanes; -{ - unsigned char xasp = 10, yasp = 10; - - if( viewportmodes & vmLACE ) - xasp *= 2; - if( viewportmodes & vmHIRES ) - yasp *= 2; + /* clean up */ + ppm_freecolorhash(cht); + free(raw_rowbuf); + ppm_fs_free(fi); - put_big_long(ID_BMHD); - put_big_long(BitMapHeaderSize); - - put_big_short(cols); - put_big_short(rows); - put_big_short(0); /* x-offset */ - put_big_short(0); /* y-offset */ - put_byte(nPlanes); /* no of planes */ - put_byte(maskmethod); /* masking */ - put_byte(compmethod); /* compression */ - put_byte(BMHD_FLAGS_CMAPOK); /* flags */ - if( maskmethod == mskHasTransparentColor ) - put_big_short(transpIndex); - else - put_big_short(0); - put_byte(xasp); /* x-aspect */ - put_byte(yasp); /* y-aspect */ - put_big_short(cols); /* pageWidth */ - put_big_short(rows); /* pageHeight */ + return bodysize; } -/* encode algorithm by Johan Widen (jw@jwdata.se) */ -static const unsigned char bitmask[] = {1, 2, 4, 8, 16, 32, 64, 128}; -static long -encode_row(outfile, rawrow, cols, nPlanes) - FILE *outfile; /* if non-NULL, write uncompressed row to this file */ - rawtype *rawrow; - int cols, nPlanes; -{ - int plane, bytes; - long retbytes = 0; +static void +ppmToStd(FILE * const ifP, + int const cols, + int const rows, + int const maxval, + pixel * const colormapArg, + int const colorsArg, + int const cmapmaxvalArg, + int const maxcolors, + int const nPlanes) { - bytes = RowBytes(cols); + long formsize, cmapsize, bodysize, oldsize; - /* Encode and write raw bytes in plane-interleaved form. */ - for( plane = 0; plane < nPlanes; plane++ ) { - register int col, cbit; - register rawtype *rp; - register unsigned char *cp; - int mask; + int colors; + pixel * colormap; + int cmapmaxval; - mask = 1 << plane; - cbit = -1; - cp = coded_rowbuf-1; - rp = rawrow; - for( col = 0; col < cols; col++, cbit--, rp++ ) { - if( cbit < 0 ) { - cbit = 7; - *++cp = 0; - } - if( *rp & mask ) - *cp |= bitmask[cbit]; - } - if( outfile ) { - write_bytes(coded_rowbuf, bytes); - retbytes += bytes; + colors = colorsArg; /* initial value */ + colormap = colormapArg; /* initial value */ + cmapmaxval = cmapmaxvalArg; /* initial value */ + + if( maskmethod == mskHasTransparentColor ) { + if( transpColor ) { + transpIndex = + ppm_addtocolorrow(colormap, &colors, maxcolors, transpColor); } else - retbytes += compress_row(bytes); + if( colors < maxcolors ) + transpIndex = colors; + + if( transpIndex < 0 ) { + pm_message("too many colors for masking method '%s' - " + "using '%s' instead", + mskNAME[mskHasTransparentColor], mskNAME[mskHasMask]); + maskmethod = mskHasMask; + } } - return retbytes; -} + if( cmapmaxval != maxval ) { + int i, *table; + pixel *newcmap; -static long -encode_maskrow(ofp, rawrow, cols) - FILE *ofp; - rawtype *rawrow; - int cols; -{ - int col; + newcmap = ppm_allocrow(colors); + table = makeValTable(cmapmaxval, maxval); + for (i = 0; i < colors; ++i) + PPM_ASSIGN(newcmap[i], + table[PPM_GETR(colormap[i])], + table[PPM_GETG(colormap[i])], + table[PPM_GETB(colormap[i])]); + free(table); + colormap = newcmap; + } + if( sortcmap ) + ppm_sortcolorrow(colormap, colors, PPM_STDSORT); - for( col = 0; col < cols; col++ ) { - if( maskrow[col] == PBM_BLACK ) - rawrow[col] = 1; + bodysize = oldsize = rows * TOTALPLANES(nPlanes) * RowBytes(cols); + if( DO_COMPRESS ) { + bodysize = doStdBody(ifP, NULL, cols, rows, maxval, colormap, + colors, nPlanes); + if( bodysize > oldsize ) + pm_message("warning - %s compression increases BODY size by %ld%%", + cmpNAME[compmethod], 100*(bodysize-oldsize)/oldsize); else - rawrow[col] = 0; + pm_message("BODY compression (%s): %ld%%", + cmpNAME[compmethod], 100*(oldsize-bodysize)/oldsize); } - return encode_row(ofp, rawrow, cols, 1); -} + cmapsize = colors * 3; + + formsize = + 4 + /* ILBM */ + 4 + 4 + BitMapHeaderSize + /* BMHD size header */ + 4 + 4 + cmapsize + PAD(cmapsize) + /* CMAP size colormap */ + 4 + 4 + bodysize + PAD(bodysize) + /* BODY size data */ + lengthOfTextChunks(); + if( gen_camg ) + formsize += 4 + 4 + CAMGChunkSize; /* CAMG size viewportmodes */ -static int -compress_row(bytes) - int bytes; -{ - int newbytes; + pm_writebiglong(stdout, ID_FORM); + pm_writebiglong(stdout, formsize); + pm_writebiglong(stdout, ID_ILBM); - switch( compmethod ) { - case cmpByteRun1: - newbytes = runbyte1(bytes); - break; - default: - pm_error("compress_row(): unknown compression method %d", - compmethod); - } - store_bodyrow(compr_rowbuf, newbytes); + writeBmhd(cols, rows, nPlanes); + writeTextChunks(); + if( gen_camg ) + writeCamg(); + writeCmap(colormap, colors, maxval); - return newbytes; + /* write body */ + pm_writebiglong(stdout, ID_BODY); + pm_writebiglong(stdout, bodysize); + if( DO_COMPRESS ) + writeBodyRows(); + else + doStdBody(ifP, stdout, cols, rows, maxval, colormap, colors, nPlanes); } -static void -store_bodyrow(row, len) - unsigned char *row; - int len; -{ - int idx = cur_block->used; - if( idx >= ROWS_PER_BLOCK ) { - MALLOCVAR_NOFAIL(cur_block->next); - cur_block = cur_block->next; - cur_block->used = idx = 0; - cur_block->next = NULL; - } - MALLOCARRAY_NOFAIL(cur_block->row[idx], len); - cur_block->len[idx] = len; - memcpy(cur_block->row[idx], row, len); - cur_block->used++; -} - -static void -write_body_rows ARGS((void)) -{ - bodyblock *b; - int i; - long total = 0; +/************ RGB8 ************/ - for( b = &firstblock; b != NULL; b = b->next ) { - for( i = 0; i < b->used; i++ ) { - write_bytes(b->row[i], b->len[i]); - total += b->len[i]; - } - } - if( ODD(total) ) - put_byte(0); -} static void -write_camg ARGS((void)) -{ - put_big_long(ID_CAMG); - put_big_long(CAMGChunkSize); - put_big_long(viewportmodes); -} +ppmToRgb8(FILE * const ifP, + int const cols, + int const rows, + int const maxval) { + long bodysize, oldsize, formsize; + pixel *pP; + int *table = NULL; + int row, col1, col2, compr_len, len; + unsigned char *compr_row; -/************ compression ************/ + maskmethod = 0; /* no masking - RGB8 uses genlock bits */ + compmethod = 4; /* RGB8 files are always compressed */ + MALLOCARRAY_NOFAIL(compr_row, cols * 4); + if( maxval != 255 ) { + pm_message("maxval is not 255 - automatically rescaling colors"); + table = makeValTable(maxval, 255); + } -/* runbyte1 algorithm by Robert A. Knop (rknop@mop.caltech.edu) */ -static int -runbyte1(size) - int size; -{ - int in,out,count,hold; - register unsigned char *inbuf = coded_rowbuf; - register unsigned char *outbuf = compr_rowbuf; - - - in=out=0; - while( in=size-2)&&(in=128 ) - break; + oldsize = cols * rows * 4; + bodysize = 0; + for( row = 0; row < rows; row++ ) { + pP = nextPixrow(ifP, row); + compr_len = 0; + for( col1 = 0; col1 < cols; col1 = col2 ) { + col2 = col1 + 1; + if( maskrow ) { + while( col2 < cols && PPM_EQUAL(pP[col1], pP[col2]) && + maskrow[col1] == maskrow[col2] ) + col2++; + } + else { + while( col2 < cols && PPM_EQUAL(pP[col1], pP[col2]) ) + col2++; + } + len = col2 - col1; + while( len ) { + int count; + count = (len > 127 ? 127 : len); + len -= count; + if( table ) { + compr_row[compr_len++] = table[PPM_GETR(pP[col1])]; + compr_row[compr_len++] = table[PPM_GETG(pP[col1])]; + compr_row[compr_len++] = table[PPM_GETB(pP[col1])]; + } + else { + compr_row[compr_len++] = PPM_GETR(pP[col1]); + compr_row[compr_len++] = PPM_GETG(pP[col1]); + compr_row[compr_len++] = PPM_GETB(pP[col1]); + } + compr_row[compr_len] = count; + if( maskrow && maskrow[col1] == PBM_WHITE ) + compr_row[compr_len] |= 1<<7; /* genlock bit */ + ++compr_len; } - outbuf[hold]=count-1; } + storeBodyrow(compr_row, compr_len); + bodysize += compr_len; } - return(out); -} + pm_message("BODY compression: %ld%%", 100*(oldsize-bodysize)/oldsize); + formsize = + 4 + /* RGB8 */ + 4 + 4 + BitMapHeaderSize + /* BMHD size header */ + 4 + 4 + CAMGChunkSize + /* CAMG size viewportmode */ + 4 + 4 + bodysize + PAD(bodysize) + /* BODY size data */ + lengthOfTextChunks(); -/************ other utility functions ************/ + /* write header */ + pm_writebiglong(stdout, ID_FORM); + pm_writebiglong(stdout, formsize); + pm_writebiglong(stdout, ID_RGB8); -static void -put_big_short(short s) -{ - if ( pm_writebigshort( stdout, s ) == -1 ) - pm_error( "write error" ); + writeBmhd(cols, rows, 25); + writeTextChunks(); + writeCamg(); /* RGB8 requires CAMG chunk */ + + pm_writebiglong(stdout, ID_BODY); + pm_writebiglong(stdout, bodysize); + writeBodyRows(); } -static void -put_big_long(l) - long l; -{ - if ( pm_writebiglong( stdout, l ) == -1 ) - pm_error( "write error" ); -} +/************ RGBN ************/ -static void -write_bytes(buffer, bytes) - unsigned char *buffer; - int bytes; -{ - if( fwrite(buffer, 1, bytes, stdout) != bytes ) - pm_error("write error"); -} -static int * -make_val_table(oldmaxval, newmaxval) - int oldmaxval, newmaxval; -{ - unsigned int i; - int * table; +static void +ppmToRgbn(FILE * const ifP, + int const cols, + int const rows, + int const maxval) { - MALLOCARRAY_NOFAIL(table, oldmaxval + 1); - for (i = 0; i <= oldmaxval; ++i) - table[i] = ROUNDDIV(i * newmaxval, oldmaxval); + long bodysize, oldsize, formsize; + pixel *pP; + int *table = NULL; + int row, col1, col2, compr_len, len; + unsigned char *compr_row; - return table; -} + maskmethod = 0; /* no masking - RGBN uses genlock bits */ + compmethod = 4; /* RGBN files are always compressed */ + MALLOCARRAY_NOFAIL(compr_row, cols * 2); + if( maxval != 15 ) { + pm_message("maxval is not 15 - automatically rescaling colors"); + table = makeValTable(maxval, 15); + } + oldsize = cols * rows * 2; + bodysize = 0; + for( row = 0; row < rows; row++ ) { + pP = nextPixrow(ifP, row); + compr_len = 0; + for( col1 = 0; col1 < cols; col1 = col2 ) { + col2 = col1 + 1; + if( maskrow ) { + while( col2 < cols && PPM_EQUAL(pP[col1], pP[col2]) && + maskrow[col1] == maskrow[col2] ) + col2++; + } + else { + while( col2 < cols && PPM_EQUAL(pP[col1], pP[col2]) ) + col2++; + } + len = col2 - col1; + while( len ) { + int count; + count = (len > 65535 ? 65535 : len); + len -= count; + if( table ) { + compr_row[compr_len] = table[PPM_GETR(pP[col1])] << 4; + compr_row[compr_len] |= table[PPM_GETG(pP[col1])]; + ++compr_len; + compr_row[compr_len] = table[PPM_GETB(pP[col1])] << 4; + } + else { + compr_row[compr_len] = PPM_GETR(pP[col1]) << 4; + compr_row[compr_len] |= PPM_GETG(pP[col1]); + ++compr_len; + compr_row[compr_len] = PPM_GETB(pP[col1]) << 4; + } + if( maskrow && maskrow[col1] == PBM_WHITE ) + compr_row[compr_len] |= 1<<3; /* genlock bit */ + if( count <= 7 ) + compr_row[compr_len++] |= count; /* 3 bit repeat count */ + else { + ++compr_len; /* 3 bit repeat count = 0 */ + if( count <= 255 ) + compr_row[compr_len++] = (unsigned char)count; + /* byte repeat count */ + else { + compr_row[compr_len++] = (unsigned char)0; + /* byte repeat count = 0 */ + compr_row[compr_len++] = (count >> 8) & 0xff; + /* word repeat count MSB */ + compr_row[compr_len++] = count & 0xff; + /* word repeat count LSB */ + } + } + } + } + storeBodyrow(compr_row, compr_len); + bodysize += compr_len; + } -static int gFormat; -static int gCols; -static int gMaxval; + pm_message("BODY compression: %ld%%", 100*(oldsize-bodysize)/oldsize); -static void -init_read(fp, colsP, rowsP, maxvalP, formatP, readall) - FILE *fp; - int *colsP, *rowsP; - pixval *maxvalP; - int *formatP; - int readall; -{ - ppm_readppminit(fp, colsP, rowsP, maxvalP, formatP); + formsize = + 4 + /* RGBN */ + 4 + 4 + BitMapHeaderSize + /* BMHD size header */ + 4 + 4 + CAMGChunkSize + /* CAMG size viewportmode */ + 4 + 4 + bodysize + PAD(bodysize) + /* BODY size data */ + lengthOfTextChunks(); - if( *rowsP >INT16MAX || *colsP >INT16MAX ) - pm_error ("Input image is too large."); + /* write header */ + pm_writebiglong(stdout, ID_FORM); + pm_writebiglong(stdout, formsize); + pm_writebiglong(stdout, ID_RGBN); - if( readall ) { - int row; + writeBmhd(cols, rows, 13); + writeTextChunks(); + writeCamg(); /* RGBN requires CAMG chunk */ - pixels = ppm_allocarray(*colsP, *rowsP); - for( row = 0; row < *rowsP; row++ ) - ppm_readppmrow(fp, pixels[row], *colsP, *maxvalP, *formatP); - /* pixels = ppm_readppm(fp, colsP, rowsP, maxvalP); */ - } - else { - pixrow = ppm_allocrow(*colsP); - } - gCols = *colsP; - gMaxval = *maxvalP; - gFormat = *formatP; + pm_writebiglong(stdout, ID_BODY); + pm_writebiglong(stdout, bodysize); + writeBodyRows(); } -static pixel * -next_pixrow(fp, row) - FILE *fp; - int row; -{ - if( pixels ) - pixrow = pixels[row]; - else { - ppm_readppmrow(fp, pixrow, gCols, gMaxval, gFormat); + +/************ multipalette ************/ + + + +#ifdef ILBM_PCHG +static pixel *ppmslice[2]; /* need 2 for laced ILBMs, else 1 */ + +void +ppmToPchg() { +/* + read first slice + build a colormap from this slice + select up to colors + build colormap from selected colors + map slice to colormap + write slice + while( !finished ) { + read next slice + compute distances for each pixel and select up to + unused colors in this slice + modify selected colors to the ones with maximum(?) distance + map slice to colormap + write slice } - if( maskrow ) { - int col; - if( maskfile ) - pbm_readpbmrow(maskfile, maskrow, maskcols, maskformat); - else { - for( col = 0; col < gCols; col++ ) - maskrow[col] = PBM_BLACK; - } - if( transpColor ) { - for( col = 0; col < gCols; col++ ) - if( PPM_EQUAL(pixrow[col], *transpColor) ) - maskrow[col] = PBM_WHITE; + + for HAM use a different mapping: + compute distance to closest color in colormap + if( there is no matching color in colormap ) { + compute distances for the three "modify" cases + use the shortest distance from the four cases } - } - return pixrow; +*/ } +#endif @@ -1902,7 +1906,7 @@ main(int argc, char ** argv) { pm_keymatch(argv[argn], "-mp", 3) ) { if( ++argn >= argc ) pm_error("-maxplanes requires a value"); - maxplanes = get_int_val(argv[argn], argv[argn-1], 1, MAXPLANES); + maxplanes = getIntVal(argv[argn], argv[argn-1], 1, MAXPLANES); fixplanes = 0; } else @@ -1910,7 +1914,7 @@ main(int argc, char ** argv) { pm_keymatch(argv[argn], "-fp", 3) ) { if( ++argn >= argc ) pm_error("-fixplanes requires a value"); - fixplanes = get_int_val(argv[argn], argv[argn-1], 1, MAXPLANES); + fixplanes = getIntVal(argv[argn], argv[argn-1], 1, MAXPLANES); maxplanes = fixplanes; } else @@ -1923,7 +1927,7 @@ main(int argc, char ** argv) { if( pm_keymatch(argv[argn], "-mmethod", 3) ) { if( ++argn >= argc ) pm_error("-mmethod requires a value"); - maskmethod = get_mask_type(argv[argn]); + maskmethod = getMaskType(argv[argn]); switch( maskmethod ) { case mskNone: case mskHasMask: @@ -1985,7 +1989,8 @@ main(int argc, char ** argv) { if( ++argn >= argc ) pm_error("-camg requires a value"); value = strtol(argv[argn], &tail, 16); - /* TODO: should do some error checking here */ + if(argv[argn] == tail) + pm_error("-camg requires a value"); viewportmodes |= value; gen_camg = 1; } @@ -2003,14 +2008,14 @@ main(int argc, char ** argv) { if( pm_keymatch(argv[argn], "-hamplanes", 5) ) { if( ++argn >= argc ) pm_error("-hamplanes requires a value"); - hamplanes = get_int_val(argv[argn], argv[argn-1], 3, HAMMAXPLANES); + hamplanes = getIntVal(argv[argn], argv[argn-1], 3, HAMMAXPLANES); } else if( pm_keymatch(argv[argn], "-hambits", 5) ) { if( ++argn >= argc ) pm_usage("-hambits requires a value"); hamplanes = - get_int_val(argv[argn], argv[argn-1], 3, HAMMAXPLANES-2) +2; + getIntVal(argv[argn], argv[argn-1], 3, HAMMAXPLANES-2) +2; } else if( pm_keymatch(argv[argn], "-ham6", 5) ) { @@ -2026,7 +2031,7 @@ main(int argc, char ** argv) { if( pm_keymatch(argv[argn], "-hammap", 5) ) { if( ++argn >= argc ) pm_error("-hammap requires a value"); - hammapmode = get_hammap_mode(argv[argn]); + hammapmode = getHammapMode(argv[argn]); } else if( pm_keymatch(argv[argn], "-hamif", 5) ) @@ -2068,7 +2073,7 @@ main(int argc, char ** argv) { if( pm_keymatch(argv[argn], "-deepplanes", 6) ) { if( ++argn >= argc ) pm_error("-deepplanes requires a value"); - deepbits = get_int_val(argv[argn], argv[argn-1], 3, 3*MAXPLANES); + deepbits = getIntVal(argv[argn], argv[argn-1], 3, 3*MAXPLANES); if( deepbits % 3 != 0 ) pm_error("option \"%s\" argument value must be divisible by 3", argv[argn-1]); @@ -2078,7 +2083,7 @@ main(int argc, char ** argv) { if( pm_keymatch(argv[argn], "-deepbits", 6) ) { if( ++argn >= argc ) pm_error("-deepbits requires a value"); - deepbits = get_int_val(argv[argn], argv[argn-1], 1, MAXPLANES); + deepbits = getIntVal(argv[argn], argv[argn-1], 1, MAXPLANES); } else if( pm_keymatch(argv[argn], "-deepif", 6) ) @@ -2117,9 +2122,9 @@ main(int argc, char ** argv) { pm_keymatch(argv[argn], "-dcplanes", 4) ) { if( argc - argn < 4 ) pm_error("-dcbits requires 4 arguments"); - dcol.r = get_int_val(argv[argn+1], argv[argn], 1, MAXPLANES); - dcol.g = get_int_val(argv[argn+2], argv[argn], 1, MAXPLANES); - dcol.b = get_int_val(argv[argn+3], argv[argn], 1, MAXPLANES); + dcol.r = getIntVal(argv[argn+1], argv[argn], 1, MAXPLANES); + dcol.g = getIntVal(argv[argn+2], argv[argn], 1, MAXPLANES); + dcol.b = getIntVal(argv[argn+3], argv[argn], 1, MAXPLANES); argn += 3; } else @@ -2146,7 +2151,7 @@ main(int argc, char ** argv) { if( pm_keymatch(argv[argn], "-cmethod", 4) ) { if( ++argn >= argc ) pm_error("-cmethod requires a value"); - compmethod = get_compr_method(argv[argn]); + compmethod = getComprMethod(argv[argn]); } else if( pm_keymatch(argv[argn], "-floyd", 3) || @@ -2205,22 +2210,22 @@ main(int argc, char ** argv) { switch(forcemode) { case MODE_HAM: if (hammapmode == HAMMODE_RGB4 || hammapmode == HAMMODE_RGB5) - init_read(ifP, &cols, &rows, &maxval, &format, 1); + initRead(ifP, &cols, &rows, &maxval, &format, 1); else - init_read(ifP, &cols, &rows, &maxval, &format, 0); + initRead(ifP, &cols, &rows, &maxval, &format, 0); break; case MODE_DCOL: case MODE_DEEP: mapfile = NULL; - init_read(ifP, &cols, &rows, &maxval, &format, 0); + initRead(ifP, &cols, &rows, &maxval, &format, 0); break; case MODE_RGB8: mapfile = NULL; - init_read(ifP, &cols, &rows, &maxval, &format, 0); + initRead(ifP, &cols, &rows, &maxval, &format, 0); break; case MODE_RGBN: mapfile = NULL; - init_read(ifP, &cols, &rows, &maxval, &format, 0); + initRead(ifP, &cols, &rows, &maxval, &format, 0); break; case MODE_CMAP: /* Figure out the colormap. */ @@ -2234,9 +2239,9 @@ main(int argc, char ** argv) { break; default: if (mapfile) - init_read(ifP, &cols, &rows, &maxval, &format, 0); + initRead(ifP, &cols, &rows, &maxval, &format, 0); else { - init_read(ifP, &cols, &rows, &maxval, &format, 1); + initRead(ifP, &cols, &rows, &maxval, &format, 1); /* read file into memory */ pm_message("computing colormap..."); colormap = @@ -2250,7 +2255,7 @@ main(int argc, char ** argv) { nPlanes = fixplanes; } else { /* too many colors */ mode = ifmode; - report_too_many_colors(ifmode, maxplanes, hamplanes, + reportTooManyColors(ifmode, maxplanes, hamplanes, dcol, deepbits ); } } @@ -2294,37 +2299,40 @@ main(int argc, char ** argv) { for (i = 0; i < RowBytes(cols); ++i) coded_rowbuf[i] = 0; if (DO_COMPRESS) - MALLOCARRAY_NOFAIL(compr_rowbuf, WORSTCOMPR(RowBytes(cols))); + pm_rlenc_allocoutbuf(&compr_rowbuf, RowBytes(cols), PM_RLE_PACKBITS); } switch (mode) { case MODE_HAM: viewportmodes |= vmHAM; - ppm_to_ham(ifP, cols, rows, maxval, - colormap, colors, cmapmaxval, hamplanes); + ppmToHam(ifP, cols, rows, maxval, + colormap, colors, cmapmaxval, hamplanes); break; case MODE_DEEP: - ppm_to_deep(ifP, cols, rows, maxval, deepbits); + ppmToDeep(ifP, cols, rows, maxval, deepbits); break; case MODE_DCOL: - ppm_to_dcol(ifP, cols, rows, maxval, &dcol); + ppmToDcol(ifP, cols, rows, maxval, &dcol); break; case MODE_RGB8: - ppm_to_rgb8(ifP, cols, rows, maxval); + ppmToRgb8(ifP, cols, rows, maxval); break; case MODE_RGBN: - ppm_to_rgbn(ifP, cols, rows, maxval); + ppmToRgbn(ifP, cols, rows, maxval); break; case MODE_CMAP: - ppm_to_cmap(colormap, colors, cmapmaxval); + ppmToCmap(colormap, colors, cmapmaxval); break; default: if (mapfile == NULL) floyd = 0; /* would only slow down conversion */ - ppm_to_std(ifP, cols, rows, maxval, colormap, colors, - cmapmaxval, MAXCOLORS, nPlanes); + ppmToStd(ifP, cols, rows, maxval, colormap, colors, + cmapmaxval, MAXCOLORS, nPlanes); break; } pm_close(ifP); return 0; } + + + diff --git a/converter/ppm/ppmtompeg/BUGS b/converter/ppm/ppmtompeg/BUGS index 64269dfb..9724014e 100644 --- a/converter/ppm/ppmtompeg/BUGS +++ b/converter/ppm/ppmtompeg/BUGS @@ -14,7 +14,7 @@ Known BUGS: REFERENCE_FRAME DECODED does not work -5. Cannot use both STDIN and CDL_FILEs (ok, since it doesnt make sense...) +5. Cannot use both STDIN and CDL_FILEs (ok, since it doesn't make sense...) 6. diff --git a/converter/ppm/ppmtompeg/CHANGES b/converter/ppm/ppmtompeg/CHANGES index fffa7a65..efb8fdcf 100644 --- a/converter/ppm/ppmtompeg/CHANGES +++ b/converter/ppm/ppmtompeg/CHANGES @@ -28,7 +28,7 @@ Changes chronology - non-integer frame rates now work for all machines - fixed parsing of -mv_histogram - fixed numPadding bug (file name problem) - - fixed full pixel assertation bug + - fixed full pixel assertion bug - corrected ASPECT_RATIO bug (was forced to 1) - buffer size is now set correctly - complains when file is too small diff --git a/converter/ppm/ppmtompeg/Makefile b/converter/ppm/ppmtompeg/Makefile index a1004fdd..eeab9727 100644 --- a/converter/ppm/ppmtompeg/Makefile +++ b/converter/ppm/ppmtompeg/Makefile @@ -31,14 +31,17 @@ endif # 1) long's are 32 bits and # 2) int's are not # -# if you are using a non-ANSI compiler, then use: -# -DNON_ANSI_COMPILER -# # one other option: # -DHEINOUS_DEBUG_MODE # -MP_BASE_OBJS = mfwddct.o postdct.o huff.o bitio.o mheaders.o +MP_BASE_OBJS = \ + mfwddct.o \ + postdct.o \ + huff.o \ + bitio.o \ + mheaders.o \ + MP_ENCODE_OBJS = \ frames.o \ iframe.o \ @@ -46,12 +49,25 @@ MP_ENCODE_OBJS = \ bframe.o \ psearch.o \ bsearch.o \ - block.o - -MP_OTHER_OBJS = mpeg.o subsample.o param.o rgbtoycc.o \ - readframe.o combine.o jrevdct.o frame.o fsize.o frametype.o \ - specifics.o rate.o opts.o input.o -ifeq ($(OMIT_NETWORK),y) + block.o \ + +MP_OTHER_OBJS = \ + mpeg.o \ + subsample.o \ + param.o \ + rgbtoycc.o \ + readframe.o \ + combine.o \ + jrevdct.o \ + frame.o \ + fsize.o \ + frametype.o \ + specifics.o \ + rate.o \ + opts.o \ + input.o \ + +ifeq ($(OMIT_NETWORK),Y) MP_OTHER_OBJS += noparallel.o else MP_OTHER_OBJS += parallel.o psocket.o @@ -62,14 +78,19 @@ else MP_OTHER_OBJS += gethostname.o endif -NONMAIN_OBJS = $(MP_BASE_OBJS) $(MP_OTHER_OBJS) $(MP_ENCODE_OBJS) \ - $(JPEG_MODULE).o -OBJECTS = ppmtompeg.o $(NONMAIN_OBJS) -MERGE_OBJECTS = ppmtompeg.o2 $(NONMAIN_OBJS) +ADDL_OBJECTS = \ + $(MP_BASE_OBJS) \ + $(MP_OTHER_OBJS) \ + $(MP_ENCODE_OBJS) \ + $(JPEG_MODULE).o \ + +OBJECTS = ppmtompeg.o $(ADDL_OBJECTS) +MERGE_OBJECTS = ppmtompeg.o2 $(ADDL_OBJECTS) MP_INCLUDE = mproto.h mtypes.h huff.h bitio.h MP_MISC = Makefile huff.table parse_huff.pl -BINARIES = ppmtompeg +PORTBINARIES = ppmtompeg +BINARIES = $(PORTBINARIES) MERGEBINARIES = $(BINARIES) SCRIPTS = @@ -84,18 +105,14 @@ else LIBOPTR = endif -ppmtompeg: $(OBJECTS) $(NETPBMLIB) $(LIBOPT) - $(LD) -o $@ \ - $(OBJECTS) $(shell $(LIBOPT) $(NETPBMLIB) $(LIBOPTR) $(JPEGLIBX)) \ - $(NETWORKLD) $(MATHLIB) $(LDFLAGS) $(LDLIBS) \ - $(RPATH) $(LADD) - -profile: $(OBJECTS) $(NETPBMLIB) $(LIBOPT) - $(LD) -o $@ -Bstatic -pg \ - $(OBJECTS) $(shell $(LIBOPT) $(NETPBMLIB) $(LIBOPTR) $(JPEGLIBX)) \ - $(NETWORKLD) $(MATHLIB) $(LDFLAGS) $(LDLIBS) \ - $(RPATH) $(LADD) +ppmtompeg: $(ADDL_OBJECTS) $(LIBOPT) +ppmtompeg: LDFLAGS_TARGET = \ + $(shell $(LIBOPT) $(LIBOPTR) $(JPEGLIBX)) $(NETWORKLD) +profile: $(ADDL_OBJECTS) $(LIBOPT) +profile: LDFLAGS_TARGET = \ + -Bstatic -pg \ + $(shell $(LIBOPT) $(LIBOPTR) $(JPEGLIBX)) $(NETWORKLD) ######### # OTHER # diff --git a/converter/ppm/ppmtompeg/bframe.c b/converter/ppm/ppmtompeg/bframe.c index 1dbc1846..f5009d6c 100644 --- a/converter/ppm/ppmtompeg/bframe.c +++ b/converter/ppm/ppmtompeg/bframe.c @@ -523,7 +523,7 @@ makeNonSkipBlock(int const y, MpegFrame * const curr, MpegFrame * const prev, MpegFrame * const next, - boolean const specificsOn, + bool const specificsOn, int const mbAddress, int const QScale, const LumBlock * const currentBlockP, diff --git a/converter/ppm/ppmtompeg/bitio.c b/converter/ppm/ppmtompeg/bitio.c index e0dc4d4e..3812bc39 100644 --- a/converter/ppm/ppmtompeg/bitio.c +++ b/converter/ppm/ppmtompeg/bitio.c @@ -244,8 +244,8 @@ Bitio_Write(BitBucket * const bbPtr, assert(nbits <= 32 && nbits >= 0); /* - * Clear top bits if not part of data, necessary due to down and - * dirty calls of Bitio_Write with unecessary top bits set. + * Clear top bits if not part of data, necessary because of down and + * dirty calls of Bitio_Write with unnecessary top bits set. */ bits &= lower_mask[nbits]; diff --git a/converter/ppm/ppmtompeg/bsearch.c b/converter/ppm/ppmtompeg/bsearch.c index 70edfef6..c618bbd4 100644 --- a/converter/ppm/ppmtompeg/bsearch.c +++ b/converter/ppm/ppmtompeg/bsearch.c @@ -43,7 +43,7 @@ * Changed copyrights * * Revision 1.6 1994/12/07 00:40:36 smoot - * Added seperate P and B search ranges + * Added separate P and B search ranges * * Revision 1.5 1994/03/15 00:27:11 keving * nothing @@ -834,7 +834,6 @@ BMotionSearchCross2(const LumBlock * const currentBlockP, interpErrF = FindBestMatch(&forwardBlock, currentBlockP, next, by, bx, &newMotion.bwd, bestErr, searchRangeB); - bestErr = min(bestErr, interpErr); interpErrB = FindBestMatch(&backBlock, currentBlockP, prev, by, bx, &newMotion.fwd, bestErr, searchRangeB); diff --git a/converter/ppm/ppmtompeg/combine.c b/converter/ppm/ppmtompeg/combine.c index 8e0d3281..c00f9c71 100644 --- a/converter/ppm/ppmtompeg/combine.c +++ b/converter/ppm/ppmtompeg/combine.c @@ -104,7 +104,7 @@ appendSpecifiedGopFiles(struct inputSource * const inputSourceP, FILE * ifP; GetNthInputFileName(inputSourceP, fileSeq, &inputFileName); - asprintfN(&fileName, "%s/%s", currentGOPPath, inputFileName); + pm_asprintf(&fileName, "%s/%s", currentGOPPath, inputFileName); for (nAttempts = 0, ifP = NULL; nAttempts < READ_ATTEMPTS && !ifP; @@ -122,8 +122,8 @@ appendSpecifiedGopFiles(struct inputSource * const inputSourceP, } else pm_error("Unable to read file '%s' after %u attempts.", fileName, READ_ATTEMPTS); - strfree(fileName); - strfree(inputFileName); + pm_strfree(fileName); + pm_strfree(inputFileName); } } @@ -140,7 +140,7 @@ appendDefaultGopFiles(const char * const outputFileName, const char * fileName; FILE * ifP; - asprintfN(&fileName, "%s.gop.%u", outputFileName, fileSeq); + pm_asprintf(&fileName, "%s.gop.%u", outputFileName, fileSeq); ifP = fopen(fileName, "rb"); if (ifP == NULL) @@ -151,7 +151,7 @@ appendDefaultGopFiles(const char * const outputFileName, AppendFile(ofP, ifP); } - strfree(fileName); + pm_strfree(fileName); } } diff --git a/converter/ppm/ppmtompeg/docs/template.param b/converter/ppm/ppmtompeg/docs/template.param index 66b6dd98..78ad5300 100644 --- a/converter/ppm/ppmtompeg/docs/template.param +++ b/converter/ppm/ppmtompeg/docs/template.param @@ -18,7 +18,7 @@ # files in the order in which they must appear, followed by 'END_INPUT' # # Also, if you use the `command` method of generating input file names, -# the command will only be executed in the INPUT_DIR if INPUT_DIR preceeds +# the command will only be executed in the INPUT_DIR if INPUT_DIR precedes # the INPUT parameter. # # ]\n\ [-dir] [-lib|-Lib ]\n\ [-xsize|-width ] [-ysize|-height ] [sldfile]"; - int scalespec = FALSE, widspec = FALSE, hgtspec = FALSE, dironly = FALSE, - ucasen; + bool dironly; + bool hgtspec; + bool widspec; + bool scalespec; + bool ucasen; const char * slobber; /* Slide library item */ + pm_proginit(&argc, argv); + argn = 1; slobber = NULL; - - ppm_init(&argc, argv); - argn = 1; + dironly = false; + hgtspec = false; + widspec = false; + scalespec = false; + ucasen = false; + blither = false; + info = false; + adjust = false; while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') { if (pm_keymatch(argv[argn], "-verbose", 2)) { - blither = TRUE; + blither = true; } else if (pm_keymatch(argv[argn], "-adjust", 2)) { - adjust = TRUE; + adjust = true; } else if (pm_keymatch(argv[argn], "-dir", 2)) { - dironly = TRUE; + dironly = true; } else if (pm_keymatch(argv[argn], "-info", 2)) { - info = TRUE; + info = true; } else if (pm_keymatch(argv[argn], "-lib", 2)) { if (slobber) pm_error("already specified a library item"); @@ -616,7 +635,7 @@ main(int argc, if (uscale <= 0.0) { pm_error("scale factor must be greater than 0"); } - scalespec = TRUE; + scalespec = true; } else if (pm_keymatch(argv[argn], "-xsize", 2) || pm_keymatch(argv[argn], "-width", 2)) { if (widspec) { @@ -625,7 +644,7 @@ main(int argc, argn++; if ((argn == argc) || (sscanf(argv[argn], "%d", &sxsize) != 1)) pm_usage(usage); - widspec = TRUE; + widspec = true; } else if (pm_keymatch(argv[argn], "-ysize", 2) || pm_keymatch(argv[argn], "-height", 2)) { if (hgtspec) { @@ -634,7 +653,7 @@ main(int argc, argn++; if ((argn == argc) || (sscanf(argv[argn], "%d", &sysize) != 1)) pm_usage(usage); - hgtspec = TRUE; + hgtspec = true; } else { pm_usage(usage); } @@ -665,7 +684,7 @@ main(int argc, if (!dironly) { slider(draw, flood); - ppm_writeppm(stdout, pixels, pixcols, pixrows, pixmaxval, FALSE); + ppm_writeppm(stdout, pixels, pixcols, pixrows, pixmaxval, 0); } pm_close(slfile); pm_close(stdout); diff --git a/converter/ppm/sputoppm.c b/converter/ppm/sputoppm.c index 2671bffa..acf61c1b 100644 --- a/converter/ppm/sputoppm.c +++ b/converter/ppm/sputoppm.c @@ -1,4 +1,4 @@ -/* sputoppm.c - read an uncompressed Spectrum file and produce a portable pixmap +/* sputoppm.c - read an uncompressed Spectrum file and produce a PPM ** ** Copyright (C) 1991 by Steve Belczyk and Jef Poskanzer ** @@ -16,93 +16,114 @@ #define COLS 320 #define MAXVAL 7 -static pixel pal[ROWS][48]; /* Spectrum palettes, three per row */ -static short screen[ROWS*COLS/4]; /* simulates the Atari's video RAM */ -int -main( argc, argv ) - int argc; - char* argv[]; +typedef struct { + pixel pal[ROWS][48]; /* Spectrum palettes, three per row */ +} Pal; + + + +static void +readPalettes(FILE * const ifP, + Pal * const palP) { + + unsigned int row; + + /* Clear the first palette line. */ { - FILE* ifp; - int i, j; - pixel* pixelrow; - register pixel* pP; - int row, col; + unsigned int j; + for (j = 0; j < 48; ++j) + PPM_ASSIGN(palP->pal[0][j], 0, 0, 0); + } + /* Read the palettes. */ + for (row = 1; row < ROWS; ++row) { + unsigned int j; + for (j = 0; j < 48; ++j) { + short k; + pm_readbigshort(ifP, &k); + PPM_ASSIGN(palP->pal[row][j], + (k & 0x700) >> 8, + (k & 0x070) >> 4, + (k & 0x007) >> 0); + } + } +} + + + +int +main(int argc, const char ** argv) { + FILE * ifP; + unsigned int i; + pixel * pixelrow; + unsigned int row; + Pal pal; + short screen[ROWS*COLS/4]; /* simulates the Atari's video RAM */ - ppm_init( &argc, argv ); + pm_proginit(&argc, argv); /* Check args. */ if ( argc > 2 ) pm_usage( "[spufile]" ); if ( argc == 2 ) - ifp = pm_openr( argv[1] ); + ifP = pm_openr( argv[1] ); else - ifp = stdin; + ifP = stdin; /* Read the SPU file */ /* Read the screen data. */ - for ( i = 0; i < ROWS*COLS/4; ++i ) - (void) pm_readbigshort( ifp, &screen[i] ); - - /* Clear the first palette line. */ - for ( j = 0; j < 48; ++j ) - PPM_ASSIGN( pal[0][j], 0, 0, 0 ); + for (i = 0; i < ROWS*COLS/4; ++i) + pm_readbigshort(ifP, &screen[i]); - /* Read the palettes. */ - for ( i = 1; i < ROWS; ++i ) - for ( j = 0; j < 48; ++j ) - { - short k; - (void) pm_readbigshort( ifp, &k ); - PPM_ASSIGN( pal[i][j], - ( k & 0x700 ) >> 8, - ( k & 0x070 ) >> 4, - ( k & 0x007 ) ); - } + readPalettes(ifP, &pal); - pm_close( ifp ); + pm_close(ifP); /* Ok, get set for writing PPM. */ - ppm_writeppminit( stdout, COLS, ROWS, (pixval) MAXVAL, 0 ); - pixelrow = ppm_allocrow( COLS ); + ppm_writeppminit(stdout, COLS, ROWS, MAXVAL, 0); + pixelrow = ppm_allocrow(COLS); /* Now do the conversion. */ - for ( row = 0; row < ROWS; ++row ) - { - for ( col = 0, pP = pixelrow; col < COLS; ++col, ++pP ) - { - int c, ind, b, plane, x1; - + for (row = 0; row < ROWS; ++row) { + unsigned int col; + for (col = 0; col < COLS; ++col) { /* Compute pixel value. */ - ind = 80 * row + ( ( col >> 4 ) << 2 ); - b = 0x8000 >> (col & 0xf); - c = 0; - for ( plane = 0; plane < 4; ++plane ) - if ( b & screen[ind+plane] ) + unsigned int const ind = 80 * row + ((col >> 4) << 2); + unsigned int const b = 0x8000 >> (col & 0xf); + unsigned int c; + unsigned int plane; + unsigned int x1; + + c = 0; /* initial value */ + for (plane = 0; plane < 4; ++plane) { + if (b & screen[ind + plane]) c |= (1 << plane); - + } /* Compute palette index. */ x1 = 10 * c; - if ( c & 1 ) + if ((c & 1) != 0) x1 -= 5; else ++x1; - if ( ( col >= x1 ) && ( col < ( x1 + 160 ) ) ) + if ((col >= x1 ) && (col < (x1 + 160))) c += 16; - if ( col >= ( x1 + 160 ) ) + if (col >= (x1 + 160)) c += 32; - /* Store the proper color. */ - *pP = pal[row][c]; - } - ppm_writeppmrow( stdout, pixelrow, COLS, (pixval) MAXVAL, 0 ); + /* Set the proper color. */ + pixelrow[col] = pal.pal[row][c]; } + ppm_writeppmrow(stdout, pixelrow, COLS, MAXVAL, 0); + } + + ppm_freerow(pixelrow); + pm_close(stdout); + + return 0; +} + - pm_close( stdout ); - exit( 0 ); - } diff --git a/converter/ppm/tgatoppm.c b/converter/ppm/tgatoppm.c index f8538214..95893089 100644 --- a/converter/ppm/tgatoppm.c +++ b/converter/ppm/tgatoppm.c @@ -71,7 +71,7 @@ parseCommandLine(int argc, char ** argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (argc - 1 == 0) diff --git a/converter/ppm/winicontoppm.c b/converter/ppm/winicontoppm.c index ad859c94..6b1376b2 100644 --- a/converter/ppm/winicontoppm.c +++ b/converter/ppm/winicontoppm.c @@ -31,10 +31,9 @@ #define MAJVERSION 0 #define MINVERSION 4 -static int file_offset = 0; /* not actually used, but useful for debug */ +static int fileOffset = 0; /* not actually used, but useful for debug */ static const char er_read[] = "%s: read error"; static const char * infname; -static FILE * ifp; struct cmdlineInfo { /* All the information the user supplied in the command line, @@ -53,8 +52,8 @@ struct cmdlineInfo { static void -parseCommandLine ( int argc, char ** argv, - struct cmdlineInfo *cmdlineP ) { +parseCommandLine (int argc, const char ** argv, + struct cmdlineInfo *cmdlineP ) { /*---------------------------------------------------------------------------- parse program command line described in Unix standard form by argc and argv. Return the information in the options as *cmdlineP. @@ -65,13 +64,15 @@ parseCommandLine ( int argc, char ** argv, Note that the strings we return are stored in the storage that was passed to us as the argv array. We also trash *argv. -----------------------------------------------------------------------------*/ - optEntry *option_def = malloc(100*sizeof(optEntry)); - /* Instructions to optParseOptions3 on how to parse our options. + optEntry * option_def; + /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; unsigned int option_def_index; + MALLOCARRAY(option_def, 100); + option_def_index = 0; /* incremented by OPTENT3 */ OPTENT3(0, "allicons", OPT_FLAG, NULL, &cmdlineP->allicons, 0 ); @@ -88,10 +89,9 @@ parseCommandLine ( int argc, char ** argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3( &argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ - if (argc-1 < 1) cmdlineP->inputFilespec = "-"; else @@ -116,37 +116,37 @@ parseCommandLine ( int argc, char ** argv, static int -GetByte(void) { +GetByte(FILE * const ifP) { + int v; - if ((v = getc(ifp)) == EOF) - { + v = getc(ifP); + if (v == EOF) pm_error(er_read, infname); - } return v; } + + static short -GetShort(void) { +GetShort(FILE * const ifP) { + short v; - if (pm_readlittleshort(ifp, &v) == -1) - { - pm_error(er_read, infname); - } - + pm_readlittleshort(ifP, &v); + return v; } + + static long -GetLong(void) { +GetLong(FILE * const ifP) { + long v; - if (pm_readlittlelong(ifp, &v) == -1) - { - pm_error(er_read, infname); - } + pm_readlittlelong(ifP, &v); return v; } @@ -158,14 +158,18 @@ GetLong(void) { * functions. */ static u1 -readU1 (void) { - file_offset++; - return GetByte(); +readU1(FILE * const ifP) { + + ++fileOffset; + + return GetByte(ifP); } + + static u1 * -readU1String (int length) -{ +readU1String (FILE * const ifP, + unsigned int const length) { u1 * string; @@ -173,150 +177,173 @@ readU1String (int length) if (string == NULL) pm_error("out of memory"); - fread(string,sizeof(u1),length,ifp); + fread(string, sizeof(u1), length, ifP); string[length] = 0; - file_offset += length * sizeof(u1); + fileOffset += length * sizeof(u1); + return string; } + + static u2 -readU2 (void) { - file_offset +=2; - return GetShort(); +readU2 (FILE * const ifP) { + + fileOffset +=2; + + return GetShort(ifP); } + + static u4 -readU4 (void) { - file_offset += 4; - return GetLong(); +readU4 (FILE * const ifP) { + + fileOffset += 4; + + return GetLong(ifP); } + + static IC_Entry -readICEntry (void) -{ - IC_Entry entry; +readICEntry(FILE * const ifP) { + + IC_Entry entryP; - MALLOCVAR(entry); + MALLOCVAR(entryP); - if (entry == NULL) + if (entryP == NULL) pm_error("Unable to allcoate memory for IC entry"); - entry->width = readU1(); - entry->height = readU1(); - entry->color_count = readU1(); - entry->reserved = readU1(); - entry->planes = readU2(); - entry->bitcount = readU2(); - entry->size_in_bytes = readU4(); - entry->file_offset = readU4(); - entry->colors = NULL; - entry->ih = NULL; - entry->xorBitmap = NULL; - entry->andBitmap = NULL; + entryP->width = readU1(ifP); + entryP->height = readU1(ifP); + entryP->color_count = readU1(ifP); + entryP->reserved = readU1(ifP); + entryP->planes = readU2(ifP); + entryP->bitcount = readU2(ifP); + entryP->size_in_bytes = readU4(ifP); + entryP->file_offset = readU4(ifP); + entryP->colors = NULL; + entryP->ih = NULL; + entryP->xorBitmap = NULL; + entryP->andBitmap = NULL; - return entry; + return entryP; } static IC_InfoHeader -readInfoHeader (IC_Entry entry) -{ - IC_InfoHeader ih; +readInfoHeader (FILE * const ifP, + IC_Entry const entryP) { + + IC_InfoHeader ihP; - MALLOCVAR(ih); + MALLOCVAR(ihP); - if (ih == NULL) + if (ihP == NULL) pm_error("Unable to allocate memory for info header"); - ih->size = readU4(); - ih->width = readU4(); - ih->height = readU4(); - ih->planes = readU2(); - ih->bitcount = readU2(); - ih->compression = readU4(); - ih->imagesize = readU4(); - ih->x_pixels_per_m = readU4(); - ih->y_pixels_per_m = readU4(); - ih->colors_used = readU4(); - ih->colors_important = readU4(); + ihP->size = readU4(ifP); + ihP->width = readU4(ifP); + ihP->height = readU4(ifP); + ihP->planes = readU2(ifP); + ihP->bitcount = readU2(ifP); + ihP->compression = readU4(ifP); + ihP->imagesize = readU4(ifP); + ihP->x_pixels_per_m = readU4(ifP); + ihP->y_pixels_per_m = readU4(ifP); + ihP->colors_used = readU4(ifP); + ihP->colors_important = readU4(ifP); - if (!entry->bitcount) entry->bitcount = ih->bitcount; - if (entry->color_count == 0 && - entry->bitcount <= 8) entry->color_count = 256; - if (ih->compression) { + if (!entryP->bitcount) + entryP->bitcount = ihP->bitcount; + + if (entryP->color_count == 0 && entryP->bitcount <= 8) + entryP->color_count = 256; + + if (ihP->compression) { pm_error("Can't handle compressed icons"); } - return ih; + return ihP; } -/* - * I don't know why this isn't the same as the spec, it just isn't - * The colors honestly seem to be stored BGR. Bizarre. - * - * I've checked this in the BMP code for bmptoppm and the gimp. Guess the - * spec I have is just plain wrong. - */ + + static IC_Color -readICColor (void) -{ - IC_Color col; +readICColor(FILE * const ifP) { + + IC_Color colorP; - MALLOCVAR(col); + MALLOCVAR(colorP); - if (col == NULL) + if (colorP == NULL) pm_error("Unable to allocate memory for color"); - col->blue = readU1(); - col->green = readU1(); - col->red = readU1(); - col->reserved = readU1(); - return col; + /* I don't know why this isn't the same as the spec, it just isn't. + The colors honestly seem to be stored BGR. Bizarre. + + I've checked this in the BMP code for bmptoppm and the gimp. Guess the + spec I have is just plain wrong. + */ + + colorP->blue = readU1(ifP); + colorP->green = readU1(ifP); + colorP->red = readU1(ifP); + colorP->reserved = readU1(ifP); + + return colorP; } -/* - * Depending on if the image is stored as 1bpp, 4bpp or 8bpp, the - * encoding mechanism is different. - * - * 8bpp => 1 byte/palette index. - * 4bpp => High Nibble, Low Nibble - * 1bpp => 1 palette value per bit, high bit 1st. - */ static u1 * -read1Bitmap (int width, int height) -{ - int tmp; - int xBytes; +read1Bitmap (FILE * const ifP, + unsigned int const width, + unsigned int const height) { + + unsigned int row; + unsigned int xByteCt; u1 * bitmap; - int wt = width; + unsigned int wt; MALLOCARRAY(bitmap, width * height); if (bitmap == NULL) pm_error("out of memory"); - wt >>= 3; - if (wt & 3) { - wt = (wt & ~3) + 4; + /* Depending on if the image is stored as 1bpp, 4bpp or 8bpp, the + encoding mechanism is different. + + 8bpp => 1 byte/palette index. + 4bpp => High Nibble, Low Nibble + 1bpp => 1 palette value per bit, high bit 1st. + */ + + wt = width >> 3; + + if ((wt & 0x3) != 0) { + wt = (wt & ~0x3) + 4; } - xBytes = wt; - for (tmp = 0; tmp>= 1; - } } - free(row); + free(imgRow); } return bitmap; } @@ -324,43 +351,46 @@ read1Bitmap (int width, int height) static u1 * -read4Bitmap (int width, int height) -{ - int tmp; +read4Bitmap (FILE * const ifP, + unsigned int const width, + unsigned int const height) { + + unsigned int row; u1 * bitmap; - int wt = width; - int xBytes; + unsigned int wt; + unsigned int xByteCt; MALLOCARRAY(bitmap, width * height); if (bitmap == NULL) pm_error("out of memory"); + wt = width >> 1; - wt >>= 1; - if (wt & 3) { - wt = (wt & ~3) + 4; + if (wt & 0x3) { + wt = (wt & ~0x3) + 4; } - xBytes = wt; - for (tmp = 0; tmp> 4; + *(bitmap + ((height - row - 1) * width) + col) = + (imgRow[rowByte] & 0xF0) >> 4; } else { - *(bitmap+((height-tmp-1)*width) + (x)) = (row[rowByte] & 0xF); - rowByte++; + *(bitmap + ((height - row -1) * width) + col) = + (imgRow[rowByte] & 0xF); + ++rowByte; } bottom = !bottom; } - free(row); + free(imgRow); } return bitmap; } @@ -368,52 +398,57 @@ read4Bitmap (int width, int height) static u1 * -read8Bitmap (int width, int height) -{ - int tmp; - unsigned int xBytes; - unsigned int wt = width; +read8Bitmap (FILE * const ifP, + unsigned int const width, + unsigned int const height) { + + unsigned int row; + unsigned int xByteCt; + unsigned int wt; u1 * bitmap; MALLOCARRAY(bitmap, width * height); if (bitmap == NULL) pm_error("out of memory"); - if (wt & 3) { - wt = (wt & ~3) + 4; + wt = width; + if (wt & 0x3) { + wt = (wt & ~0x3) + 4; } - xBytes = wt; - for (tmp = 0; tmp> 3; - unsigned int const xBytes = width * bytes; +readXBitmap (FILE * const ifP, + unsigned int const width, + unsigned int const height, + unsigned int const bpp) { +/*---------------------------------------------------------------------------- + Read a true color bitmap. (24/32 bits) + + The output routine deplanarizes it for us, we keep it flat here. +-----------------------------------------------------------------------------*/ + unsigned int const byteCt = bpp >> 3; + unsigned int const xByteCt = width * byteCt; u1 * bitmap; /* remember - bmp (dib) stored upside down, so reverse */ - MALLOCARRAY(bitmap, bytes * width * height); + MALLOCARRAY(bitmap, byteCt * width * height); if (bitmap == NULL) pm_error("out of memory allocating bitmap array"); @@ -421,12 +456,12 @@ readXBitmap (int const width, unsigned int i; u1 * bitcurptr; - for (i = 0, bitcurptr = &bitmap[bytes * width * (height-1)]; + for (i = 0, bitcurptr = &bitmap[byteCt * width * (height-1)]; i < height; - ++i, bitcurptr -= xBytes) { + ++i, bitcurptr -= xByteCt) { - u1 * const row = readU1String(xBytes); - memcpy(bitcurptr, row, xBytes); + u1 * const row = readU1String(ifP, xByteCt); + memcpy(bitcurptr, row, xByteCt); free(row); } } @@ -436,80 +471,70 @@ readXBitmap (int const width, static MS_Ico -readIconFile (bool const verbose) { - int iter,iter2; +readIconFile(FILE * const ifP, + bool const verbose) { + + unsigned int i; MS_Ico MSIconData; MALLOCVAR(MSIconData); - /* - * reserved - should equal 0. - */ - MSIconData->reserved = readU2(); - /* - * Type - should equal 1 - */ - MSIconData->type = readU2(); - /* - * count - no of icons in file.. - */ - MSIconData->count = readU2(); - /* - * Allocate "count" array of entries. - */ + MSIconData->reserved = readU2(ifP); /* should be 0 */ + MSIconData->type = readU2(ifP); /* should be 1 */ + MSIconData->count = readU2(ifP); /* # icons in file */ + if (verbose) pm_message("Icon file contains %d icons.", MSIconData->count); MALLOCARRAY(MSIconData->entries, MSIconData->count); if (MSIconData->entries == NULL) pm_error("out of memory"); - /* - * Read in each of the entries - */ - for (iter = 0;iter < MSIconData->count ; iter++ ) { - MSIconData->entries[iter] = readICEntry(); - } - /* After that, we have to read in the infoheader, color map (if - * any) and the actual bit/pix maps for the icons. - */ + + /* Read in each of the entries */ + for (i = 0; i < MSIconData->count; ++i) + MSIconData->entries[i] = readICEntry(ifP); + + /* Read in the infoheader, color map (if any) and the actual bit/pix maps + for the icons. + */ if (verbose) - fprintf (stderr,"#\tColors\tBPP\tWidth\tHeight\n"); - for (iter = 0;iter < MSIconData->count ; iter++ ) { - int bpp; - MSIconData->entries[iter]->ih = - readInfoHeader (MSIconData->entries[iter]); + pm_message("#\tColors\tBPP\tWidth\tHeight\n"); + + for (i = 0; i < MSIconData->count; ++i) { + unsigned int bpp; /* bits per pixel */ + + MSIconData->entries[i]->ih = + readInfoHeader(ifP, MSIconData->entries[i]); - /* What's the bits per pixel? */ - bpp = MSIconData->entries[iter]->bitcount; + bpp = MSIconData->entries[i]->bitcount; + /* Read the palette, if appropriate */ switch (bpp) { case 24: case 32: /* 24/32 bpp icon has no palette */ break; - default: - MALLOCARRAY(MSIconData->entries[iter]->colors, - MSIconData->entries[iter]->color_count); - if (MSIconData->entries[iter]->colors == NULL) + default: { + unsigned int j; + + MALLOCARRAY(MSIconData->entries[i]->colors, + MSIconData->entries[i]->color_count); + if (MSIconData->entries[i]->colors == NULL) pm_error("out of memory"); - for (iter2 = 0; - iter2 < MSIconData->entries[iter]->color_count ; - iter2++ ) { - MSIconData->entries[iter]->colors[iter2] = readICColor(); - } - break; + for (j = 0; j < MSIconData->entries[i]->color_count; ++j) + MSIconData->entries[i]->colors[j] = readICColor(ifP); + } } if (verbose) { - char cols_text[10]; - sprintf (cols_text, "%d", MSIconData->entries[iter]->color_count); - fprintf (stderr, - "%d\t%s\t%d\t%d\t%d\n", iter, - MSIconData->entries[iter]->color_count ? - cols_text : "TRUE", - bpp, MSIconData->entries[iter]->width, - MSIconData->entries[iter]->height); + char colsText[10]; + sprintf (colsText, "%d", MSIconData->entries[i]->color_count); + pm_message("%d\t%s\t%d\t%d\t%d\n", i, + MSIconData->entries[i]->color_count ? + colsText : "TRUE", + bpp, MSIconData->entries[i]->width, + MSIconData->entries[i]->height); } /* Pixels are stored bottom-up, left-to-right. Pixel lines are * padded with zeros to end on a 32bit (4byte) boundary. Every @@ -528,35 +553,40 @@ readIconFile (bool const verbose) { */ switch (bpp) { case 1: - MSIconData->entries[iter]->xorBitmap = - read1Bitmap(MSIconData->entries[iter]->width, - MSIconData->entries[iter]->height); + MSIconData->entries[i]->xorBitmap = + read1Bitmap(ifP, + MSIconData->entries[i]->width, + MSIconData->entries[i]->height); break; case 4: - MSIconData->entries[iter]->xorBitmap = - read4Bitmap(MSIconData->entries[iter]->width, - MSIconData->entries[iter]->height); + MSIconData->entries[i]->xorBitmap = + read4Bitmap(ifP, + MSIconData->entries[i]->width, + MSIconData->entries[i]->height); break; case 8: - MSIconData->entries[iter]->xorBitmap = - read8Bitmap(MSIconData->entries[iter]->width, - MSIconData->entries[iter]->height); + MSIconData->entries[i]->xorBitmap = + read8Bitmap(ifP, + MSIconData->entries[i]->width, + MSIconData->entries[i]->height); break; case 24: case 32: - MSIconData->entries[iter]->xorBitmap = - readXBitmap(MSIconData->entries[iter]->width, - MSIconData->entries[iter]->height,bpp); + MSIconData->entries[i]->xorBitmap = + readXBitmap(ifP, + MSIconData->entries[i]->width, + MSIconData->entries[i]->height,bpp); break; default: - pm_error("Uncatered bit depth %d",bpp); + pm_error("Uncatered bit depth %u", bpp); } /* * Read AND Bitmap */ - MSIconData->entries[iter]->andBitmap = - read1Bitmap(MSIconData->entries[iter]->width, - MSIconData->entries[iter]->height); + MSIconData->entries[i]->andBitmap = + read1Bitmap(ifP, + MSIconData->entries[i]->width, + MSIconData->entries[i]->height); } } @@ -566,15 +596,14 @@ readIconFile (bool const verbose) { static char * -trimOutputName(const char inputName[]) -{ +trimmedOutputName(const char inputName[]) { /* * Just trim off the final ".ppm", if there is one, else return as is. * oh, for =~ ... :) */ - char * outFile = strdup(inputName); - if (streq(outFile + (strlen (outFile) - 4), ".ppm")) { - *(outFile + (strlen (outFile) - 4)) = 0; + char * const outFile = strdup(inputName); + if (streq(outFile + (strlen(outFile) - 4), ".ppm")) { + *(outFile + (strlen(outFile) - 4)) = 0; } return outFile; @@ -585,29 +614,34 @@ trimOutputName(const char inputName[]) static int getBestQualityIcon(MS_Ico MSIconData) { - int x,best,best_size,best_bpp,bpp,size; - IC_Entry entry; - - best_size = best_bpp = 0; - for (x = 0; x < MSIconData->count; x++) { - entry = MSIconData->entries[x]; - size = entry->width * entry->height; - bpp = entry->bitcount ? entry->bitcount : entry->ih->bitcount; - if (size > best_size) { - best = x; - best_size = size; - } else if (size == best_size && bpp > best_bpp) { - best = x; - best_bpp = bpp; + unsigned int i; + unsigned int best; + unsigned int bestSize; + unsigned int bestBpp; + + for (i = 0, bestSize = 0, bestBpp = 0; i < MSIconData->count; ++i) { + IC_Entry const entryP = MSIconData->entries[i]; + unsigned int const size = entryP->width * entryP->height; + unsigned int const bpp = + entryP->bitcount ? entryP->bitcount : entryP->ih->bitcount; + + if (size > bestSize) { + best = i; + bestSize = size; + } else if (size == bestSize && bpp > bestBpp) { + best = i; + bestBpp = bpp; } } return best; } + + static void writeXors(FILE * const multiOutF, - char outputFileBase[], - IC_Entry const entry, + char * const outputFileBase, + IC_Entry const entryP, int const entryNum, bool const multiple, bool const xor) { @@ -625,85 +659,79 @@ writeXors(FILE * const multiOutF, we are to open a file using outputFileBase[] and 'entryNum' and 'xor' to derive its name, and close it afterward. -----------------------------------------------------------------------------*/ - FILE * outF; - pixel ** ppm_array; - int row; - int pel_size; - const char *outputFile; - int maxval; - int forcetext; + FILE * ofP; + pixel ** pixArray; + unsigned int row; + const char * outputFileName; if (multiOutF) { - outF = multiOutF; - outputFile = strdup(""); + ofP = multiOutF; + outputFileName = strdup(""); } else { if (outputFileBase) { if (multiple) { - asprintfN(&outputFile, "%s%s_%d.ppm", - outputFileBase,(xor ? "_xor" : ""), entryNum); + pm_asprintf(&outputFileName, "%s%s_%d.ppm", + outputFileBase,(xor ? "_xor" : ""), entryNum); } else { - asprintfN(&outputFile, "%s%s.ppm", - outputFileBase,(xor ? "_xor" : "")); + pm_asprintf(&outputFileName, "%s%s.ppm", + outputFileBase,(xor ? "_xor" : "")); } } else - outputFile = strdup("-"); + outputFileName = strdup("-"); - outF = pm_openw(outputFile); + ofP = pm_openw(outputFileName); } /* - * allocate an array to save the bmp data into. - * note that entry->height will be 1/2 entry->ih->height, - * as the latter adds "and" and "xor" height. - */ - ppm_array = ppm_allocarray(entry->width, entry->height); - for (row=0; row < entry->height; row++) { - u1 * xorRow; - int col; - switch (entry->bitcount) { + Allocate an array to save the bmp data into. + note that entry->height will be 1/2 entry->ih->height, + as the latter adds "and" and "xor" height. + */ + pixArray = ppm_allocarray(entryP->width, entryP->height); + for (row = 0; row < entryP->height; ++row) { + switch (entryP->bitcount) { case 24: - case 32: - pel_size = entry->bitcount >> 3; - xorRow = entry->xorBitmap + row * entry->width * pel_size; - for (col=0; col < entry->width*pel_size;col+=pel_size) { - PPM_ASSIGN(ppm_array[row][col/pel_size], - xorRow[col+2],xorRow[col+1],xorRow[col]); - } - break; - default: - xorRow = entry->xorBitmap + row * entry->width; - for (col=0; col < entry->width; col++) { - int colorIndex; - IC_Color color; - colorIndex = xorRow[col]; - color = entry->colors[colorIndex]; - PPM_ASSIGN(ppm_array[row][col], - color->red,color->green,color->blue); + case 32: { + unsigned int const pixelSize = entryP->bitcount >> 3; + u1 * const xorRow = + entryP->xorBitmap + row * entryP->width * pixelSize; + unsigned int col; + for (col = 0; col < entryP->width * pixelSize; col += pixelSize) + PPM_ASSIGN(pixArray[row][col/pixelSize], + xorRow[col+2], xorRow[col+1], xorRow[col]); + } break; + default: { + u1 * const xorRow = entryP->xorBitmap + row * entryP->width; + unsigned int col; + for (col = 0; col < entryP->width; ++col) { + unsigned int const colorIndex = xorRow[col]; + IC_Color const colorP = entryP->colors[colorIndex]; + PPM_ASSIGN(pixArray[row][col], + colorP->red, colorP->green, colorP->blue); } - break; + } break; } } - maxval = 255; - forcetext = 0; - - ppm_writeppm(outF,ppm_array,entry->width, entry->height, - (pixval) maxval, forcetext); - ppm_freearray(ppm_array,entry->height); + ppm_writeppm(ofP, pixArray, entryP->width, entryP->height, + 255 /* maxval */, false /* text */); + ppm_freearray(pixArray, entryP->height); - strfree(outputFile); + pm_strfree(outputFileName); if (!multiOutF) - pm_close(outF); + pm_close(ofP); } static void -writeAnds(FILE * const multiOutF, - char outputFileBase[], IC_Entry const entry, int const entryNum, - bool multiple) { +writeAnds(FILE * const multiOutF, + char const outputFileBase[], + IC_Entry const entryP, + unsigned int const entryNum, + bool const multiple) { /*---------------------------------------------------------------------------- - Write the "and" image (i.e. the alpha mask) of the image 'IC_Entry' out. + Write the "and" image (i.e. the alpha mask) of the image *entryP out. 'multiple' means this is one of multiple images that are being written. 'entryNum' is the sequence number within the winicon file of the image @@ -714,114 +742,122 @@ writeAnds(FILE * const multiOutF, we are to open a file using outputFileBase[] and 'entryNum' and 'xor' to derive its name, and close it afterward. -----------------------------------------------------------------------------*/ - FILE * outF; - bit ** pbm_array; - u1 * andRow; - int row; + FILE * ofP; + bit ** bitArray; + unsigned int row; if (multiOutF) - outF = multiOutF; + ofP = multiOutF; else { - const char *outputFile; + const char * outputFileName; assert(outputFileBase); if (multiple) - asprintfN(&outputFile, "%s_and_%d.pbm", outputFileBase, entryNum); + pm_asprintf(&outputFileName, "%s_and_%u.pbm", + outputFileBase, entryNum); else - asprintfN(&outputFile, "%s_and.pbm", outputFileBase); - outF = pm_openw(outputFile); - strfree(outputFile); + pm_asprintf(&outputFileName, "%s_and.pbm", outputFileBase); + ofP = pm_openw(outputFileName); + pm_strfree(outputFileName); } - pbm_array = pbm_allocarray(entry->width, entry->height); - for (row=0; row < entry->height; row++) { - int col; - andRow = entry->andBitmap + row * entry->width; - for (col=0; col < entry->width; col++) { + bitArray = pbm_allocarray(entryP->width, entryP->height); + for (row = 0; row < entryP->height; ++row) { + u1 * const andRow = entryP->andBitmap + row * entryP->width; + unsigned int col; + for (col = 0; col < entryP->width; ++col) { /* Note: black is transparent in a Netpbm alpha mask */ - pbm_array[row][col] = andRow[col] ? PBM_BLACK: PBM_WHITE; + bitArray[row][col] = andRow[col] ? PBM_BLACK: PBM_WHITE; } } - pbm_writepbm(outF, pbm_array, entry->width, entry->height, 0); + pbm_writepbm(ofP, bitArray, entryP->width, entryP->height, 0); - pbm_freearray(pbm_array, entry->height); + pbm_freearray(bitArray, entryP->height); if (!multiOutF) - pm_close (outF); + pm_close(ofP); } static void -openMultiXor(char outputFileBase[], +openMultiXor(char const outputFileBase[], bool const writeands, FILE ** const multiOutFP) { - const char *outputFile; + const char * outputFileName; if (outputFileBase) { - asprintfN(&outputFile, "%s%s.ppm", - outputFileBase, (writeands ? "_xor" : "")); + pm_asprintf(&outputFileName, "%s%s.ppm", + outputFileBase, (writeands ? "_xor" : "")); } else - outputFile = strdup("-"); + outputFileName = strdup("-"); - /* - * Open the output file now, it'll stay open the whole time. - */ - *multiOutFP = pm_openw(outputFile); + *multiOutFP = pm_openw(outputFileName); - strfree(outputFile); + pm_strfree(outputFileName); } static void -openMultiAnd(char outputFileBase[], FILE ** const multiAndOutFP) { +openMultiAnd(char const outputFileBase[], + FILE ** const multiAndOutFP) { - const char *outputFile; + const char * outputFileName; assert(outputFileBase); - asprintfN(&outputFile, "%s_and.pbm", outputFileBase); + pm_asprintf(&outputFileName, "%s_and.pbm", outputFileBase); - *multiAndOutFP = pm_openw(outputFile); + *multiAndOutFP = pm_openw(outputFileName); - strfree(outputFile); + pm_strfree(outputFileName); } -static void free_iconentry(IC_Entry entry) { - int x; - if (entry->colors && entry->color_count) { - for (x=0;xcolor_count;x++) free(entry->colors[x]); - free(entry->colors); + + +static void +freeIconentry(IC_Entry const entryP) { + + if (entryP->colors && entryP->color_count) { + unsigned int i; + for (i = 0; i color_count; ++i) + free(entryP->colors[i]); + free(entryP->colors); } - if (entry->andBitmap) free(entry->andBitmap); - if (entry->xorBitmap) free(entry->xorBitmap); - if (entry->ih) free(entry->ih); - free(entry); + if (entryP->andBitmap) free(entryP->andBitmap); + if (entryP->xorBitmap) free(entryP->xorBitmap); + if (entryP->ih) free(entryP->ih); + free(entryP); } -static void free_icondata(MS_Ico MSIconData) -{ - int x; - for (x=0;xcount;x++) { - free_iconentry(MSIconData->entries[x]); - } - free(MSIconData); + + +static void +freeIcondata(MS_Ico const MSIconDataP) { + + unsigned int i; + for (i = 0; i < MSIconDataP->count; ++i) + freeIconentry(MSIconDataP->entries[i]); + + free(MSIconDataP); } + int -main(int argc, char *argv[]) { +main(int argc, const char *argv[]) { struct cmdlineInfo cmdline; - int startEntry, endEntry; - MS_Ico MSIconData; + FILE * ifP; + unsigned int startEntry, endEntry; + MS_Ico MSIconDataP; char * outputFileBase; FILE * multiOutF; FILE * multiAndOutF; - ppm_init (&argc, argv); + pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); @@ -832,13 +868,13 @@ main(int argc, char *argv[]) { if (streq(cmdline.outputFilespec, "-")) outputFileBase = NULL; else - outputFileBase = trimOutputName(cmdline.outputFilespec); + outputFileBase = trimmedOutputName(cmdline.outputFilespec); - ifp = pm_openr(cmdline.inputFilespec); + ifP = pm_openr(cmdline.inputFilespec); infname = cmdline.inputFilespec; - MSIconData = readIconFile(cmdline.verbose); + MSIconDataP = readIconFile(ifP, cmdline.verbose); /* * Now we've read the icon file in (Hopefully! :) * Go through each of the entries, and write out files of the @@ -852,18 +888,15 @@ main(int argc, char *argv[]) { /* * If allicons is set, we want everything, if not, just go through once. */ - startEntry = 0; - if (cmdline.allicons) { - endEntry = MSIconData->count; - } else { - endEntry = 1; - } - /* - * If bestqual is set, find the icon with highest size & bpp. - */ if (cmdline.bestqual) { - startEntry = getBestQualityIcon(MSIconData); + startEntry = getBestQualityIcon(MSIconDataP); endEntry = startEntry+1; + } else { + startEntry = 0; + if (cmdline.allicons) + endEntry = MSIconDataP->count; + else + endEntry = 1; } if (cmdline.multippm) @@ -877,24 +910,25 @@ main(int argc, char *argv[]) { multiAndOutF = NULL; { - int entryNum; + unsigned int entryNum; - for (entryNum = startEntry ; entryNum < endEntry ; entryNum++ ) { - IC_Entry const entry = MSIconData->entries[entryNum]; + for (entryNum = startEntry; entryNum < endEntry; ++entryNum) { + IC_Entry const entryP = MSIconDataP->entries[entryNum]; - writeXors(multiOutF, outputFileBase, entry, entryNum, + writeXors(multiOutF, outputFileBase, entryP, entryNum, cmdline.allicons, cmdline.writeands); if (cmdline.writeands) writeAnds(multiAndOutF, outputFileBase, - entry, entryNum, cmdline.allicons); + entryP, entryNum, cmdline.allicons); } } if (multiOutF) - pm_close (multiOutF); + pm_close(multiOutF); if (multiAndOutF) pm_close(multiAndOutF); /* free up the image data here. */ - free_icondata(MSIconData); + freeIcondata(MSIconDataP); + return 0; } diff --git a/converter/ppm/xim.h b/converter/ppm/xim.h index ffe60fb6..27556b30 100644 --- a/converter/ppm/xim.h +++ b/converter/ppm/xim.h @@ -112,7 +112,7 @@ typedef struct XimAsciiHeader { /* Note: * - All data is in char's in order to maintain easily portability * across machines, and some human readibility. -* - Images may be stored as pixmaps (8 bits/pixel) or as seperate +* - Images may be stored as pixmaps (8 bits/pixel) or as separate * red, green, blue channel data (24+ bits/pixel). * - An alpha channel is optional and is found after every num_channels * of data. diff --git a/converter/ppm/ximtoppm.c b/converter/ppm/ximtoppm.c index 15589c16..ce5e6396 100644 --- a/converter/ppm/ximtoppm.c +++ b/converter/ppm/ximtoppm.c @@ -56,7 +56,7 @@ parseCommandLine(int argc, char ** argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and all of *cmdlineP. */ if (!alphaoutSpec) @@ -208,7 +208,7 @@ ReadImageChannel(FILE * const infp, } marker += i; } - /* return to the begining of the next image's bufffer */ + /* return to the beginning of the next image's bufffer */ if (fseek(infp, marker, 0) == -1) { pm_message("ReadImageChannel: can't fseek to location in image buffer" ); return(0); diff --git a/converter/ppm/xpmtoppm.c b/converter/ppm/xpmtoppm.c index 235c3867..27f17931 100644 --- a/converter/ppm/xpmtoppm.c +++ b/converter/ppm/xpmtoppm.c @@ -1,43 +1,19 @@ -/* xpmtoppm.c - read an X11 pixmap file and produce a portable pixmap -** -** Copyright (C) 1991 by Jef Poskanzer. -** -** Permission to use, copy, modify, and distribute this software and its -** documentation for any purpose and without fee is hereby granted, provided -** that the above copyright notice appear in all copies and that both that -** copyright notice and this permission notice appear in supporting -** documentation. This software is provided "as is" without express or -** implied warranty. -** -** Upgraded to handle XPM version 3 by -** Arnaud Le Hors (lehors@mirsa.inria.fr) -** Tue Apr 9 1991 -** -** Rainer Sinkwitz sinkwitz@ifi.unizh.ch - 21 Nov 91: -** - Bug fix, no advance of read ptr, would not read -** colors like "ac c black" because it would find -** the "c" of "ac" and then had problems with "c" -** as color. -** -** - Now understands multiword X11 color names -** -** - Now reads multiple color keys. Takes the color -** of the hightest available key. Lines no longer need -** to begin with key 'c'. -** -** - expanded line buffer to from 500 to 2048 for bigger files +/* xpmtoppm.c - convert XPM file (X11 pixmap) to PPM + + Copyright and history information is at end of file */ #define _BSD_SOURCE /* Make sure strdup() is in string.h */ #define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */ +#include #include #include "pm_c_util.h" -#include "ppm.h" +#include "mallocvar.h" #include "shhopt.h" #include "nstring.h" -#include "mallocvar.h" +#include "ppm.h" #define MAX_LINE (8 * 1024) /* The maximum size XPM input line we can handle. */ @@ -47,72 +23,321 @@ const char *xpmColorKeys[] = { - "s", /* key #1: symbol */ - "m", /* key #2: mono visual */ - "g4", /* key #3: 4 grays visual */ - "g", /* key #4: gray visual */ - "c", /* key #5: color visual */ + "s", /* key #1: symbol */ + "m", /* key #2: mono visual */ + "g4", /* key #3: 4 grays visual */ + "g", /* key #4: gray visual */ + "c", /* key #5: color visual */ }; -struct cmdline_info { +struct cmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ - char *input_filespec; /* Filespecs of input files */ - char *alpha_filename; + const char * input_filespec; /* Filespecs of input files */ + const char * alpha_filename; int alpha_stdout; int verbose; }; -static int verbose; +static bool verbose; + static void -parse_command_line(int argc, char ** argv, - struct cmdline_info *cmdline_p) { +parseCommandLine(int argc, char ** argv, + struct cmdlineInfo *cmdlineP) { /*---------------------------------------------------------------------------- Note that the file spec array we return is stored in the storage that was passed to us as the argv array. -----------------------------------------------------------------------------*/ - optStruct *option_def = malloc(100*sizeof(optStruct)); + optEntry * option_def; /* Instructions to OptParseOptions2 on how to parse our options. */ - optStruct2 opt; + optStruct3 opt; unsigned int option_def_index; - option_def_index = 0; /* incremented by OPTENTRY */ - OPTENTRY(0, "alphaout", OPT_STRING, &cmdline_p->alpha_filename, 0); - OPTENTRY(0, "verbose", OPT_FLAG, &cmdline_p->verbose, 0); + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENT3 */ + OPTENT3(0, "alphaout", OPT_STRING, &cmdlineP->alpha_filename, + NULL, 0); + OPTENT3(0, "verbose", OPT_FLAG, &cmdlineP->verbose, + NULL, 0); - cmdline_p->alpha_filename = NULL; - cmdline_p->verbose = FALSE; + cmdlineP->alpha_filename = NULL; + cmdlineP->verbose = FALSE; opt.opt_table = option_def; opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = TRUE; /* We may have parms that are negative numbers */ - optParseOptions2(&argc, argv, opt, 0); - /* Uses and sets argc, argv, and some of *cmdline_p and others. */ + pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (argc - 1 == 0) - cmdline_p->input_filespec = NULL; /* he wants stdin */ + cmdlineP->input_filespec = NULL; /* he wants stdin */ else if (argc - 1 == 1) - cmdline_p->input_filespec = strdup(argv[1]); + cmdlineP->input_filespec = strdup(argv[1]); else pm_error("Too many arguments. The only argument accepted\n" "is the input file specification"); - if (cmdline_p->alpha_filename && - streq(cmdline_p->alpha_filename, "-")) - cmdline_p->alpha_stdout = TRUE; + if (cmdlineP->alpha_filename && + streq(cmdlineP->alpha_filename, "-")) + cmdlineP->alpha_stdout = TRUE; else - cmdline_p->alpha_stdout = FALSE; + cmdlineP->alpha_stdout = FALSE; + +} + + + +struct ColorNameHashTableEntry { +/*---------------------------------------------------------------------------- + An entry in the color name hash table. It maps a color name to a + color, or is empty. +-----------------------------------------------------------------------------*/ + bool empty; + char colorName[3]; + /* Actual length 0-3. NOT NUL-terminated */ + pixel color; +}; + + + +typedef struct { +/*---------------------------------------------------------------------------- + This is a color map which is primarily a hash table that maps an XPM + color name to a color. An XPM color name is a 0-3 character name that + appears in the raster of an XPM image to uniquely identify a color. + The header of the XPM contains a listing of all the color names that + appear in the raster, identifying a color for each. + + We represent a color as a 'pixel'. +-----------------------------------------------------------------------------*/ + unsigned int nameSize; + /* Size of color names in this hash. 0-3 */ + struct ColorNameHashTableEntry * transparentP; + /* The element of 'table' that is for the transparent color. + NULL if there is none. + */ + + /* This is an internally chained hash table, i.e. there are no linked + lists. You use the hash function to get an index into the hash table. + If the entry indexed by that is not for the color name you're looking + for, you look at the next entry down, and keep going down until you + either find the color name you're looking for or hit an empty entry. + + So that we never run out of space for new color names, we make the + creator of the hash table tell us the maximum number of colors there + will be. We allocate twice that size in order to reduce average hash + chain length. + */ + unsigned int size; + struct ColorNameHashTableEntry * table; +} ColorNameHash; + + + +static ColorNameHash * +hash_create(unsigned int const nColors, + unsigned int const nameSize) { + + ColorNameHash * hashP; + + MALLOCVAR_NOFAIL(hashP); + + hashP->nameSize = nameSize; + + hashP->size = nColors * 2; + + MALLOCARRAY(hashP->table, hashP->size); + + if (!hashP->table) + pm_error("Failed to allocate memory for a %u-entry " + "color name hash table.", hashP->size); + + { + unsigned int i; + for (i = 0; i < hashP->size; ++i) + hashP->table[i].empty = true; + } + + hashP->transparentP = NULL; + + return hashP; +} + + + +static void +hash_destroy(ColorNameHash * const hashP) { + + free(hashP->table); + + free(hashP); +} + + + +static unsigned int +hashColorName(const char * const name, + unsigned int const size, + unsigned int const hashTableSize) { +/*---------------------------------------------------------------------------- + Return the hash value (initial index into the color name hash table) + for the color name 'name', which is 'size' characters long. The hash + is to be in the range [0, hashTableSize). +-----------------------------------------------------------------------------*/ + /* I have no idea if this is an appropriate hash function. I borrowed + it from pnm_hashTuple() + */ + + unsigned int const hash_factor[] = {1, 33, 33*33}; + + unsigned int i; + unsigned int hash; + hash = 0; /* initial value */ + for (i = 0; i < size; ++i) { + hash += name[i] * hash_factor[i]; + } + hash %= hashTableSize; + return hash; +} + + + +static bool +entryMatch(struct ColorNameHashTableEntry const entry, + const char * const name, + unsigned int const size) { + + if (entry.empty) + return true; + + assert(size <= ARRAY_SIZE(entry.colorName)); + + { + unsigned int i; + + for (i = 0; i < size; ++i) { + if (name[i] != entry.colorName[i]) + return false; + } + } + + return true; +} + + + +static void +bumpIndex(unsigned int * const indexP, + unsigned int const tableSize, + unsigned int const limit) { +/*---------------------------------------------------------------------------- + Bump *indexP to the next entry in a table of size 'tableSize', in a + circular fashion. But abort the program if this would take us to + 'limit'. +-----------------------------------------------------------------------------*/ + *indexP += 1; + if (*indexP >= tableSize) + *indexP = 0; + + if (*indexP == limit) + pm_error("INTERNAL ERROR: color name hash table is full"); +} + + + +static void +hash_find(const ColorNameHash * const hashP, + const char * const name, + struct ColorNameHashTableEntry ** const entryPP) { +/*---------------------------------------------------------------------------- + Find the entry in the color hash table *hashP for the color + named 'name' in the lexicon of this XPM file. If the color is in the + table, this is where it is. If it isn't, this is where it should go. +-----------------------------------------------------------------------------*/ + unsigned int const initialIndex = + hashColorName(name, hashP->nameSize, hashP->size); + + unsigned int i; + + for (i = initialIndex; + !entryMatch(hashP->table[i], name, hashP->nameSize); + bumpIndex(&i, hashP->size, initialIndex)); + + *entryPP = &hashP->table[i]; } + +static void +hash_add(ColorNameHash * const hashP, + const char * const name, + pixel const color, + bool const isTransparent) { + + struct ColorNameHashTableEntry * entryP; + + hash_find(hashP, name, &entryP); + + if (!entryP->empty) + pm_error("Color name appears multiple times in color map"); + + entryP->empty = false; + { + unsigned int i; + for (i = 0; i < hashP->nameSize; ++i) + entryP->colorName[i] = name[i]; + } + entryP->color = color; + + if (isTransparent) { + if (hashP->transparentP) + pm_error("There are multiple NONE (transparent) entries in " + "the XPM color map"); + else + hashP->transparentP = entryP; + } +} + + + +static pixel +hash_color(const ColorNameHash * const hashP, + const char * const name) { + + struct ColorNameHashTableEntry * entryP; + + hash_find(hashP, name, &entryP); + + if (entryP->empty) + pm_error("Color name in raster is not in color map"); + + return entryP->color; +} + + + +static bool +hash_isTransparent(const ColorNameHash * const hashP, + const char * const name) { + + struct ColorNameHashTableEntry * entryP; + + hash_find(hashP, name, &entryP); + + return (entryP == hashP->transparentP); +} + + + static char lastInputLine[MAX_LINE+1]; /* contents of line most recently read from input */ static bool backup; @@ -121,6 +346,7 @@ static bool backup; */ + static void getLine(char * const line, size_t const size, @@ -158,21 +384,6 @@ getLine(char * const line, -static unsigned int -getNumber(char * const p, unsigned int const size) { - - unsigned int retval; - unsigned char * q; - - retval = 0; - for (q = p; q < p+size; ++q) - retval = (retval << 8) + *q; - - return retval; -} - - - static void getword(char * const output, char ** const cursorP) { @@ -191,90 +402,97 @@ getword(char * const output, char ** const cursorP) { static void -addToColorMap(unsigned int const seqNum, - unsigned int const colorNumber, - pixel * const colors, int * const ptab, - char colorspec[], int const isTransparent, - int * const transparentP) { +addToColorMap(ColorNameHash * const hashP, + const char * const colorName, + char const colorspec[], + bool const isTransparent) { /*---------------------------------------------------------------------------- - Add the color named by colorspec[] to the colormap contained in - 'colors' and 'ptab', as the color associated with XPM color number - 'colorNumber', which is the seqNum'th color in the XPM color map. + Add the color named by colorspec[] to the colormap represented by *hashP, + as the color associated with XPM color name 'colorNumber'. - Iff 'transparent', set *transparentP to the colormap index that - corresponds to this color. + Note that *hashP determines how long 'colorName' is. -----------------------------------------------------------------------------*/ - if (ptab == NULL) { - /* Index into table. */ - colors[colorNumber] = ppm_parsecolor(colorspec, - (pixval) PPM_MAXMAXVAL); - if (isTransparent) - *transparentP = colorNumber; - } else { - /* Set up linear search table. */ - colors[seqNum] = ppm_parsecolor(colorspec, - (pixval) PPM_MAXMAXVAL); - ptab[seqNum] = colorNumber; - if (isTransparent) - *transparentP = seqNum; + hash_add(hashP, colorName, ppm_parsecolor(colorspec, PPM_MAXMAXVAL), + isTransparent); +} + + + +static void +validateColorName(const char * const name, + unsigned int const charsPerPixel) { + + unsigned int i; + + for (i = 0; i < charsPerPixel; ++i) { + if (name[i] == '"') + pm_error("A color map entry ends in the middle of the colormap " + "index"); + else if (name[i] == '\0') + pm_error("The XPM file ends in the middle of a color map entry"); } } static void -interpretXpm3ColorTableLine(char line[], int const seqNum, - int const chars_per_pixel, - pixel * const colors, int * const ptab, - int * const transparentP) { +interpretXpm3ColorTableLine(char const line[], + unsigned int const seqNum, + unsigned int const charsPerPixel, + ColorNameHash * const hashP) { /*---------------------------------------------------------------------------- - Interpret one line of the color table in the XPM header. 'line' is - the line from the XPM file. It is the seqNum'th color table entry in - the file. The file uses 'chars_per_pixel' characters per pixel. + Interpret one line of the color table in the XPM header. 'line' is the + line from the XPM file. It is the seqNum'th color table entry in the file. + The raster in the file uses 'charsPerPixel' characters per pixel (i.e. + a an XPM color name is 'charsPerPixel' characters). - Add the information from this color table entry to the color table - 'colors' and, if it isn't NULL, the corresponding lookup shadow table - 'ptab' (see readXpm3ColorTable for a description of these data - structures). + Add the information from this color table entry to the color name hash + *hashP. The line may include values for multiple kinds of color (grayscale, color, etc.). We take the highest of these (e.g. color over grayscale). If a color table entry indicates transparency, set *transparentP - to the colormap index that corresponds to the indicated color. + to indicate the XPM color name. -----------------------------------------------------------------------------*/ /* Note: this code seems to allow for multi-word color specifications, but I'm not aware that such are legal. Ultimately, ppm_parsecolor() - interprets the name, and I believe it only takes single word + interprets the name, and I believe it takes only single word color specifications. -Bryan 2001.05.06. */ char str2[MAX_LINE+1]; - char *t1; - char *t2; + char * t1; + char * t2; int endOfEntry; /* boolean */ - unsigned int curkey, key, highkey; /* current color key */ - unsigned int lastwaskey; + unsigned int curkey, key, highkey; /* current color key */ + bool lastwaskey; /* The last token we processes was a key, and we have processed at least one token. */ - char curbuf[BUFSIZ]; /* current buffer */ - int isTransparent; + char curbuf[BUFSIZ]; /* current buffer */ + bool isTransparent; - int colorNumber; - /* A color number that appears in the raster */ + const char * colorName; + /* The 0-3 character name this color map line gives the color + (i.e. the name that the raster uses). This is NOT NUL-terminated. + It's length is bytesPerPixel. + */ + /* read the chars */ t1 = strchr(line, '"'); if (t1 == NULL) pm_error("A line that is supposed to be an entry in the color " "table does not start with a quote. The line is '%s'. " - "It is the %dth entry in the color table.", + "It is the %uth entry in the color table.", line, seqNum); else - t1++; /* Points now to first color number character */ + ++t1; /* Points now to first color number character */ + + validateColorName(t1, charsPerPixel); + colorName = t1; - colorNumber = getNumber(t1, chars_per_pixel); - t1 += chars_per_pixel; + t1 += charsPerPixel; /* * read color keys and values @@ -306,30 +524,30 @@ interpretXpm3ColorTableLine(char line[], int const seqNum, pm_error("Missing color key token in color table line " "'%s' before '%s'.", line, str2); if (!lastwaskey) - strcat(curbuf, " "); /* append space */ - if ( (strncmp(str2, "None", 4) == 0) - || (strncmp(str2, "none", 4) == 0) ) { + strcat(curbuf, " "); /* append space */ + if ( (strneq(str2, "None", 4)) + || (strneq(str2, "none", 4)) ) { /* This entry identifies the transparent color number */ strcat(curbuf, "#000000"); /* Make it black */ isTransparent = TRUE; } else - strcat(curbuf, str2); /* append buf */ - lastwaskey = 0; + strcat(curbuf, str2); /* append buf */ + lastwaskey = FALSE; } else { /* This word is a key. So we've seen the last of the info for the previous key, and we must either put it in the color map or ignore it if we already have a higher color form in the colormap for this colormap entry. */ - if (curkey > highkey) { /* flush string */ - addToColorMap(seqNum, colorNumber, colors, ptab, curbuf, - isTransparent, transparentP); + if (curkey > highkey) { /* flush string */ + addToColorMap(hashP, colorName, curbuf, isTransparent); highkey = curkey; } - curkey = key; /* set new key */ - curbuf[0] = '\0'; /* reset curbuf */ + /* intialize state to process this new key */ + curkey = key; + curbuf[0] = '\0'; isTransparent = FALSE; - lastwaskey = 1; + lastwaskey = TRUE; } if (*t2 == '"') break; } @@ -339,8 +557,7 @@ interpretXpm3ColorTableLine(char line[], int const seqNum, entry in it) */ if (curkey > highkey) { - addToColorMap(seqNum, colorNumber, colors, ptab, curbuf, - isTransparent, transparentP); + addToColorMap(hashP, colorName, curbuf, isTransparent); highkey = curkey; } if (highkey == 1) @@ -350,152 +567,208 @@ interpretXpm3ColorTableLine(char line[], int const seqNum, static void -readXpm3Header(FILE * const stream, int * const widthP, int * const heightP, - int * const chars_per_pixelP, int * const ncolorsP, - pixel ** const colorsP, int ** const ptabP, - int * const transparentP) { +readV3ColorTable(FILE * const ifP, + ColorNameHash ** const colorNameHashPP, + unsigned int const nColors, + unsigned int const charsPerPixel) { /*---------------------------------------------------------------------------- - Read the header of the XPM file on stream 'stream'. Assume the + Read the color table from the XPM Version 3 header. + + Assume *ifP is positioned to the color table; leave it positioned after. +-----------------------------------------------------------------------------*/ + ColorNameHash * const colorNameHashP = hash_create(nColors, charsPerPixel); + + unsigned int seqNum; + /* Sequence number of entry within color table in XPM header */ + + for (seqNum = 0; seqNum < nColors; ++seqNum) { + char line[MAX_LINE+1]; + getLine(line, sizeof(line), ifP); + /* skip the comment line if any */ + if (strneq(line, "/*", 2)) + getLine(line, sizeof(line), ifP); + + interpretXpm3ColorTableLine(line, seqNum, charsPerPixel, + colorNameHashP); + + } + *colorNameHashPP = colorNameHashP; +} + + + +static void +readXpm3Header(FILE * const ifP, + unsigned int * const widthP, + unsigned int * const heightP, + unsigned int * const charsPerPixelP, + ColorNameHash ** const colorNameHashPP) { +/*---------------------------------------------------------------------------- + Read the header of the XPM file on stream *ifP. Assume the getLine() stream is presently positioned to the beginning of the file and it is a Version 3 XPM file. Leave the stream positioned after the header. - We have two ways to return the colormap, depending on the number of - characters per pixel in the XPM: - - If it is 1 or 2 characters per pixel, we return the colormap as a - Netpbm 'pixel' array *colorsP (in newly malloc'ed storage), such - that if a color in the raster is identified by index N, then - (*colorsP)[N] is that color. So this array is either 256 or 64K - pixels. In this case, we return *ptabP = NULL. - - If it is more than 2 characters per pixel, we return the colormap as - both a Netpbm 'pixel' array *colorsP and a lookup table *ptabP (both - in newly malloc'ed storage). - - If a color in the raster is identified by index N, then for some I, - (*ptabP)[I] is N and (*colorsP)[I] is the color in question. So - you iterate through *ptabP looking for N and then look at the - corresponding entry in *colorsP to get the color. - - Return as *transColorNumberP the value of the XPM color number that - represents a transparent pixel, or -1 if no color number does. + Return as *widthP and *heightP the dimensions of the image indicated + by the header. + + Return as *charsPerPixelP the number of characters the header says the + raster uses for each pixel, i.e. the XPM color name length. + + Return the color map as *colorNameHashPP. -----------------------------------------------------------------------------*/ char line[MAX_LINE+1]; const char * xpm3_signature = "/* XPM */"; - *widthP = *heightP = *ncolorsP = *chars_per_pixelP = -1; + unsigned int width, height; + unsigned int nColors; + unsigned int charsPerPixel; /* Read the XPM signature comment */ - getLine(line, sizeof(line), stream); - if (strncmp(line, xpm3_signature, strlen(xpm3_signature)) != 0) + getLine(line, sizeof(line), ifP); + if (!strneq(line, xpm3_signature, strlen(xpm3_signature))) pm_error("Apparent XPM 3 file does not start with '/* XPM */'. " "First line is '%s'", xpm3_signature); /* Read the assignment line */ - getLine(line, sizeof(line), stream); - if (strncmp(line, "static char", 11) != 0) + getLine(line, sizeof(line), ifP); + if (!strneq(line, "static char", 11)) pm_error("Cannot find data structure declaration. Expected a " "line starting with 'static char', but found the line " "'%s'.", line); - /* Read the hints line */ - getLine(line, sizeof(line), stream); - /* skip the comment line if any */ - if (!strncmp(line, "/*", 2)) { + getLine(line, sizeof(line), ifP); + + /* Skip the comment block, if one starts here */ + if (strneq(line, "/*", 2)) { while (!strstr(line, "*/")) - getLine(line, sizeof(line), stream); - getLine(line, sizeof(line), stream); + getLine(line, sizeof(line), ifP); + getLine(line, sizeof(line), ifP); } - if (sscanf(line, "\"%d %d %d %d\",", widthP, heightP, - ncolorsP, chars_per_pixelP) != 4) + + /* Parse the hints line */ + if (sscanf(line, "\"%u %u %u %u\",", &width, &height, + &nColors, &charsPerPixel) != 4) pm_error("error scanning hints line"); - if (verbose == 1) - { - pm_message("Width x Height: %d x %d", *widthP, *heightP); - pm_message("no. of colors: %d", *ncolorsP); - pm_message("chars per pixel: %d", *chars_per_pixelP); + if (verbose) { + pm_message("Width x Height: %u x %u", width, height); + pm_message("no. of colors: %u", nColors); + pm_message("chars per pixel: %u", charsPerPixel); } - /* Allocate space for color table. */ - if (*chars_per_pixelP <= 2) { - /* Set up direct index (see above) */ - *colorsP = ppm_allocrow(*chars_per_pixelP == 1 ? 256 : 256*256); - *ptabP = NULL; - } else { - /* Set up lookup table (see above) */ - *colorsP = ppm_allocrow(*ncolorsP); - MALLOCARRAY(*ptabP, *ncolorsP); - if (*ptabP == NULL) - pm_error("Unable to allocate memory for %d colors", *ncolorsP); - } - - { - /* Read the color table */ - int seqNum; - /* Sequence number of entry within color table in XPM header */ - - *transparentP = -1; /* initial value */ - - for (seqNum = 0; seqNum < *ncolorsP; seqNum++) { - getLine(line, sizeof(line), stream); - /* skip the comment line if any */ - if (!strncmp(line, "/*", 2)) - getLine(line, sizeof(line), stream); - - interpretXpm3ColorTableLine(line, seqNum, *chars_per_pixelP, - *colorsP, *ptabP, transparentP); - } + readV3ColorTable(ifP, colorNameHashPP, nColors, charsPerPixel); + + *widthP = width; + *heightP = height; + *charsPerPixelP = charsPerPixel; +} + + + +static void +readV1ColorTable(FILE * const ifP, + ColorNameHash ** const colorNameHashPP, + unsigned int const nColors, + unsigned int const charsPerPixel) { +/*---------------------------------------------------------------------------- + Read the color table from the XPM Version 1 header. + + Assume *ifP is positioned to the color table; leave it positioned after. +-----------------------------------------------------------------------------*/ + ColorNameHash * const colorNameHashP = hash_create(nColors, charsPerPixel); + + unsigned int i; + + for (i = 0; i < nColors; ++i) { + char line[MAX_LINE+1]; + char str1[MAX_LINE+1]; + char str2[MAX_LINE+1]; + char * t1; + char * t2; + + getLine(line, sizeof(line), ifP); + + if ((t1 = strchr(line, '"')) == NULL) + pm_error("D error scanning color table"); + if ((t2 = strchr(t1 + 1, '"')) == NULL) + pm_error("E error scanning color table"); + if (t2 - t1 - 1 != charsPerPixel) + pm_error("wrong number of chars per pixel in color table"); + strncpy(str1, t1 + 1, t2 - t1 - 1); + str1[t2 - t1 - 1] = '\0'; + + if ((t1 = strchr(t2 + 1, '"')) == NULL) + pm_error("F error scanning color table"); + if ((t2 = strchr(t1 + 1, '"')) == NULL) + pm_error("G error scanning color table"); + strncpy(str2, t1 + 1, t2 - t1 - 1); + str2[t2 - t1 - 1] = '\0'; + + addToColorMap(colorNameHashP, str1, str2, false); } + *colorNameHashPP = colorNameHashP; } + static void -readXpm1Header(FILE * const stream, int * const widthP, int * const heightP, - int * const chars_per_pixelP, int * const ncolorsP, - pixel ** const colorsP, int ** const ptabP) { +readXpm1Header(FILE * const ifP, + unsigned int * const widthP, + unsigned int * const heightP, + unsigned int * const charsPerPixelP, + ColorNameHash ** const colorNameHashPP) { /*---------------------------------------------------------------------------- - Read the header of the XPM file on stream 'stream'. Assume the + Read the header of the XPM file on stream *ifP. Assume the getLine() stream is presently positioned to the beginning of the file and it is a Version 1 XPM file. Leave the stream positioned after the header. Return the information from the header the same as for readXpm3Header. -----------------------------------------------------------------------------*/ - char line[MAX_LINE+1], str1[MAX_LINE+1], str2[MAX_LINE+1]; - char *t1; - char *t2; - int format; - unsigned int v; - int i, j; + int format, v; bool processedStaticChar; /* We have read up to and interpreted the "static char..." line */ + char * t1; + unsigned int nColors; + bool gotPixel, gotNColors, gotWidth, gotHeight, gotFormat; - *widthP = *heightP = *ncolorsP = *chars_per_pixelP = format = -1; + gotNColors = false; + gotWidth = false; + gotHeight = false; + gotFormat = false; + gotPixel = false; /* Read the initial defines. */ processedStaticChar = FALSE; while (!processedStaticChar) { - getLine(line, sizeof(line), stream); + char line[MAX_LINE+1]; + char str1[MAX_LINE+1]; + + getLine(line, sizeof(line), ifP); if (sscanf(line, "#define %s %d", str1, &v) == 2) { - char *t1; if ((t1 = strrchr(str1, '_')) == NULL) t1 = str1; else ++t1; - if (streq(t1, "format")) + if (streq(t1, "format")) { + gotFormat = true; format = v; - else if (streq(t1, "width")) + } else if (streq(t1, "width")) { + gotWidth = true; *widthP = v; - else if (streq(t1, "height")) + } else if (streq(t1, "height")) { + gotHeight = true; *heightP = v; - else if (streq(t1, "ncolors")) - *ncolorsP = v; - else if (streq(t1, "pixel")) - *chars_per_pixelP = v; - } else if (!strncmp(line, "static char", 11)) { + } else if (streq(t1, "nColors")) { + gotNColors = true; + nColors = v; + } else if (streq(t1, "pixel")) { + gotPixel = TRUE; + *charsPerPixelP = v; + } + } else if (strneq(line, "static char", 11)) { if ((t1 = strrchr(line, '_')) == NULL) t1 = line; else @@ -507,85 +780,40 @@ readXpm1Header(FILE * const stream, int * const widthP, int * const heightP, t1 points to position of last "_" in the line, or the beginning of the line if there is no "_" */ - if (format == -1) + if (!gotPixel) + pm_error("No 'pixel' value (characters per pixel)"); + if (!gotFormat) pm_error("missing or invalid format"); if (format != 1) pm_error("can't handle XPM version %d", format); - if (*widthP == -1) + if (!gotWidth) pm_error("missing or invalid width"); - if (*heightP == -1) + if (!gotHeight) pm_error("missing or invalid height"); - if (*ncolorsP == -1) - pm_error("missing or invalid ncolors"); - if (*chars_per_pixelP == -1) - pm_error("missing or invalid *chars_per_pixelP"); - if (*chars_per_pixelP > 2) - pm_message("WARNING: *chars_per_pixelP > 2 uses a lot of memory"); + if (!gotNColors) + pm_error("missing or invalid nColors"); + + if (*charsPerPixelP > 2) + pm_message("WARNING: > 2 characters per pixel uses a lot of memory"); /* If there's a monochrome color table, skip it. */ - if (!strncmp(t1, "mono", 4)) { + if (strneq(t1, "mono", 4)) { for (;;) { - getLine(line, sizeof(line), stream); - if (!strncmp(line, "static char", 11)) + char line[MAX_LINE+1]; + getLine(line, sizeof(line), ifP); + if (strneq(line, "static char", 11)) break; } } - /* Allocate space for color table. */ - if (*chars_per_pixelP <= 2) { - /* Up to two chars per pixel, we can use an indexed table. */ - v = 1; - for (i = 0; i < *chars_per_pixelP; ++i) - v *= 256; - *colorsP = ppm_allocrow(v); - *ptabP = NULL; - } else { - /* Over two chars per pixel, we fall back on linear search. */ - *colorsP = ppm_allocrow(*ncolorsP); - MALLOCARRAY(*ptabP, *ncolorsP); - if (*ptabP == NULL) - pm_error("Unable to allocate memory for %d colors", *ncolorsP); - } - - /* Read color table. */ - for (i = 0; i < *ncolorsP; ++i) { - getLine(line, sizeof(line), stream); + readV1ColorTable(ifP, colorNameHashPP, nColors, *charsPerPixelP); - if ((t1 = strchr(line, '"')) == NULL) - pm_error("D error scanning color table"); - if ((t2 = strchr(t1 + 1, '"')) == NULL) - pm_error("E error scanning color table"); - if (t2 - t1 - 1 != *chars_per_pixelP) - pm_error("wrong number of chars per pixel in color table"); - strncpy(str1, t1 + 1, t2 - t1 - 1); - str1[t2 - t1 - 1] = '\0'; - - if ((t1 = strchr(t2 + 1, '"')) == NULL) - pm_error("F error scanning color table"); - if ((t2 = strchr(t1 + 1, '"')) == NULL) - pm_error("G error scanning color table"); - strncpy(str2, t1 + 1, t2 - t1 - 1); - str2[t2 - t1 - 1] = '\0'; - - v = 0; - for (j = 0; j < *chars_per_pixelP; ++j) - v = (v << 8) + str1[j]; - if (*chars_per_pixelP <= 2) - /* Index into table. */ - (*colorsP)[v] = ppm_parsecolor(str2, - (pixval) PPM_MAXMAXVAL); - else { - /* Set up linear search table. */ - (*colorsP)[i] = ppm_parsecolor(str2, - (pixval) PPM_MAXMAXVAL); - (*ptabP)[i] = v; - } - } /* Position to first line of raster (which is the line after "static char ..."). */ for (;;) { - getLine(line, sizeof(line), stream); - if (strncmp(line, "static char", 11) == 0) + char line[MAX_LINE+1]; + getLine(line, sizeof(line), ifP); + if (strneq(line, "static char", 11)) break; } } @@ -593,29 +821,49 @@ readXpm1Header(FILE * const stream, int * const widthP, int * const heightP, static void -interpretXpmLine(char const line[], - int const chars_per_pixel, - int const ncolors, - int * const ptab, - int ** const cursorP, - int * const maxCursor) { +validateRasterPixel(const char * const pixelChars, + unsigned int const charsPerPixel) { + + unsigned int i; + + for (i = 0; i < charsPerPixel; ++i) { + if (pixelChars[i] == '\0') + pm_error("XPM input file ends in the middle of a string " + "that represents a raster line"); + else if (pixelChars[i] == '"') + pm_error("A string that represents a raster line in the " + "XPM input file is too short to contain all the " + "pixels (%u characters each)", + charsPerPixel); + } +} + + + +static void +convertRow(char const line[], + unsigned int const width, + unsigned int const charsPerPixel, + const ColorNameHash * const colorNameHashP, + pixel * const pixrow, + bit * const alpharow) { /*---------------------------------------------------------------------------- - Interpret one line of XPM input. The line is in 'line', and its - format is 'chars_per_pixel' characters per pixel. 'ptab' is the - color table that applies to the line, which table has 'ncolors' - colors. + Convert one row from XPM input, which describes one raster line of the + image, to PPM. The XPM line is in 'line', and its format is 'width' pixel, + 'charsPerPixel' characters per pixel. *colorNameHashP is the color table + that applies to the line. + + Put the PPM pixels in 'pixrow'. - Put the colormap indexes for the pixels represented in 'line' at - *cursorP, lined up in the order they are in 'line', and return - *cursorP positioned just after the last one. + Also produce PBM row 'alpharow' with the transparency information from the + row. If the line doesn't start with a quote (e.g. it is empty), we issue a warning and just treat the line as one that describes no pixels. - Stop processing the line either at the end of the line or when - the output would go beyond maxCursor, whichever comes first. + Abort program if there aren't exactly 'width' pixels in the line. -----------------------------------------------------------------------------*/ - char * lineCursor; + const char * lineCursor; lineCursor = strchr(line, '"'); /* position to 1st quote in line */ if (lineCursor == NULL) { @@ -626,209 +874,208 @@ interpretXpmLine(char const line[], "line which is supposed to be a line of raster data: " "'%s'. Ignoring this line.", line); } else { + unsigned int col; + ++lineCursor; /* Skip to first character after quote */ /* Handle pixels until a close quote, eol, or we've returned all the pixels Caller wants. */ - while (*lineCursor && *lineCursor != '"' && *cursorP <= maxCursor) { - int colorNumber; - int i; - colorNumber = 0; /* initial value */ - for (i = 0; i < chars_per_pixel; ++i) - colorNumber = (colorNumber << 8) + *(lineCursor++); - if (ptab == NULL) - /* colormap is indexed directly by XPM color number */ - *(*cursorP)++ = colorNumber; - else { - /* colormap shadows ptab[]. Find this color # in ptab[] */ - int i; - for (i = 0; i < ncolors && ptab[i] != colorNumber; ++i); - if (i < ncolors) - *(*cursorP)++ = i; - else - pm_error("Color number %d is in raster, but not in " - "colormap. Line it's in: '%s'", - colorNumber, line); - } + for (col = 0; col < width; ++col) { + + validateRasterPixel(lineCursor, charsPerPixel); + + pixrow[col] = hash_color(colorNameHashP, lineCursor); + + alpharow[col] = hash_isTransparent(colorNameHashP, lineCursor) ? + PBM_BLACK : PBM_WHITE; + + lineCursor += charsPerPixel; } + if (*lineCursor != '"') + pm_error("A raster line continues past width of image"); } } static void -ReadXPMFile(FILE * const stream, int * const widthP, int * const heightP, - pixel ** const colorsP, int ** const dataP, - int * const transparentP) { +convertRaster(FILE * const ifP, + unsigned int const cols, + unsigned int const rows, + unsigned int const charsPerPixel, + const ColorNameHash * const colorNameHashP, + FILE * const imageOutFileP, + FILE * const alphaOutFileP) { /*---------------------------------------------------------------------------- - Read the XPM file from stream 'stream'. + Read the XPM raster from *ifP and write the PPM raster to *imageOutFileP + and the alpha channel to *alphaOutFileP (where those are, respectively, + non-null). - Return the dimensions of the image as *widthP and *heightP. - Return the color map as *colorsP, which is an array of *ncolorsP - colors. + The dimensions are 'cols' by 'rows' and the color map for the XPM + raster is *colorNameHashP. +-----------------------------------------------------------------------------*/ + char line[MAX_LINE+1]; + pixel * pixrow; + bit * alpharow; + unsigned int row; - Return the raster in newly malloced storage, an array of *widthP by - *heightP integers, each of which is an index into the colormap - *colorsP (and therefore less than *ncolorsP). Return the address - of the array as *dataP. + pixrow = ppm_allocrow(cols); + alpharow = pbm_allocrow(cols); - In the colormap, put black for the transparent color, if the XPM - image contains one. ------------------------------------------------------------------------------*/ - char line[MAX_LINE+1], str1[MAX_LINE+1]; - int totalpixels; - int *cursor; /* cursor into *dataP */ - int *maxcursor; /* value of above cursor for last pixel in image */ - int *ptab; /* colormap - malloc'ed */ - int rc; - int ncolors; - int chars_per_pixel; + for (row = 0; row < rows; ++row) { + bool haveLine; - backup = FALSE; + for (haveLine = false; !haveLine; ) { + getLine(line, sizeof(line), ifP); - /* Read the header line */ - getLine(line, sizeof(line), stream); - backup = TRUE; /* back up so next read reads this line again */ - - rc = sscanf(line, "/* %s */", str1); - if (rc == 1 && strncmp(str1, "XPM", 3) == 0) { - /* It's an XPM version 3 file */ - readXpm3Header(stream, widthP, heightP, &chars_per_pixel, - &ncolors, colorsP, &ptab, transparentP); - } else { /* try as an XPM version 1 file */ - /* Assume it's an XPM version 1 file */ - readXpm1Header(stream, widthP, heightP, &chars_per_pixel, - &ncolors, colorsP, &ptab); - *transparentP = -1; /* No transparency in version 1 */ - } - totalpixels = *widthP * *heightP; - MALLOCARRAY(*dataP, totalpixels); - if (*dataP == NULL) - pm_error("Could not get %d bytes of memory for image", totalpixels); - cursor = *dataP; - maxcursor = *dataP + totalpixels - 1; - getLine(line, sizeof(line), stream); - /* read next line (first line may not always start with comment) */ - while (cursor <= maxcursor) { - if (strncmp(line, "/*", 2) == 0) { - /* It's a comment. Ignore it. */ - } else { - interpretXpmLine(line, chars_per_pixel, - ncolors, ptab, &cursor, maxcursor); + if (strneq(line, "/*", 2)) { + /* It's a comment. Ignore it. */ + } else + haveLine = true; } - if (cursor <= maxcursor) - getLine(line, sizeof(line), stream); + convertRow(line, cols, charsPerPixel, colorNameHashP, + pixrow, alpharow); + + if (imageOutFileP) + ppm_writeppmrow(imageOutFileP, + pixrow, cols, PPM_MAXMAXVAL, 0); + if (alphaOutFileP) + pbm_writepbmrow(alphaOutFileP, alpharow, cols, 0); } - if (ptab) free(ptab); + + pbm_freerow(alpharow); + ppm_freerow(pixrow); } static void -writeOutput(FILE * const imageout_file, - FILE * const alpha_file, - int const cols, int const rows, - pixel * const colors, int * const data, - int transparent) { +readXpmHeader(FILE * const ifP, + unsigned int * const widthP, + unsigned int * const heightP, + unsigned int * const charsPerPixelP, + ColorNameHash ** const colorNameHashPP) { /*---------------------------------------------------------------------------- - Write the image in 'data' to open PPM file stream 'imageout_file', - and the alpha mask for it to open PBM file stream 'alpha_file', - except if either is NULL, skip it. + Read the XPM header, including color map. - 'data' is an array of cols * rows integers, each one being an index - into the colormap 'colors'. - - Where the index 'transparent' occurs in 'data', the pixel is supposed - to be transparent. If 'transparent' < 0, no pixels are transparent. + In the colormap, put black for the transparent color, if the XPM image + contains one. -----------------------------------------------------------------------------*/ - int row; - pixel *pixrow; - bit * alpharow; - - if (imageout_file) - ppm_writeppminit(imageout_file, cols, rows, PPM_MAXMAXVAL, 0); - if (alpha_file) - pbm_writepbminit(alpha_file, cols, rows, 0); - - pixrow = ppm_allocrow(cols); - alpharow = pbm_allocrow(cols); + char line[MAX_LINE+1]; + char str1[MAX_LINE+1]; + int rc; + unsigned int charsPerPixel; + unsigned int width, height; - for (row = 0; row < rows; ++row ) { - int col; - int * const datarow = data+(row*cols); + backup = FALSE; - for (col = 0; col < cols; ++col) { - pixrow[col] = colors[datarow[col]]; - if (datarow[col] == transparent) - alpharow[col] = PBM_BLACK; - else - alpharow[col] = PBM_WHITE; - } - if (imageout_file) - ppm_writeppmrow(imageout_file, - pixrow, cols, (pixval) PPM_MAXMAXVAL, 0); - if (alpha_file) - pbm_writepbmrow(alpha_file, alpharow, cols, 0); + /* Read the header line */ + getLine(line, sizeof(line), ifP); + backup = TRUE; /* back up so next read reads this line again */ + + rc = sscanf(line, "/* %s */", str1); + if (rc == 1 && strneq(str1, "XPM", 3)) { + /* It's an XPM version 3 file */ + readXpm3Header(ifP, &width, &height, &charsPerPixel, colorNameHashPP); + } else { + /* Assume it's an XPM version 1 file */ + readXpm1Header(ifP, &width, &height, &charsPerPixel, colorNameHashPP); } - ppm_freerow(pixrow); - pbm_freerow(alpharow); - - if (imageout_file) - pm_close(imageout_file); - if (alpha_file) - pm_close(alpha_file); -} - + *widthP = width; + *heightP = height; + *charsPerPixelP = charsPerPixel; +} + int main(int argc, char *argv[]) { - FILE *ifp; - FILE *alpha_file, *imageout_file; - pixel *colormap; - int cols, rows; - int transparent; /* value of 'data' that means transparent */ - int *data; - /* The image as an array of width * height integers, each one - being an index int colormap[]. - */ + FILE * ifP; + FILE * alphaOutFileP; + FILE * imageOutFileP; + unsigned int cols, rows; + unsigned int charsPerPixel; + ColorNameHash * colorNameHashP; - struct cmdline_info cmdline; + struct cmdlineInfo cmdline; ppm_init(&argc, argv); - parse_command_line(argc, argv, &cmdline); + parseCommandLine(argc, argv, &cmdline); verbose = cmdline.verbose; if ( cmdline.input_filespec != NULL ) - ifp = pm_openr( cmdline.input_filespec); + ifP = pm_openr( cmdline.input_filespec); else - ifp = stdin; + ifP = stdin; if (cmdline.alpha_stdout) - alpha_file = stdout; + alphaOutFileP = stdout; else if (cmdline.alpha_filename == NULL) - alpha_file = NULL; + alphaOutFileP = NULL; else { - alpha_file = pm_openw(cmdline.alpha_filename); + alphaOutFileP = pm_openw(cmdline.alpha_filename); } if (cmdline.alpha_stdout) - imageout_file = NULL; + imageOutFileP = NULL; else - imageout_file = stdout; + imageOutFileP = stdout; - ReadXPMFile(ifp, &cols, &rows, &colormap, &data, &transparent); - - pm_close(ifp); + readXpmHeader(ifP, &cols, &rows, &charsPerPixel, &colorNameHashP); - writeOutput(imageout_file, alpha_file, cols, rows, colormap, data, - transparent); + if (imageOutFileP) + ppm_writeppminit(imageOutFileP, cols, rows, PPM_MAXMAXVAL, 0); + if (alphaOutFileP) + pbm_writepbminit(alphaOutFileP, cols, rows, 0); - free(colormap); + + convertRaster(ifP, cols, rows, charsPerPixel, colorNameHashP, + imageOutFileP, alphaOutFileP); + + pm_close(ifP); + if (imageOutFileP) + pm_close(imageOutFileP); + if (alphaOutFileP) + pm_close(alphaOutFileP); + + hash_destroy(colorNameHashP); return 0; } + + + +/* +** +** Copyright (C) 1991 by Jef Poskanzer. +** +** Permission to use, copy, modify, and distribute this software and its +** documentation for any purpose and without fee is hereby granted, provided +** that the above copyright notice appear in all copies and that both that +** copyright notice and this permission notice appear in supporting +** documentation. This software is provided "as is" without express or +** implied warranty. +** +** Upgraded to handle XPM version 3 by +** Arnaud Le Hors (lehors@mirsa.inria.fr) +** Tue Apr 9 1991 +** +** Rainer Sinkwitz sinkwitz@ifi.unizh.ch - 21 Nov 91: +** - Bug fix, no advance of read ptr, would not read +** colors like "ac c black" because it would find +** the "c" of "ac" and then had problems with "c" +** as color. +** +** - Now understands multiword X11 color names +** +** - Now reads multiple color keys. Takes the color +** of the hightest available key. Lines no longer need +** to begin with key 'c'. +** +** - expanded line buffer to from 500 to 2048 for bigger files +*/ + diff --git a/converter/ppm/yuvsplittoppm.c b/converter/ppm/yuvsplittoppm.c index b3088812..5343a21e 100644 --- a/converter/ppm/yuvsplittoppm.c +++ b/converter/ppm/yuvsplittoppm.c @@ -57,7 +57,7 @@ parseCommandLine(int argc, was passed to us as the argv array. We also trash *argv. -----------------------------------------------------------------------------*/ optEntry *option_def = malloc(100*sizeof(optEntry)); - /* Instructions to optParseOptions3 on how to parse our options. + /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; @@ -71,7 +71,7 @@ parseCommandLine(int argc, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ - optParseOptions3( &argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ @@ -196,9 +196,9 @@ main(int argc, char **argv) { parseCommandLine(argc, argv, &cmdline); - asprintfN(&ufname, "%s.U", cmdline.filenameBase); - asprintfN(&vfname, "%s.V", cmdline.filenameBase); - asprintfN(&yfname, "%s.Y", cmdline.filenameBase); + pm_asprintf(&ufname, "%s.U", cmdline.filenameBase); + pm_asprintf(&vfname, "%s.V", cmdline.filenameBase); + pm_asprintf(&yfname, "%s.Y", cmdline.filenameBase); uf = pm_openr(ufname); vf = pm_openr(vfname); @@ -241,9 +241,9 @@ main(int argc, char **argv) { } pm_close(stdout); - strfree(yfname); - strfree(vfname); - strfree(ufname); + pm_strfree(yfname); + pm_strfree(vfname); + pm_strfree(ufname); pm_close(yf); pm_close(uf); diff --git a/converter/ppm/yuvtoppm.c b/converter/ppm/yuvtoppm.c index 2b44c65f..151ff9f9 100644 --- a/converter/ppm/yuvtoppm.c +++ b/converter/ppm/yuvtoppm.c @@ -20,96 +20,201 @@ ** implied warranty. */ -#include "ppm.h" +#include "pm_c_util.h" #include "mallocvar.h" +#include "shhopt.h" +#include "ppm.h" -/* x must be signed for the following to work correctly */ -#define limit(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16) -int -main(argc, argv) - char **argv; -{ - FILE *ifp; - pixel *pixrow; - int argn, rows, cols, row; - const char * const usage = " [yuvfile]"; - struct yuv { - /* This is an element of a YUV file. It describes two - side-by-side pixels. - */ - unsigned char u; - unsigned char y1; - unsigned char v; - unsigned char y2; - } *yuvbuf; - - ppm_init(&argc, argv); - - argn = 1; - - if (argn + 2 > argc) - pm_usage(usage); - - cols = atoi(argv[argn++]); - rows = atoi(argv[argn++]); - if (cols <= 0 || rows <= 0) - pm_usage(usage); - - if (argn < argc) { - ifp = pm_openr(argv[argn]); - ++argn; - } else - ifp = stdin; - - if (argn != argc) - pm_usage(usage); - - if (cols % 2 != 0) { - pm_error("Number of columns (%d) is odd. A YUV image must have an " - "even number of columns.", cols); + +struct CmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + unsigned int cols; + unsigned int rows; + const char * inputFileName; /* Name of input file */ +}; + + + +static void +parseCommandLine(int argc, const char ** argv, + struct CmdlineInfo * const cmdlineP) { + + optEntry * option_def; + /* Instructions to OptParseOptions3 on how to parse our options */ + optStruct3 opt; + + MALLOCARRAY_NOFAIL(option_def, 100); + + OPTENTINIT; + + opt.opt_table = option_def; + opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ + opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ + + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + if (argc-1 < 2) + pm_error("You need at least two arguments: width and height in " + "pixels. You specified %u", argc-1); + else { + int const widthArg = atoi(argv[1]); + int const heightArg = atoi(argv[2]); + + if (widthArg < 0) + pm_error("Negative number for width: %d", widthArg); + if (heightArg < 0) + pm_error("Negative number for height: %d", heightArg); + + cmdlineP->cols = widthArg; + cmdlineP->rows = heightArg; + + if (cmdlineP->cols % 2 != 0) + pm_error("Number of columns (%u) is odd. " + "A YUV image must have an " + "even number of columns.", cmdlineP->cols); + + if (argc-1 < 3) + cmdlineP->inputFileName = "-"; + else { + cmdlineP->inputFileName = argv[3]; + + if (argc-1 > 3) + pm_error("Too many arguments: %u. " + "The only possible arguments are " + "width, height, and input file name", argc-1); + } } +} - ppm_writeppminit(stdout, cols, rows, (pixval) 255, 0); - pixrow = ppm_allocrow(cols); - MALLOCARRAY(yuvbuf, (cols+1)/2); - if (yuvbuf == NULL) - pm_error("Unable to allocate YUV buffer for %d columns.", cols); - for (row = 0; row < rows; ++row) { - int col; - fread(yuvbuf, cols * 2, 1, ifp); +static int +limit(int const x) { - for (col = 0; col < cols; col += 2) { - /* Produce two pixels in pixrow[] */ - int y1, u, v, y2, r, g, b; + if (x > 0xffffff) + return 0xff; + else if (x <= 0xffff) + return 0; + else + return ((x >> 16) & 0xff); +} + + + +static int +nonneg(int const x) { +/*---------------------------------------------------------------------------- + Raise 'x' to 0 if negative +-----------------------------------------------------------------------------*/ + return x < 0 ? 0 : x; +} + + + +struct Yuv { +/*---------------------------------------------------------------------------- + This is an element of a YUV file. It describes two side-by-side pixels. + + This is the actual layout of the data in the file (4 bytes). +-----------------------------------------------------------------------------*/ + unsigned char u; + unsigned char y1; + unsigned char v; + unsigned char y2; +}; - u = yuvbuf[col/2].u-128; - y1 = yuvbuf[col/2].y1 - 16; - if (y1 < 0) y1 = 0; - v = yuvbuf[col/2].v - 128; +static void +readYuv(FILE * const ifP, + struct Yuv * const yuvP) { - y2 = yuvbuf[col/2].y2 - 16; - if (y2 < 0) y2 = 0; + size_t readCt; - r = 104635 * v; - g = -25690 * u + -53294 * v; - b = 132278 * u; + readCt = fread(yuvP, sizeof(*yuvP), 1, ifP); - y1*=76310; y2*=76310; + if (readCt != 1) { + if (feof(ifP)) + pm_error("Premature end of input."); + else + pm_error("Error reading input."); + } +} + + + +static void +yuvtoppm(FILE * const ifP, + unsigned int const cols, + unsigned int const rows, + FILE * const ofP) { + + pixval const maxval = 255; + + pixel * pixrow; + unsigned int row; + + ppm_writeppminit(ofP, cols, rows, maxval, 0); + + pixrow = ppm_allocrow(cols); + + for (row = 0; row < rows; ++row) { + unsigned int col; + for (col = 0; col < cols; col += 2) { + /* Produce two pixels in pixrow[] */ + struct Yuv yuv; + int y1, u, v, y2, r, g, b; + + readYuv(ifP, &yuv); + + u = yuv.u - 128; + y1 = nonneg (yuv.y1 - 16); + v = yuv.v - 128; + y2 = nonneg (yuv.y2 - 16); + + r = 104635 * v; + g = -25690 * u + -53294 * v; + b = 132278 * u; + + y1 *= 76310; + y2 *= 76310; + + PPM_ASSIGN(pixrow[col], + limit(r + y1), limit(g + y1), limit(b + y1)); + PPM_ASSIGN(pixrow[col + 1], + limit(r + y2), limit(g + y2), limit(b + y2)); + } + ppm_writeppmrow(ofP, pixrow, cols, maxval, 0); + } - PPM_ASSIGN(pixrow[col], limit(r+y1), limit(g+y1), limit(b+y1)); - PPM_ASSIGN(pixrow[col+1], limit(r+y2), limit(g+y2), limit(b+y2)); - } - ppm_writeppmrow(stdout, pixrow, cols, (pixval) 255, 0); - } - free(yuvbuf); ppm_freerow(pixrow); - pm_close(ifp); - pm_close(stdout); - exit(0); + if (fgetc(ifP) != EOF) + pm_message("Extraneous data at end of image."); +} + + + +int +main (int argc, const char ** argv) { + + FILE * ifP; + struct CmdlineInfo cmdline; + + pm_proginit(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + ifP = pm_openr(cmdline.inputFileName); + + yuvtoppm(ifP, cmdline.cols, cmdline.rows, stdout); + + pm_close(ifP); + pm_close(stdout); + + return 0; } -- cgit 1.4.1